commit 8f291ff
zzo38
·
2023-06-21 20:01:43 +0000 UTC
parent f88b636
Implement the -m switch.
2 files changed,
+141,
-2
M
main.c
+39,
-0
1@@ -73,6 +73,10 @@
2 -j
3 Enable key repeat for joypad emulation.
4
5+-m #
6+ Specify memory writes and device writes to do before or after loading the
7+ file. See the "Memory/device scripts" section below for details.
8+
9 -n
10 Disable GUI. Either this switch or -I is required in order to read stdin.
11 If neither -n nor -I is specified, then stdin cannot be read (although
12@@ -323,3 +327,38 @@ expansion commands to activate them).
13 What happens if you then try to change colours using the colour ports
14 after doing this, is not specified.
15
16+
17+=== Memory/device scripts ===
18+
19+A command with the -m switch has the subcommands which have the format of
20+an optional "." to indicate executed after instead of before loading, and
21+then an optional letter "g" to "z" to specify the specific command (if none
22+is specified, then it is a memory command), and then the address in hex,
23+and then optionally = and the data in hex. The address is treated as a pure
24+number while the data is a sequence of bytes so the number of digits must
25+be an even number.
26+
27+It can also optionally be @ and a file name, in which case the commands are
28+loaded from a file. The file cannot itself have @ commands, and it may have
29+lines starting with # as comments.
30+
31+The subcommands are:
32+
33+Memory (no letter)
34+ Write memory starting at the specified address.
35+
36+Device trigger (p)
37+ Write and trigger devices starting at the specified address. If there are
38+ multiple bytes of data, then multiple consecutive ports are written to
39+ and are triggered.
40+
41+Device set (s)
42+ Same as device trigger but omit the trigger; only writes are done.
43+
44+Execute (x)
45+ Execute uxn code at the specified address, which must be nonzero, and
46+ cannot be in expanded memory. (The data of this command is not used.)
47+
48+During the execution of any of these commands, it behaves as though the -x
49+switch is specified, even if it isn't specified.
50+
M
main.c
+102,
-2
1@@ -101,6 +101,13 @@ typedef struct {
2 Uint8 vol[2];
3 } UxnAudio;
4
5+typedef struct {
6+ Uint8*data;
7+ Uint32 addr;
8+ Uint16 len;
9+ Uint8 kind,stage;
10+} Script;
11+
12 static SDL_Color colors[64]={
13 // 0
14 {0xFF,0xFF,0xFF,0},
15@@ -227,6 +234,10 @@ static Uint8 palet=7;
16 static Uint8 eof_trigger=0;
17 static Uint8 touch_mode=0;
18
19+static Uint16 scriptc;
20+static Script*scriptv;
21+static FILE*scriptf;
22+
23 static Sint32*audio_option;
24 static SDL_AudioSpec audiospec;
25
26@@ -1525,6 +1536,87 @@ static void set_palette(char*s) {
27 fclose(f);
28 }
29
30+static void set_script(char*s) {
31+ static size_t siz;
32+ Script o={0,0,0,0,0};
33+ if(!scriptf) {
34+ scriptf=open_memstream((char**)&scriptv,&siz);
35+ if(!scriptf) err(1,"Error with open_memstream during parsing command-line arguments");
36+ }
37+ if(*s=='@') {
38+ char*line=0;
39+ size_t line_size=0;
40+ FILE*fp=fopen(s+1,"r");
41+ if(!fp) err(1,"Cannot open file \"%s\"",s+1);
42+ while(getline(&line,&line_size,fp)>0) {
43+ s=line+strlen(line);
44+ while(s>line && (s[-1]=='\r' || s[-1]=='\n' || s[-1]==' ' || s[-1]=='\t')) *--s=0;
45+ if(*s=='@') errx(1,"Nested file in -m not allowed");
46+ if(*s && *s!='#') set_script(s);
47+ }
48+ fclose(fp);
49+ free(line);
50+ } else {
51+ Uint8 b;
52+ if(*s=='.') o.stage=1,s++;
53+ if(*s>'f') o.kind=*s++;
54+ o.addr=strtoll(s,&s,16);
55+ if(*s=='=') {
56+ s++;
57+ if(strlen(s)>=0x1FFFF) errx(1,"Argument too long");
58+ o.data=malloc(strlen(s)/2+1);
59+ if(!o.data) err(1,"Allocation failed");
60+ while(*s && s[1]) {
61+ if(!sscanf(s,"%2hhX",&b)) break;
62+ o.data[o.len++]=b;
63+ s+=2;
64+ }
65+ if(*s) errx(1,"Syntax error in -m");
66+ } else if(*s) {
67+ errx(1,"Syntax error in -m");
68+ }
69+ if(o.kind || o.len) {
70+ if(!fwrite(&o,sizeof(Script),1,scriptf)) err(1,"Cannot write to memory stream");
71+ ++scriptc;
72+ }
73+ }
74+}
75+
76+static void do_script(Uint8 stage) {
77+ Uint8 u=use_extension;
78+ Uint16 n,i,j;
79+ Script*o;
80+ use_extension=1;
81+ for(n=0;n<scriptc;n++) if(scriptv[n].stage==stage) {
82+ o=scriptv+n;
83+ switch(o->kind) {
84+ case 0: // Memory write
85+ memcpy(mem+o->addr,o->data,o->len);
86+ break;
87+ case 'p': // Device port (including trigger)
88+ j=o->addr;
89+ for(i=0;i<o->len;i++) {
90+ device[(j>>4)&15].d[j&15]=o->data[i];
91+ device[(j>>4)&15].out(device+((j>>4)&15),j&15);
92+ j++;
93+ }
94+ break;
95+ case 's': // Device port (set only)
96+ j=o->addr;
97+ for(i=0;i<o->len;i++) {
98+ device[(j>>4)&15].d[j&15]=o->data[i];
99+ j++;
100+ }
101+ break;
102+ case 'x': // Execute
103+ run(o->addr);
104+ break;
105+ default: errx(1,"Unrecognized command -m%c",o->kind);
106+ }
107+ }
108+ use_extension=u;
109+}
110+
111 int main(int argc,char**argv) {
112 int i,j;
113 for(i=0;i<16;i++) {
114@@ -1538,7 +1630,7 @@ int main(int argc,char**argv) {
115 device[11].aux=&uxnfile1;
116 device[12].in=datetime_in;
117 inf=stdin; outf=stdout;
118- while((i=getopt(argc,argv,"+ADFIJ:NOQST:YZa:de:h:ijnp:qs:t:w:xyz:"))>0) switch(i) {
119+ while((i=getopt(argc,argv,"+ADFIJ:NOQST:YZa:de:h:ijm:np:qs:t:w:xyz:"))>0) switch(i) {
120 case 'D': scrflags|=SDL_DOUBLEBUF; break;
121 case 'F': scrflags|=SDL_FULLSCREEN; break;
122 case 'I': use_thread=1; break;
123@@ -1556,6 +1648,7 @@ int main(int argc,char**argv) {
124 case 'h': default_height=strtol(optarg,0,10); break;
125 case 'i': hide_cursor=1; break;
126 case 'j': joypad_repeat=1; break;
127+ case 'm': set_script(optarg); break;
128 case 'n': use_screen=0; break;
129 case 'p': palet=strtol(optarg,0,10)&7; if(*optarg && optarg[1]=='=') set_palette(optarg+2); break;
130 case 'q': use_console=0; break;
131@@ -1569,6 +1662,12 @@ int main(int argc,char**argv) {
132 }
133 if(optind==argc) errx(1,"Required argument missing");
134 rom_name=argv[optind];
135+ if(use_console) device[1].out=console_out;
136+ if(scriptf) {
137+ fclose(scriptf);
138+ if(!scriptv) err(1,"Allocation failed");
139+ do_script(0);
140+ }
141 load_rom();
142 if(use_screen) {
143 if(zoom<1) errx(1,"Zoom out of range");
144@@ -1589,13 +1688,13 @@ int main(int argc,char**argv) {
145 SDL_JoystickEventState(SDL_ENABLE);
146 }
147 }
148- if(use_console) device[1].out=console_out;
149 if(optind+1<argc) strncpy(uxnfile0.name,argv[optind+1],4095);
150 if(optind+2<argc) strncpy(uxnfile1.name,argv[optind+2],4095);
151 restart:
152 size_changed=1;
153 ds.p=rs.p=0;
154 device[1].d[7]=(optind+1==argc)?0:1;
155+ if(scriptc) do_script(1);
156 run(0x0100);
157 if(device[1].d[0] || device[1].d[1]) for(i=optind+1;i<argc;i++) {
158 for(j=0;argv[i][j];j++) {
159@@ -1612,6 +1711,7 @@ int main(int argc,char**argv) {
160 if(use_thread) SDL_CreateThread(stdin_thread_fn,0);
161 while(run_screen()) {
162 for(i=0;i<15;i++) for(j=0;j<16;j++) device[i].d[j]=0;
163+ if(scriptc) do_script(0);
164 load_rom();
165 goto restart;
166 }