comparison scn2k/scn2k_cmd.cc @ 0:223b71206888

Initial import
author thib
date Fri, 01 Aug 2008 16:32:45 +0000
parents
children a05bf0823154
comparison
equal deleted inserted replaced
-1:000000000000 0:223b71206888
1 /*
2 * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28
29 #include"scn2k.h"
30
31 #include<stdlib.h>
32 #include<stdarg.h>
33 #include<stdio.h>
34 #include<string.h>
35 #include<string>
36 #include"system/file.h"
37
38 using namespace std;
39
40
41 // #define SCN_DUMP
42 /* 注意点: @@@ で表記 */
43
44
45
46 //bool debug_flag = true;
47 bool debug_flag = false;
48 void dprintf(const char* fmt, ...) {
49 if (debug_flag) {
50 va_list ap; va_start(ap, fmt);
51 vprintf(fmt, ap);
52 va_end(ap);
53 }
54 }
55
56
57 void eprintf(const char* fmt, ...) {
58 va_list ap; va_start(ap, fmt);
59 // vprintf(fmt, ap);
60 va_end(ap);
61 }
62
63 /**************************************************************
64 ** Flag
65 */
66
67 Flags::Flags(void) {
68 int i,j;
69 for (i=0; i<=TYPE_VARMAX; i++) {
70 for (j=0; j<2000; j++) {
71 var[i][j] = 0;
72 }
73 }
74 sys = 0;
75 }
76
77 bool Flags::IsInt(int type) const {
78 int v = type % 26;
79 return v >= 0 && v < 7 || v == 25;
80 }
81
82 int Flags::MaxIndex(int type) const {
83 switch (type / 26) {
84 case 1:
85 return 63999;
86 case 2:
87 return 31999;
88 case 3:
89 return 15999;
90 case 4:
91 return 7999;
92 default:
93 return 1999;
94 }
95 }
96
97 int Flags::operator()() const {
98 return sys; // rand() % 10000;
99 }
100
101 int Flags::operator() (VarInfo info) const {
102 return Get(info.type, info.number);
103 }
104
105 int Flags::Get(int type, int number) const {
106 int index = type % 26;
107 type /= 26;
108 if (index == 25) {
109 if (var[7][number] != 0) return var[7][number];
110 if (cgm_data.find(number) == cgm_data.end()) return 0;
111 else return 1;
112 }
113 if (index == 10) index = 8;
114 if (index == 11) index = 9;
115 if (index > TYPE_VARMAX || uint(type) > 4) return 0;
116 if (type == 0) {
117 // A[]..G[], Z[] を直に読む
118 if (uint(number) >= 2000) return 0;
119 return var[index][number];
120 } else {
121 // Ab[]..G4b[], Z8b[] などを読む
122 int factor = 1 << (type - 1);
123 int eltsize = 32 / factor;
124 if (uint(number) >= (64000 / factor)) return 0;
125 return (var[index][number / eltsize] >> ((number % eltsize) * factor)) & ((1 << factor) - 1);
126 }
127 }
128
129 void Flags::Set(VarInfo info, int value) {
130 int type = info.type / 26;
131 int index = info.type % 26;
132 if (index == 25) {
133 if (uint(info.number) >= 2000) return;
134 if (value == 0)
135 cgm_data.erase(info.number);
136 else
137 cgm_data.insert(info.number);
138 index = 7;
139 }
140 if (index == 10) index = 8;
141 if (index == 11) index = 9;
142 if (index < 0 || index > TYPE_VARMAX) {
143 fprintf(stderr,"Error: invalid access to Var<%d>[%d]\n",info.type,info.number);
144 }
145 if (type == 0) {
146 // A[]..G[], Z[] を直に書く
147 if (uint(info.number) >= 2000) return;
148 var[index][info.number] = value;
149 } else {
150 // Ab[]..G4b[], Z8b[] などを書く
151 int factor = 1 << (type - 1);
152 int eltsize = 32 / factor;
153 int eltmask = (1 << factor) - 1;
154 int shift = (info.number % eltsize) * factor;
155 if (uint(info.number) >= (64000 / factor)) return;
156 var[index][info.number / eltsize] =
157 (var[index][info.number / eltsize] & ~(eltmask << shift))
158 | (value & eltmask) << shift;
159 }
160 }
161
162 void Flags::SetSys(int value) {
163 sys = value;
164 }
165 void Flags::SetStr(VarInfo info, string val) {
166 switch(info.type) {
167 case TYPE_VARLOCSTR:
168 if (info.number >= 3) return;
169 loc_str[info.number] = val;
170 break;
171 case TYPE_VARSYSSTR:
172 if (info.number >= 2000) return;
173 sys_str[info.number] = val;
174 break;
175 case TYPE_VARSTR:
176 if (info.number >= 2000) return;
177 str[info.number] = val;
178 break;
179 }
180 return;
181 }
182 void Flags::Str(int type, unsigned int number, char* buf, int sz) const {
183 if (sz <= 0) return;
184 buf[0] = 0;
185 const string* sptr;
186 switch(type) {
187 case TYPE_VARLOCSTR:
188 if (number >= 3) return;
189 sptr = &loc_str[number];
190 break;
191 case TYPE_VARSYSSTR:
192 if (number >= 2000) return;
193 sptr = &sys_str[number];
194 break;
195 case TYPE_VARSTR:
196 if (number >= 2000) return;
197 sptr = &str[number];
198 break;
199 }
200
201 int len = sptr->length();
202 if (sz-1 > len) sz = len;
203 sptr->copy(buf, sz, 0);
204 buf[sz] = 0;
205 return;
206 }
207 string Flags::Str(int type, unsigned int number) const {
208 switch(type) {
209 case TYPE_VARLOCSTR:
210 if (number >= 3) return "";
211 return loc_str[number];
212 case TYPE_VARSYSSTR:
213 if (number >= 2000) return "";
214 return sys_str[number];
215 case TYPE_VARSTR:
216 if (number >= 2000) return "";
217 return str[number];
218 }
219 return "";
220 }
221
222 void Flags::Save(string& save) {
223 char buf[1024];
224 save = "\n[Flags]\n";
225 int i,j;
226 for (i=0; i<=TYPE_NONSYSVARMAX; i++) {
227 for (j=0; j<2000; j++) {
228 if (var[i][j] != 0) {
229 sprintf(buf, "V<%d>[%04d]=%d\n",i,j,var[i][j]);
230 save += buf;
231 }
232 }
233 }
234 for (j=0; j<2000; j++) {
235 if (str[j].length() != 0) {
236 sprintf(buf, "V<C>[%04d]=%s\n", j, str[j].c_str());
237 save += buf;
238 }
239 }
240 }
241 void Flags::Load(const char* save) {
242 int i,j;
243 for (i=0; i<=TYPE_NONSYSVARMAX; i++) {
244 for (j=0; j<2000; j++) {
245 var[i][j] = 0;
246 }
247 }
248 sys = 0;
249 for (j=0; j<2000; j++) {
250 str[j] = "";
251 }
252
253 save = strstr(save, "\n[Flags]\n");
254
255 if (save) {
256 save += strlen("\n[Flags]\n");
257 do {
258 if (save[0] == '[') break; // next section
259 if (strncmp(save, "V<",2) == 0) {
260 if (strncmp(save, "V<C>[",5) == 0) { // string
261 char buf[1024];
262 int n;
263 if (sscanf(save, "V<C>[%04d]=",&n) == 1) {
264 char* s = strchr(save, '=');
265 s++;
266 char* send = strchr(s, '\n');
267 int slen = send - s;
268 strncpy(buf, s, slen);
269 buf[slen] = 0;
270 if (n >= 0 && n < 2000) str[n] = buf;
271 }
272 } else if (save[2] >= '0' && save[2] <= '9') {
273 int c,n,v;
274 if (sscanf(save, "V<%d>[%04d]=%d\n",&c,&n,&v) == 3) {
275 if (c >= 0 && c <= TYPE_NONSYSVARMAX && n >= 0 && n < 2000)
276 var[c][n] = v;
277 }
278 }
279 }
280 save = strchr(save, '\n');
281 if (save) save++;
282 } while (save);
283 }
284 return;
285 }
286
287 void Flags::SaveSys(string& save) {
288 char buf[1024];
289 int j;
290 save = "\n[Flags]\n";
291 for (j=0; j<2000; j++) {
292 if (var[6][j] != 0) {
293 sprintf(buf, "V<6>[%04d]=%d\n",j,var[6][j]);
294 save += buf;
295 }
296 }
297 for (j=0; j<2000; j++) {
298 if (var[7][j] != 0) {
299 sprintf(buf, "V<25>[%04d]=%d\n",j,var[7][j]);
300 save += buf;
301 }
302 }
303 for (j=0; j<2000; j++) {
304 if (sys_str[j].length() != 0) {
305 sprintf(buf, "V<M>[%04d]=%s\n", j, sys_str[j].c_str());
306 save += buf;
307 }
308 }
309 }
310 void Flags::LoadSys(const char* save) {
311 int i,j;
312 for (i=6; i<=7; i++) {
313 for (j=0; j<2000; j++) {
314 var[i][j] = 0;
315 }
316 }
317 for (j=0; j<2000; j++) {
318 sys_str[j] = "";
319 }
320 sys = 0;
321
322 save = strstr(save, "\n[Flags]\n");
323
324 if (save) {
325 save += strlen("\n[Flags]\n");
326 do {
327 if (save[0] == '[') break; // next section
328 if (strncmp(save, "V<",2) == 0) {
329 if (strncmp(save, "V<M>[",5) == 0) { // string
330 char buf[1024];
331 int n;
332 if (sscanf(save, "V<M>[%04d]=",&n) == 1) {
333 char* s = strchr(save, '=');
334 s++;
335 char* send = strchr(s, '\n');
336 int slen = send - s;
337 strncpy(buf, s, slen);
338 buf[slen] = 0;
339 if (n >= 0 && n < 2000) sys_str[n] = buf;
340 }
341 } else if (save[2] >= '0' && save[2] <= '9') {
342 int c,n,v;
343 if (sscanf(save, "V<%d>[%04d]=%d\n",&c,&n,&v) == 3) {
344 if (c == 6 && n >= 0 && n < 2000)
345 var[6][n] = v;
346 else if (c == 25 && n >= 0 && n < 2000)
347 var[7][n] = v;
348 }
349 }
350 }
351 save = strchr(save, '\n');
352 if (save) save++;
353 } while (save);
354 }
355 return;
356 }
357
358 bool Flags::Exec(Cmd& cmd) {
359 if (cmd.cmd_type == CMD_FLAGS) { // 代入演算
360 if (cmd.args.size() != 2) return false;
361 Set(cmd.args[0], cmd.args[1].value);
362 cmd.clear();
363 return true;
364 }
365 if (cmd.cmd1 == 1 && cmd.cmd2 == 0x0a) { // 文字列演算
366 VarInfo arg1 = cmd.args[0];
367 switch(cmd.cmd3) {
368 case 0:
369 if (cmd.cmd4 == 0) {
370 SetStr(arg1, cmd.Str(cmd.args[1]));
371 } else if (cmd.cmd4 == 1) {
372 string s = cmd.Str(cmd.args[1]);
373 const char* sc = s.c_str();
374 int len = cmd.args[2].value;
375 int i;for (i=0; i<sc[i]!=0 && len != 0; i++, len--) {
376 if (sc[i]<0 && sc[i+1]!=0) i++;
377 }
378 s.erase(i); // 全角で len 文字まで切り詰める
379 SetStr(arg1, s);
380 // fprintf(stderr,"Set[%d,%d]<-%s\n",arg1.type,arg1.number,s.c_str());
381 } else break;
382 cmd.clear();
383 break;
384 case 1:
385 if (cmd.cmd4 == 0) {
386 SetStr(arg1, "");
387 cmd.clear();
388 } else if (cmd.cmd4 == 1) {
389 // 領域指定で文字列クリア
390 VarInfo v1 = cmd.args[0];
391 VarInfo v2 = cmd.args[1];
392 eprintf("memclear(str). Var[%d]<%d> - Var[%d]<%d>\n",v1.type, v1.number, v2.type, v2.number);
393 if (v1.type != v2.type || (v1.type != TYPE_VARSTR && v1.type != TYPE_VARSYSSTR && v1.type != TYPE_VARLOCSTR)) {
394 eprintf(" error: bad args\n");
395 } else {
396 if (v1.number < 0) v1.number = 0;
397 if (v2.number > 2000) v2.number = 2000;
398 for (; v1.number <= v2.number; v1.number++) {
399 SetStr(v1, "");
400 }
401 }
402 cmd.clear();
403 }
404 case 2:
405 SetStr(arg1, Str(arg1.type,arg1.number) + cmd.Str(cmd.args[1]));
406 // fprintf(stderr,"Append[%d,%d]<-%s(%d:%d)\n",arg1.type,arg1.number,Str(arg1.type,arg1.number).c_str(),cmd.args[1].type,cmd.args[1].number);
407 cmd.clear();
408 break;
409 case 3:
410 SetSys(strlen(cmd.Str(cmd.args[0])));
411 cmd.clear();
412 break;
413 case 4:
414 { int v = strcmp(cmd.Str(cmd.args[0]), cmd.Str(cmd.args[1]));
415 // string s1=cmd.Str(cmd.args[0]);
416 // string s2=cmd.Str(cmd.args[1]);
417 // fprintf(stderr,"Cmp %s(%d:%d):%s(%d:%d):%d\n",s1.c_str(),cmd.args[0].type,cmd.args[0].number,s2.c_str(),cmd.args[1].type,cmd.args[1].number,v);
418 if (v < 0) SetSys(-1);
419 else if (v > 0) SetSys(1);
420 else SetSys(0);
421 cmd.clear();
422 break; }
423 case 5: // substring, index from left
424 case 6: // substring, index from right
425 // 全角対応らしい
426 { int offset = cmd.args[2].value;
427 int len = strlen(cmd.Str(cmd.args[1]));
428 string str = cmd.Str(cmd.args[1]);
429 const char* s = str.c_str();
430 if (cmd.cmd3 == 6) offset = len - offset;
431 if (offset < 0) offset = 0;
432 // 先頭 N 文字を読み飛ばす
433 int i;
434 int offset_top = 0;
435 for (i=0; i<offset && s[offset_top] != 0; i++) {
436 if (s[offset_top] < 0 && s[offset_top+1] != 0) offset_top += 2;
437 else offset_top += 1;
438 }
439 if (s[offset_top] == 0) {
440 SetStr(arg1, "");
441 } else if (cmd.cmd4 == 0) { // 長さ制限なし
442 SetStr(arg1, string(s, offset_top));
443 } else { // cmd.cmd4 == 1
444 int slen = cmd.args[3].value;
445 int offset_end = offset_top;
446 for (i=0; i<slen && s[offset_end] != 0; i++) {
447 if (s[offset_end] < 0 && s[offset_end]+1 != 0) offset_end += 2;
448 else offset_end += 1;
449 }
450 string result(s, offset_top, offset_end-offset_top);
451 SetStr(arg1, result);
452 }
453 cmd.clear();
454 break; }
455 case 7: {// strlen w/ kanji
456 const char* s = cmd.Str(cmd.args[0]); int i;
457 for (i=0; *s != 0; i++) {
458 if (*s < 0 && s[1] != 0) s += 2;
459 else s++;
460 }
461 SetSys(i);
462 cmd.clear();
463 break; }
464 case 8: // 文字列を切って短くする
465 if (cmd.args[1].value <= 0) {
466 SetStr(arg1, "");
467 } else if (cmd.args[1].value < strlen(cmd.Str(cmd.args[1]))) {
468 Str(arg1.type,arg1.number).erase(cmd.args[1].value);
469 }
470 cmd.clear();
471 break;
472 case 0x0e: // 漢字モードでitoa
473 {
474 int arg1 = cmd.args[0].value;
475 string result;
476 char wc[3]; wc[2]=0;
477 char buf[20];
478 if (cmd.cmd4 == 0) {
479 sprintf(buf, "%d", arg1);
480 } else { // cmd.cmd4 == 1
481 char fmt[20];
482 sprintf(fmt, "%%%dd", cmd.args[2].value);
483 sprintf(buf, fmt, arg1);
484 }
485 int i;
486 for (i=0; buf[i] != 0; i++) {
487 if (buf[i] == ' ') {
488 wc[0] = 0x81;
489 wc[0] = 0x40;
490 } else if (buf[i] == '-') {
491 wc[0] = 0x81;
492 wc[0] = 0x7c;
493 } else if (isdigit(buf[i])) {
494 wc[0] = 0x82;
495 wc[1] = buf[i] - '0' + 0x4f;
496 } else {
497 continue;
498 }
499 result += wc;
500 }
501 SetStr(cmd.args[1], result);
502 cmd.clear();
503 }
504 break;
505 case 0x0f: case 0x11: // itoa (0x11 の方は zero padding するっぽい)
506 if (cmd.cmd4 == 0) {
507 int arg1 = cmd.args[0].value;
508 char buf[1024]; sprintf(buf, "%d", arg1);
509 SetStr(cmd.args[1], buf);
510 cmd.clear();
511 } else if (cmd.cmd4 == 1) {
512 // 漢字(SJIS) : 82 [4f+N]
513 // やはり漢字じゃない?
514 int arg1 = cmd.args[0].value;
515 char buf[1024]; char fmt[1024];
516 if (cmd.cmd3 == 0x0f) {
517 sprintf(fmt, "%%%dd",cmd.args[2].value); /* 空白でパディング */
518 } else {
519 sprintf(fmt, "%%0%dd",cmd.args[2].value);
520 }
521 sprintf(buf, fmt, arg1);
522 SetStr(cmd.args[1], buf);
523 cmd.clear();
524 }
525 break;
526 case 0x64: // 文字列の表示 : 引数をテキストウィンドウに表示
527 if (cmd.cmd4 == 1) {
528 char buf[256];
529 snprintf(buf, 255, "%d", Get(cmd.args[0].type, cmd.args[0].number));
530 cmd.args[0].type = TYPE_STR;
531 cmd.args[0].value = cmd.AddStr(buf);
532 cmd.cmd4 = 0;
533 }
534
535 #if 0
536 @@@
537 save 27
538 ともよメガネのところ
539 - オブジェクト関連:seen9061:0 呼び出しで黒い背景画をかさねるところ、変になる
540 @@@
541 %Xで置換する名前の設定。0x51e で読みだし。セーブファイルごとに保存されるはずなので実装を考えること
542 %は0-3 (4 以降は使ってない)で、渚、秋生、渚、伊吹先生、など
543 StrVar を拡張して代入すること
544 初期値はこの辺
545 Text側に納め、セーブファイルでも同じようにすべきだろうなあ
546 args:0,"渚"
547 args:1,"秋生"
548 args:2,"渚"
549 args:3,"伊吹先生"
550 args:4,"朋也くん"
551 args:5,"岡崎さん"
552
553
554 106737 : 0x23 - cmd 01-04:051f:00[ 2]
555 args:0,"古河"
556 106758 : line 1712
557 106761 : 0x23 - cmd 01-04:051f:00[ 2]
558 args:2,"古河"
559 106782 : line 1713
560 106785 : 0x23 - cmd 01-04:051f:00[ 2]
561 args:4,"岡崎さん"
562
563 47382 : 0x23 - cmd 01-04:051e:00[ 2]
564 args:4,V<18>[0](=0)
565
566 47408 : 0x23 - cmd 01-0a:0004:00[ 2]
567 args:V<18>[0](=0),"岡崎さん"
568 47437 : expr: V<0>[1000](=0)=V<sys>
569 47451 : 0x23 - cmd 01-0a:0004:00[ 2]
570 args:V<18>[0](=0),"朋也くん"
571 47480 : expr: V<0>[1001](=0)=V<sys>
572 47494 : V<0>[1000](=0)==0(=true)-> 47589
573 47526 : 0x23 - cmd 01-04:0514:00[ 2]
574 args:0,V<18>[0](=0) /* NAME.A を帰す */
575 47552 : 0x23 - cmd 01-0a:0002:00[ 2]
576 args:V<18>[0](=0),"さん"
577 47577 : jmp -> 47672
578 47589 : V<0>[1001](=0)==0(=true)-> 47672
579 47621 : 0x23 - cmd 01-04:0514:00[ 2]
580 args:1,V<18>[0](=0) /* NAME.B を帰す */
581 47647 : 0x23 - cmd 01-0a:0002:00[ 2]
582 args:V<18>[0](=0),"くん"
583 47672 : pos. 279
584 47675 : 0x23 - cmd 01-0a:0064:00[ 1]
585 args:V<18>[0](=0)
586
587 #endif
588 cmd.cmd_type = CMD_TEXT;
589 break;
590 }
591 }
592 if (cmd.cmd1 == 1 && cmd.cmd2 == 0x0b) { // 数値変数演算
593 if (cmd.cmd3 == 0 && cmd.cmd4 == 0) {
594 /* 複数の変数をセット */
595 VarInfo v1 = cmd.args[0];
596 eprintf("set multiple-var Var[%d]<%d> <- ",v1.type, v1.number);
597 int i;
598 if (cmd.args.size() < cmd.argc) {
599 eprintf(" error: argsize changed %d -> %d\n",cmd.argc, cmd.args.size());
600 cmd.argc = cmd.args.size();
601 }
602 for (i=0; i<cmd.argc; i++) {
603 eprintf("%d, ",cmd.args[i+1].value);
604 Set(v1, cmd.args[i+1].value);
605 v1.number++;
606 }
607 eprintf("\n");
608 cmd.clear();
609 } else if (cmd.cmd3 == 1 && cmd.cmd4 == 0) {
610 /* 領域指定で変数をクリア */
611 VarInfo v1 = cmd.args[0];
612 VarInfo v2 = cmd.args[1];
613 eprintf("memclear. Var[%d]<%d> - Var[%d]<%d>\n",v1.type, v1.number, v2.type, v2.number);
614 if (v1.type != v2.type || !IsInt(v1.type)) eprintf(" error: bad args\n");
615 else {
616 if (v1.number < 0) v1.number = 0;
617 if (v2.number > MaxIndex(v2.type)) v2.number = MaxIndex(v2.type);
618 for (; v1.number <= v2.number; v1.number++)
619 Set(v1, 0);
620 }
621 cmd.clear();
622 } else if (cmd.cmd3 == 1 && cmd.cmd4 == 1) {
623 /* 領域指定で変数をセット */
624 VarInfo v1 = cmd.args[0];
625 VarInfo v2 = cmd.args[1];
626 int value = cmd.args[2].value;
627 eprintf("memset. Var[%d]<%d> - Var[%d]<%d> <- %d\n",v1.type, v1.number, v2.type, v2.number, value);
628 if (v1.type != v2.type || !IsInt(v1.type)) eprintf(" error: bad args\n");
629 else {
630 if (v1.number < 0) v1.number = 0;
631 if (v2.number > MaxIndex(v2.type)) v2.number = MaxIndex(v2.type);
632 for (; v1.number <= v2.number; v1.number++)
633 Set(v1, value);
634 }
635 cmd.clear();
636 } else if (cmd.cmd3 == 4 && cmd.cmd4 == 1) { // 領域クリア(sysfunc.txt)
637 VarInfo v1 = cmd.args[0];
638 int step = cmd.args[1].value;
639 int deal = cmd.args[2].value;
640 int val = cmd.args[3].value;
641 eprintf("memclear. Var[%d]<%d> step %d deal %d <- val %d\n",v1.type, v1.number, step, deal, val);
642 int i; for (i=0; i<deal; i++) {
643 Set(v1, val);
644 v1.number += step;
645 }
646 cmd.clear();
647 } else if (cmd.cmd3 == 0x64 && cmd.cmd4 == 0) { //領域で数値を合計する
648 VarInfo v1 = cmd.args[0];
649 VarInfo v2 = cmd.args[1];
650 eprintf("sum var. Var[%d]<%d> - Var[%d]<%d>\n",v1.type, v1.number, v2.type, v2.number);
651 int sum = 0;
652 if (v1.type != v2.type || !IsInt(v1.type)) eprintf(" error: bad args\n");
653 else {
654 if (v1.number < 0) v1.number = 0;
655 if (v2.number > MaxIndex(v2.type)) v2.number = MaxIndex(v2.type);
656 for (; v1.number <= v2.number; v1.number++)
657 sum += (*this)(v1);
658 }
659 eprintf(" ret %d\n",sum);
660 cmd.SetSysvar(sum);
661 }
662 }
663 return false;
664 }
665
666 /*********************************************************************
667 ** Cmd
668 */
669
670 /* 数値 num := 0x24 0xff <int num> */
671 /* 変数 var := 0x24 <uchar type> 0x5b <exp> 0x5d */
672 /* 項 token := num | var | 0x28 <exp> 0x29 | <plus|minus> token */
673
674 int Cmd::GetLeftToken(const char*& d, VarInfo& info) {
675 bool var_flag = true;
676 int minus_flag = 0;
677 int value = 0;
678 if (d[0] == 0x5c && (d[1] == 1 || d[1] == 0) ) {
679 if (d[1] == 1) {dprintf("minus-"); minus_flag ^= 1;}
680 else dprintf("plus-");
681 d += 2;
682 var_flag = false;
683 }
684 if (d[0] == 0x24 && ((unsigned const char*)d)[1] == 0xff) {
685 // if ( (d[0] == 0x30 || d[0] == 0x31) && d[1] == 0x24 && ((unsigned const char*)d)[2] == 0xff) /* @@@ not supported; selection 内で、0x30|0x31 が付随することがある */
686 // numerical atom
687 d += 6;
688 value = read_little_endian_int(d-4);
689 dprintf("%d",value);
690 var_flag = false;
691 } else if (d[0] == 0x24 && *(unsigned char*)(d+1) == 0xc8) {
692 dprintf("V<sys>");
693 d += 2;
694 info.type = TYPE_SYS; info.number = 0;
695 value = info.value = flags();
696 } else if (d[0] == 0x24 && d[2] == 0x5b) {
697 // 0x24,<type>,0x5b,<expr>,0x5d-terminated term
698 info.type = *(unsigned char*)(d+1);
699 d += 3;
700 dprintf("V<%d>[",info.type);
701 info.number = GetExpression(d);
702 dprintf("]");
703 if (*d == 0x5d) d++;
704 else SetError();
705 if (info.type == TYPE_VARSTR || info.type == TYPE_VARSYSSTR || info.type == TYPE_VARLOCSTR) {
706 value = 0;
707 info.value = StrVar(info.type, info.number);
708 } else {
709 value = info.value = flags(info);
710 }
711 dprintf("(=%d)",value);
712 } else SetError();
713
714 if (minus_flag) value = -value;
715 if (!var_flag) {
716 info.type = TYPE_VAL;
717 info.value = value;
718 }
719 return value;
720 }
721
722 static char* op_str[70] = {
723 // 0 1 2 3 4 5 6 7 8 9
724 "+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", // +00
725 "err.","err.","err.","err.","err.","err.","err.","err.","err.","err.", // +10
726 "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", // +20
727 "=", "err.","err.","err.","err.","err.","err.","err.","err.","err.", // +30
728 "==", "!=", "<=", "<", ">=", ">", "err.","err.","err.","err.", // +40
729 "err.","err.","err.","err.","err.","err.","err.","err.","err.","err.", // +50
730 "&&", "||", "err.","err.","err.","err.","err.","err.","err.","err.", // +60
731 };
732
733 static int op_pri_tbl[12] = {
734 // + - * / % & | ^ << >>
735 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 10, 10};
736
737 inline int op_pri(int op) {
738 if (op > 11) return 10;
739 return op_pri_tbl[op];
740 }
741 inline int op_pri_cond(int op) {
742 if (op <= 11) return op_pri_tbl[op];
743 else if (op < 50) return 7;
744 else if (op == 60) return 8;
745 else if (op == 61) return 8;
746 else return 10;
747 }
748
749
750 inline int eval(int v1, int op, int v2) {
751 switch(op) {
752 case 0: return v1+v2;
753 case 1: return v1-v2;
754 case 2: return v1*v2;
755 case 3: return v2!=0 ? v1/v2 : v1;
756 case 4: return v2!=0 ? v1%v2 : v1;
757 case 5: return v1&v2;
758 case 6: return v1|v2;
759 case 7: return v1^v2;
760 case 8: return v1<<v2;
761 case 9: return v1>>v2;
762 case 40: return v1 == v2;
763 case 41: return v1 != v2;
764 case 42: return v1 <= v2;
765 case 43: return v1 < v2;
766 case 44: return v1 >= v2;
767 case 45: return v1 > v2;
768 case 60: return v1 && v2;
769 case 61: return v1 || v2;
770 }
771 return v2;
772 }
773
774 /* 演算子 op := 0x5c <uchar op> */
775 /* 数式 exp: [op] <token> [op <token> [...]] */
776 int Cmd::GetExpression(const char*& d, VarInfo* info_ptr) {
777 #define STACK_DEPTH 1024
778 #define OP_LB 11
779 char op_stack[STACK_DEPTH];
780 int val_stack[STACK_DEPTH];
781 int stack_count = 0;
782
783 // 第一項の読み込み
784 while(*d == 0x28) {
785 d++;
786 dprintf("(");
787 op_stack[stack_count++] = OP_LB;
788 }
789 VarInfo info;
790 int value = GetLeftToken(d, info);
791
792 while(*d == 0x29 && stack_count > 0 && op_stack[stack_count-1] == OP_LB) {
793 d++;
794 dprintf(")");
795 stack_count--;
796 }
797
798 if (*d != 0x5c && stack_count == 0) {
799 if (info_ptr) *info_ptr = info;
800 return value; // 単純なleft-termはここで終了。有効なinfo_ptrを帰す(可能性がある)
801 }
802
803 while(*d == 0x5c) {
804 int op_type = *(unsigned char*)(d+1);
805 d += 2;
806 if (op_type < 70) dprintf("%s",op_str[op_type]);
807 else dprintf("err.");
808 if (op_type >= 10) SetError();
809 int cur_pri = op_pri(op_type);
810 while(stack_count != 0 && op_pri(op_stack[stack_count-1]) <= cur_pri) {
811 // 優先順位の高い、先行する演算を行う
812 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
813 stack_count--;
814 }
815 val_stack[stack_count] = value;
816 op_stack[stack_count++] = op_type;
817 while(*d == 0x28) {
818 d++;
819 dprintf("(");
820 op_stack[stack_count++] = OP_LB;
821 }
822 if (stack_count >= STACK_DEPTH) SetError();
823 value = GetLeftToken(d, info);
824
825 while (*d != 0x5c && stack_count > 0) {
826 // 未実行の演算を終わらせる
827 if (op_stack[stack_count-1] != OP_LB) {
828 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
829 stack_count--;
830 } else if (*d == 0x29) { /* op_stack == OP_LB */
831 // bracket 終端があれば、閉じておく
832 d++;
833 dprintf(")");
834 stack_count--;
835 } else break; // error
836 }
837 }
838 if (stack_count) SetError(); // unbalanced bracket
839 dprintf("(=%d)",value);
840 if (info_ptr) {
841 info_ptr->type = TYPE_VAL;
842 info_ptr->value = value;
843 }
844 return value;
845 }
846
847 // 条件分岐専用に、条件演算と算術演算の混合を検知できる専用ルーチン(本来はGetExpressionで差し支えない)
848 int Cmd::GetExpressionCond(const char*& d) {
849 char op_stack[STACK_DEPTH];
850 int val_stack[STACK_DEPTH];
851 int valattr_stack[STACK_DEPTH];
852 #define ATTR_VAL 0
853 #define ATTR_FLAG 1
854 int stack_count = 0;
855
856 // 第一項の読み込み
857 while(*d == 0x28) {
858 d++;
859 dprintf("(");
860 op_stack[stack_count++] = OP_LB;
861 }
862 VarInfo info;
863 int value = GetLeftToken(d, info);
864 while(*d == 0x29 && stack_count > 0 && op_stack[stack_count-1] == OP_LB) {
865 d++;
866 dprintf(")");
867 stack_count--;
868 }
869 bool valattr = ATTR_VAL;
870
871 while(*d == 0x5c) {
872 int op_type = *(unsigned char*)(d+1);
873 d += 2;
874 if (op_type < 70) dprintf("%s",op_str[op_type]);
875 else dprintf("err.");
876 int cur_pri = op_pri_cond(op_type);
877 while(stack_count != 0 && op_pri_cond(op_stack[stack_count-1]) <= cur_pri) {
878 // 優先順位の高い、先行する演算を行う
879 if (op_stack[stack_count-1] >= 60) {
880 if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError();
881 } else {
882 if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError();
883 }
884 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
885 if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG;
886 stack_count--;
887 }
888 val_stack[stack_count] = value;
889 valattr_stack[stack_count] = valattr;
890 op_stack[stack_count++] = op_type;
891 while(*d == 0x28) {
892 d++;
893 dprintf("(");
894 op_stack[stack_count++] = OP_LB;
895 }
896 if (stack_count >= STACK_DEPTH) SetError();
897 value = GetLeftToken(d, info);
898 valattr = ATTR_VAL;
899
900 while (*d != 0x5c && stack_count > 0) {
901 // 未実行の演算を終わらせる
902 if (op_stack[stack_count-1] != OP_LB) {
903 if (op_stack[stack_count-1] >= 60) {
904 if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError();
905 } else {
906 if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError();
907 }
908 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
909 if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG;
910 stack_count--;
911 // bracket 終端があれば、閉じておく
912 } else if (*d == 0x29) { /* op_stack == OP_LB */
913 d++;
914 dprintf(")");
915 stack_count--;
916 } else break; // error
917 }
918 }
919 if (stack_count) SetError(); // unbalanced bracket
920 if (value) dprintf("(=true)");
921 else dprintf("(=false)");
922 return value;
923 }
924
925
926 /*
927 str =
928 arg =
929 args = 0x28 <exp> [[0x2c] <exp> [[0x2c] <exp> [...] ]]
930 */
931
932 int Cmd::GetArgs(const char*& d) {
933 if (*d != 0x28) return 0; /* 引数なし */
934 d++;
935 dprintf("args:");
936 VarInfo var;
937 int i; for (i=0; i<100 ; i++) {
938 /* number, variable, string の種別なく値を得る */
939 if (*d == 0x61) { // よくわからない(智代アフター)
940 dprintf("*%d*",d[1]);
941 d += 2;
942 if (*d == 0x28) {
943 dprintf("{");
944 GetArgs(d); // (A,B,C)節が含まれることがある
945 dprintf("}");
946 } else {
947 dprintf("{}");
948 }
949 } else if (d[0] == 0x0a || d[0] == 0x40) { // よくわからない (Little Busters!)
950 int var;
951 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
952 else { var = read_little_endian_short(d+1); d += 3;}
953 dprintf("line %d; ",var);
954 } else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) {
955 GetExpression(d, &var);
956 args.push_back(var);
957 } else if (StrType(d)) {
958 var.type = TYPE_STR;
959 var.value = GetString(d);
960 args.push_back(var);
961 } else SetError();
962 if (*d == 0x29) break;
963 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
964 dprintf(",");
965 }
966 if (*d == 0x29) d++;
967 else SetError();
968 return i;
969 }
970
971 int Cmd::GetArgsSpecial(int normal_args,const char*& d) {
972 if (*d != 0x28) return 0; /* 引数なし */
973 d++;
974 dprintf("args:");
975 int i; for (i=0; i<normal_args; i++) {
976 /* number, variable, string の種別なく値を得る */
977 if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) {
978 GetExpression(d);
979 } else if (StrType(d)) {
980 GetString(d);
981 } else SetError();
982 if (*d == 0x29) break;
983 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
984 dprintf(",");
985 }
986 for (i=0; i<argc ; i++) {
987 if (*d == 0x28) {
988 /*
989 ** cmd 01-22:0c1c, 01-22:0835
990 ** Princess Bride のカードが落ちるアニメの場面
991 ** なお、_PBCARDANM* の画像はこのコマンドでのみ使われているので、特殊処理として無視することも可能
992 **
993 ** cmd 01-04:0276, 026c, 0270
994 ** 複数の enum が args の数だけ続く処理。特殊処理として分離する
995 */
996 dprintf("enum.<");
997 /* (...) は列挙型 or 構造体の可能性がある */
998 const char* d_orig = d;
999 int pt = args.size(); args.push_back(VarInfo(0));
1000 int count = GetArgs(d);
1001 args[pt] = VarInfo(count);
1002 dprintf(">");
1003 } else if (*d == 0x61 && (d[1] >= 0x00 && d[1] <= 0x04) && d[2] == 0x28 ) {
1004 /* 使われるコマンドは 01-21:004b, 01-28:0064 のいずれか(R,C,PB,LO)
1005 ** それらのコマンドは
1006 ** arg1: 画像ファイル名
1007 ** arg2 : Sel 番号
1008 ** らしく、arg3 以降が 0x61 <00-04> (a,b,c,...) となる(ダンプ上は enum と表記される)
1009 ** () 内の引数はさまざまで、a のみ(画像ファイル名)、
1010 ** a,b b=SEL?
1011 ** a,b,c (b,c)=座標?
1012 ** a,(b,c,d,e,f,g) b-g = src / dest?
1013 ** らしい
1014 */
1015 dprintf("kasane. #%d <",d[1]);
1016 d += 2;
1017 int pt = args.size(); args.push_back(VarInfo(0));
1018 int count = GetArgs(d);
1019 args[pt] = VarInfo(count);
1020 dprintf(">");
1021 } else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0))) {
1022 /* cmd 01-15:0028 ; 始めに 0x24 節があり、続いて 0x28 節になる */
1023 VarInfo var;
1024 GetExpression(d, &var);
1025 args.push_back(var);
1026 i--; // この引数はargc の数には入らない
1027 } else SetError();
1028 if (d[0] == 0x0a || d[0] == 0x40) {
1029 /* cmd 01-15:0028 ; 0x28 節の後に毎回 0x0a 節が来る */
1030 int var;
1031 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
1032 else { var = read_little_endian_short(d+1); d += 3;}
1033 dprintf("line %d; ",var);
1034 }
1035 if (*d == 0x29) break;
1036 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
1037 dprintf(",");
1038 }
1039 if (*d == 0x29) d++;
1040 else SetError();
1041 return 0;
1042 }
1043
1044 /* switch
1045 <exp>
1046 0x7b
1047 <exp> <int>
1048 ...
1049 0x7d
1050 */
1051
1052 int Cmd::GetSwitch(const char*& d) {
1053 if (*d != 0x28) {SetError(); return -1;}
1054 d++;
1055 dprintf("switch. ");
1056 int var = GetExpression(d);
1057 if (*d != 0x29) {SetError(); return -1;}
1058 d++;
1059 dprintf("->\n");
1060 if (*d == 0x7b) {
1061 d++;
1062 } else SetError();
1063
1064 int default_jmp = -1; int jmpto = -1;
1065 int i; for (i=0; i<argc; i++) {
1066 dprintf("\t");
1067 if (*d++ != 0x28) {SetError(); return -1;}
1068 int item = -1; // default
1069 if (*d != 0x29) {
1070 int item = GetExpression(d);
1071 if (*d++ != 0x29) {SetError(); return -1;}
1072 int jmp = read_little_endian_int(d);
1073 if (var == item) {
1074 dprintf("(selected)");
1075 jmpto = jmp;
1076 }
1077 dprintf(" -> %d\n", jmp);
1078 } else {
1079 d++;
1080 default_jmp = read_little_endian_int(d);
1081 }
1082 d += 4;
1083 }
1084 if (default_jmp != -1) {
1085 dprintf("default -> %d\n",default_jmp);
1086 if (jmpto == -1) jmpto = default_jmp;
1087 }
1088 if (*d == 0x7d) {
1089 d++;
1090 } else SetError();
1091 return jmpto;
1092 }
1093 /* simple switch
1094 <exp>
1095 0x7b
1096 <int>
1097 ...
1098 0x7d
1099 */
1100 int Cmd::GetSimpleSwitch(const char*& d) {
1101 if (*d != 0x28) {SetError(); return -1;}
1102 d++;
1103 dprintf("simple switch. ");
1104 int var = GetExpression(d);
1105 if (*d != 0x29) {SetError(); return -1;}
1106 d++;
1107 dprintf(" ->\n");
1108 int jumpto = -1;
1109 if (*d == 0x7b) {
1110 d++;
1111 } else SetError();
1112 int i; for (i=0; i<argc; i++) {
1113 int j = read_little_endian_int(d);
1114 d += 4;
1115 dprintf("\t%d -> %d\n", i+1, j);
1116 if (var == i) jumpto = j;
1117 }
1118 if (*d == 0x7d) {
1119 d++;
1120 } else SetError();
1121 return jumpto;
1122 }
1123
1124 /*
1125 selection
1126 ? <exp>
1127 0x7b
1128 <0x0a|0x40> <ushort | uint>
1129 */
1130 void Cmd::GetSelection(const char*& d) {
1131 dprintf("selection. ");
1132 if (*d == 0x28) {
1133 d++;
1134 GetExpression(d);
1135 if (*d != 0x29) { SetError(); return;}
1136 d++;
1137 }
1138 if (*d == 0x7b) {
1139 d++;
1140 dprintf("{\n\t");
1141 } else SetError();
1142 int arg_count = 0;
1143 string text = "";
1144 int cond_result = false;
1145 int sel_no = 0;
1146 while(*d != 0x7d) {
1147 if (d[0] == 0x0a || d[0] == 0x40) {
1148 int var;
1149 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
1150 else { var = read_little_endian_short(d+1); d += 3;}
1151 dprintf("Line %d; ",var);
1152 if (text.length() != 0) {
1153 if (cond_result) ; // 条件節が true なら表示しない
1154 else {
1155 const char* str = text.c_str();
1156 VarInfo var;
1157 var.type = TYPE_STR;
1158 var.value = CopyString(str);
1159 args.push_back(var);
1160 var.type = TYPE_VAL;
1161 var.value = sel_no;
1162 args.push_back(var);
1163 }
1164 sel_no++;
1165 }
1166 text = "";
1167 cond_result = false;
1168 } else if (d[0] == 0x2c) {
1169 dprintf(":comma:");
1170 } else if (d[0] == 0x28) {
1171 dprintf(":cond:");
1172 d++;
1173 while(d[0] != 0x29) {
1174 int result = GetExpressionCond(d); // PRINT- 節でないばあい、条件表示。次は文字節、またはPRINT節のはず
1175 if (*d == 0x32) { // 0x32 なら、現在の条件節を表示しない
1176 d++; dprintf("##");
1177 cond_result = result;
1178 } else if (*d == 0x31) { // 0x31 なら、現在の条件節を表示する
1179 // Little Busters! : この条件で正しいかは未検証
1180 d++; dprintf("***");
1181 cond_result = !result;
1182 }
1183 dprintf(":");
1184 }
1185 d++;
1186 } else if (StrType(d)) {
1187 int strpt = GetString(d);
1188 text += strheap + strpt;
1189 arg_count++;
1190 dprintf("\n\t");
1191 } else if (*d == 0x23 && strncmp(d,"###PRINT",8) == 0) {
1192 d += 8;
1193 if (d[0] != 0x28) SetError();
1194 else { // 文字変数の内容の表示
1195 d++;
1196 dprintf("Print.");
1197 VarInfo info;
1198 GetLeftToken(d, info);
1199 if (d[0] != 0x29 || info.type == -1) SetError();
1200 d++;
1201 dprintf(";");
1202 // 数値を全角文字に変換して登録
1203 char str[10], str2[20]; // itoa
1204 sprintf(str, "%d", info.value);
1205 int i; for (i=0; str[i] != 0; i++) {
1206 str2[i*2] = 0xa3;
1207 str2[i*2+1] = 0xb0 + str[i]-'0';
1208 }
1209 str2[i*2] = 0;
1210 text += str2;
1211 }
1212 } else { SetError(); break;}
1213 }
1214 d++;
1215 /* @@@ */
1216 /* 一致しない場合があるのでコメントアウト */
1217 // if (arg_count != argc) SetError();
1218 dprintf("\n}\n");
1219 return;
1220 }
1221
1222 static char* op_str3[11] = { "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", "="};
1223 void Cmd::GetCmd(Flags& flags_orig, const char*& d ) {
1224 if (d == 0) { SetError(); return;}
1225 if (cmd_type != CMD_NOP) return;
1226
1227 cmdstr[0] = 0;
1228 rawdata = d;
1229 if (*d == 0x23) { /* コマンド */
1230 cmd_type = CMD_OTHER;
1231 cmd1 = *(unsigned const char*)(d+1);
1232 cmd2 = *(unsigned const char*)(d+2);
1233 cmd3 = read_little_endian_short(d+3);
1234 argc = read_little_endian_short(d+5);
1235 cmd4 = *(unsigned const char*)(d+7);
1236 d += 8;
1237 /* verbose */
1238 // dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",cmd1,cmd2,cmd3,cmd4,argc);
1239 sprintf(cmdstr, "%02x-%02x:%04x:%02x",cmd1,cmd2,cmd3,cmd4);
1240 /* 引数を得る */
1241 /* 特殊引数のもの */
1242 int is_special = 0;
1243 if (cmd1 == 0) {
1244 if (cmd2 == 1) {
1245 int jump_arg = -1;
1246 if (cmd3 == 0 || cmd3 == 5) {
1247 /* gosub / goto */
1248 jump_arg =read_little_endian_int(d);
1249 d += 4;
1250 if (cmd3 == 0)
1251 dprintf("\tjmp -> %d\n", jump_arg);
1252 else /* cmd3 == 5 */
1253 dprintf("\tcall -> %d\n", jump_arg);
1254 is_special = 1;
1255 } else if (cmd3 == 1 || cmd3 == 2) {
1256 /* conditional jump (if / unless) */
1257 if (*d++ != 0x28) { SetError(); return;}
1258 dprintf("\t");
1259 int cond = GetExpressionCond(d);
1260 if (cmd3 == 1) cond = !cond; // 逆になる
1261 if (*d++ != 0x29) { SetError(); return; }
1262 int jumpto = read_little_endian_int(d);
1263 d += 4;
1264 dprintf("-> %d\n", jumpto);
1265 if (! cond) jump_arg = jumpto; /* condition が満たされない場合、ジャンプ */
1266 is_special = 1;
1267 } else if (cmd3 == 4) {
1268 /* switch to */
1269 jump_arg = GetSwitch(d);
1270 is_special = 1;
1271 } else if (cmd3 == 8 || cmd3 == 3) {
1272 /* switch to */
1273 jump_arg = GetSimpleSwitch(d);
1274 is_special = 1;
1275 } else if (cmd3 == 16) { // call with parameters
1276 GetArgs(d);
1277 jump_arg = read_little_endian_int(d);
1278 d += 4;
1279 is_special = 1;
1280 } else goto retry;
1281 if (jump_arg == -1) {
1282 cmd_type = CMD_NOP;
1283 }
1284 else {
1285 cmd_type = CMD_JMP;
1286 args.push_back(VarInfo(jump_arg));
1287 }
1288 } else if (cmd2 == 2 && (cmd3 == 0 || cmd3 == 1 || cmd3 == 2 || cmd3 == 3 || cmd3 == 0x0d) ) {
1289 /* selection */
1290 GetSelection(d);
1291 is_special = 1;
1292 }
1293 }
1294 retry:
1295 /* 一般引数のもの */
1296 if (!is_special) {
1297 dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",cmd1,cmd2,cmd3,cmd4,argc);
1298 dprintf("\t");
1299 if (cmd1 == 1 && cmd2 == 0x22 && (cmd3 == 0xc1c || cmd3 == 0x835)) GetArgsSpecial(3, d);
1300 else if (cmd1 == 1 && cmd2 == 0x0b && cmd3 == 0x65) GetArgsSpecial(0, d);
1301 else if (cmd1 == 1 && cmd2 == 0x15 && cmd3 == 0x28) GetArgsSpecial(0, d);
1302 else if (cmd1 == 1 && cmd2 == 4 && (cmd3 == 0x26c || cmd3 == 0x26d || cmd3 == 0x270 || cmd3 == 0x276)) GetArgsSpecial(0, d);
1303 else if (cmd1 == 1 && cmd2 == 4 && cmd3 == 0x586) GetArgsSpecial(1, d);
1304 else if (cmd1 == 1 && (cmd2 == 0x21 && cmd3 == 0x4b) || (cmd2 == 0x28 && cmd3 == 0x64)) GetArgsSpecial(2,d);
1305 else GetArgs(d);
1306 dprintf("\n");
1307
1308 }
1309 } else if (*d == 0x24) { /* 代入演算 */
1310 if (d[1] == 0x12 || d[2] != 0x5b) SetError();
1311 dprintf("expr: ");
1312 sprintf(cmdstr, "expr");
1313
1314 VarInfo info;
1315 int value = GetLeftToken(d, info);
1316 if (d[0] != 0x5c) SetError();
1317 int type = d[1];
1318 if (type < 20 || type > 30) SetError();
1319 else dprintf("%s",op_str[type]);
1320 d += 2;
1321 int value2 = GetExpression(d);
1322 // 代入情報を埋め込む
1323 if (type != 30) value2 = eval(value, type-20, value2);
1324 cmd_type = CMD_FLAGS;
1325 args.push_back(info);
1326 args.push_back(value2);
1327 dprintf("\n");
1328 } else if (StrType(d)) { /* 文字出力 */
1329 VarInfo info;
1330 info.type = TYPE_STR;
1331 info.value = GetString(d);
1332 args.push_back(info);
1333 cmd_type = CMD_TEXT;
1334 dprintf("\n");
1335 } else if (*d == 0x0a || *d == 0x40 || *d == 0x21) { /* デバッグ用データと既読フラグ */
1336 cmd_type = CMD_NOP;
1337 if (*d == 0x0a) {
1338 dprintf("line ");
1339 d++;
1340 int l;
1341 if (system_version == 0) {
1342 l = read_little_endian_int(d);
1343 d += 4;
1344 } else {
1345 l = read_little_endian_short(d);
1346 d += 2;
1347 }
1348 dprintf("%d\n", l);
1349 } else { /* 0x40, 0x21 */
1350 // 既読マーカーらしい。エントリーポイントとセーブポイントも使われる。
1351 // RealLive 1.2.5から、0x40はセーブポイント、0x21はエントリーポイント。
1352 // 1.2.5以前、どちらも0x40が使われる。
1353 int kidoku_index;
1354 d++;
1355 if (system_version == 0) {
1356 kidoku_index = read_little_endian_int(d);
1357 d += 4;
1358 } else {
1359 kidoku_index = read_little_endian_short(d);
1360 d += 2;
1361 }
1362 dprintf("kidoku marker %d\n", kidoku_index);
1363 // text_readflagは、このkidoku_indexを使ったら良いかな。
1364 }
1365 } else if (*d == 0x2c) { /* ??? */
1366 dprintf("commd;0x2c\n"); // conditional jump の行き先によくあるらしい(常に、かはわからない)
1367 d++;
1368 } else {
1369 SetError();
1370 }
1371 return;
1372 }
1373 void Cmd::clear(void) {
1374 cmd_type = CMD_NOP;
1375 ResetString();
1376 args.clear();
1377 errorflag = false;
1378 pos = -1;
1379 }
1380
1381 char Cmd::strtype[256] = {
1382 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +00 */
1383 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +10 */ // 0123456789ABCDEF
1384 1,0,3,0, 0,0,0,1, 0,0,0,0, 0,1,1,0, /* +20 */ // !"#$%&'()*+,-./
1385 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, /* +30 */ // 0123456789:;<=>?
1386 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, /* +40 */ // @ABCDEFGHIJKLMNO
1387 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, /* +50 */ // PQRSTUVWXYZ[\]^_
1388 0,0,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, /* +60 */ // `abcdefghijklmno
1389 1,1,1,1, 1,1,1,1, 1,1,1,1, 0,0,0,0, /* +70 */ // pqrstuvwxyz{|}~
1390 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +80 */
1391 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +90 */
1392 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +A0 */
1393 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +B0 */
1394 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +C0 */
1395 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +D0 */
1396 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +E0 */
1397 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,0,0 /* +F0 */
1398 };
1399
1400 int Cmd::GetString(const char*& d) {
1401 int retnum = -1;
1402 bool quote_flag = false;
1403 int stype;
1404 retnum = strend;
1405 while(1) {
1406 if (*d == '\\') {
1407 d++;
1408 strheap[strend++] = *d++;
1409 } else if (*d == '"') {
1410 if (quote_flag) quote_flag = false;
1411 else quote_flag = true;
1412 d++;
1413 } else if (quote_flag) {
1414 strheap[strend++] = *d++;
1415 } else if (stype = StrType(d)) {
1416 strheap[strend++] = *d++;
1417 if (stype == 2) strheap[strend++] = *d++;
1418 } else break;
1419 }
1420 strheap[strend++] = 0;
1421 dprintf("\"%s\"", strheap + retnum);
1422 if (strend >= STRHEAP_SIZE) {
1423 dprintf("Error: string heap overflow\n");
1424 }
1425 return retnum;
1426 }
1427
1428 int Cmd::CopyString(const char* d) {
1429 int retnum = strend;
1430 int len = strlen(d);
1431 memcpy(strheap+strend, d, len+1);
1432 strend += len+1;
1433 d += len+1;
1434 return retnum;
1435 }
1436
1437 int Cmd::StrVar(int type, int var_num) {
1438 int retnum = strend;
1439 flags.Str(type, var_num, strheap+strend, STRHEAP_SIZE-strend);
1440 strend += strlen(strheap+strend)+1;
1441 return retnum;
1442 }
1443
1444 void Cmd::SetSysvar(int n, int val) {
1445 VarInfo info;
1446 if (cmd_type != CMD_SYSVAR) {
1447 args.clear();
1448 }
1449 cmd_type = CMD_SYSVAR;
1450
1451 info.type = TYPE_SYS;
1452 info.number = n;
1453 info.value = val;
1454 args.push_back(info);
1455 }
1456 void Cmd::SetFlagvar(VarInfo info, int val) {
1457 if (cmd_type != CMD_SYSVAR) {
1458 args.clear();
1459 }
1460 cmd_type = CMD_SYSVAR;
1461
1462 info.value = val;
1463 args.push_back(info);
1464 }
1465
1466 void Cmd::SetStrvar(VarInfo info, const string& s) {
1467 if (cmd_type != CMD_SYSVAR) {
1468 args.clear();
1469 }
1470
1471 cmd_type = CMD_SYSVAR;
1472 const char* ss = s.c_str();
1473 info.value = CopyString(ss);
1474 args.push_back(info);
1475 }
1476
1477 void Cmd::read(const CmdSimplified& from) {
1478 errorflag = false;
1479 ResetString();
1480
1481 cmd_type = Cmdtype(from.type);
1482 cmd1 = from.cmd1;
1483 cmd2 = from.cmd2;
1484 cmd3 = from.cmd3;
1485 cmd4 = from.cmd4;
1486 argc = from.argc;
1487 /* args の読み込み */
1488 args.clear();
1489 char* d = from.args;
1490 if (d == 0) return;
1491 while(*d != TYPE_END) {
1492 VarInfo info;
1493 switch(*d) {
1494 case TYPE_VAL:
1495 info.type = TYPE_VAL;
1496 info.number = 0;
1497 info.value = read_little_endian_int(d+1);
1498 d += 5;
1499 args.push_back(info);
1500 break;
1501 case TYPE_STR:
1502 info.type = TYPE_STR;
1503 info.number = 0;
1504 d++;
1505 info.value = CopyString( d);
1506 d += strlen(d)+1;
1507 args.push_back(info);
1508 break;
1509 default:
1510 fprintf(stderr,"Cmd::read: Invalid Load Data\n");
1511 *d = TYPE_END;
1512 }
1513 }
1514 return;
1515 }
1516 void Cmd::write(CmdSimplified& to, char*& buffer) const {
1517 /*
1518 if (cmd_type != CMD_OTHER) {
1519 fprintf(stderr,"Cmd::write: Invalid Cmd during Saving Data\n");
1520 to.cmd1 = 0; to.cmd2 = 0; to.cmd3 = 0; to.cmd4 = 0; to.argc = 0; to.args = 0;
1521 return;
1522 }
1523 */
1524 to.type = cmd_type;
1525 to.cmd1 = cmd1;
1526 to.cmd2 = cmd2;
1527 to.cmd3 = cmd3;
1528 to.cmd4 = cmd4;
1529 to.argc = argc;
1530 /* args の書き込み */
1531 if (args.empty()) {
1532 to.args = 0;
1533 } else {
1534 to.args = buffer;
1535 char* d = to.args;
1536 vector<VarInfo>::const_iterator it;
1537 for (it = args.begin(); it != args.end(); it++) {
1538 int type = it->type;
1539 if ( (type >= 0 && type < 7) || type == TYPE_VAL || type == char(TYPE_SYS)) { // digits
1540 *d++ = TYPE_VAL;
1541 write_little_endian_int(d, it->value);
1542 d += 4;
1543 } else if (type == TYPE_VARSTR || type == TYPE_VARSYSSTR || type == TYPE_VARLOCSTR || type == TYPE_STR) { // string
1544 *d++ = TYPE_STR;
1545 const char* s = Str(*it);
1546 int len = strlen(s);
1547 memcpy(d, s, len+1);
1548 d += len+1;
1549 } else {
1550 fprintf(stderr,"Cmd::write: Invalid Cmd args during Saving Data\n");
1551 }
1552 }
1553 *d++ = TYPE_END;
1554 buffer = d;
1555 }
1556 }
1557 void CmdSimplified::copy(const CmdSimplified& from, char*& args_buffer) {
1558 *this = from;
1559 if (args == 0) return;
1560 char* args_old = from.args;
1561 /* args のコピー */
1562 while(*args_old != TYPE_END) {
1563 if (*args_old == TYPE_VAL) {
1564 args_old += 5;
1565 } else { /* TYPE_STR */
1566 args_old += strlen(args_old)+1;
1567 }
1568 }
1569 args_old++;
1570 int args_len = args_old - from.args;
1571 memmove(args_buffer, from.args, args_len);
1572 args = args_buffer;
1573 args_buffer += args_len;
1574 }
1575 void CmdSimplified::Save(string& saveret) {
1576 char buf[1024];
1577 sprintf(buf, "%02x-%02x:%04x:%02x(%02d),", cmd1, cmd2, cmd3, cmd4, argc);
1578 saveret += buf;
1579
1580 /* args のコピー */
1581 char* d = args;
1582 while(d && *d != TYPE_END) {
1583 if (*d == TYPE_VAL) {
1584 d++;
1585 sprintf(buf, "%d,", read_little_endian_int(d));
1586 d += 4;
1587 } else { /* TYPE_STR と仮定 */
1588 d++;
1589 if (strlen(d) > 1000) d[1000] = 0; // ありえない・・・
1590 int i; int cnt = 0;
1591 buf[cnt++] = '"';
1592 for (i=0; d[i] != 0; i++) {
1593 if (d[i] == '"') buf[cnt++] = '"';
1594 buf[cnt++] = d[i];
1595 }
1596 buf[cnt++]='"';
1597 buf[cnt++] = ',';
1598 buf[cnt++] = 0;
1599 d += strlen(d)+1;
1600 }
1601 saveret += buf;
1602 }
1603 saveret += 'E';
1604 }
1605
1606 void CmdSimplified::Load(const char* save, char*& args_buffer) {
1607 args = args_buffer;
1608
1609 type = CMD_OTHER;
1610 sscanf(save, "%02x-%02x:%04x:%02x(%02d),", &cmd1, &cmd2, &cmd3, &cmd4, &argc);
1611 save = strchr(save, ',');
1612 if (save == 0) {
1613 *args_buffer++ = TYPE_END;
1614 return;
1615 }
1616 save++;
1617 while(*save != 'E' && *save != '\n' && *save != '\0') {
1618 if (isdigit(*save)) {
1619 int v;
1620 sscanf(save,"%d,",&v);
1621 *args_buffer++ = TYPE_VAL;
1622 write_little_endian_int(args_buffer, v);
1623 args_buffer+= 4;
1624 save = strchr(save, ',');
1625 if (save) save++;
1626 } else { // *save == '"'
1627 save++;
1628 *args_buffer++ = TYPE_STR;
1629 while(1) {
1630 if (*save == 0) break;
1631 if (*save == '"') {
1632 if (save[1] != '"') break;
1633 save++;
1634 }
1635 *args_buffer++ = *save++;
1636 }
1637 save += 2;
1638 *args_buffer++ = 0;
1639 }
1640 }
1641 *args_buffer++ = TYPE_END;
1642 return;
1643 }
1644
1645 #ifdef SCN_DUMP
1646 void usage(void) {
1647 fprintf(stderr,"usage : scn2kdump [inputfile] [outputfile]\n");
1648 fprintf(stderr," inputfile: seen.txt(default)\n");
1649 fprintf(stderr," outputfile: seen.txt_out(default)\n");
1650 exit(-1);
1651 }
1652 int main(int argc, char** argv) {
1653 /* determine file names */
1654 bool verbose = false;
1655 char* inname = "seen.txt";
1656 char* outname = 0;
1657 if (argc > 2 && strcmp(argv[1],"-v") == 0) {
1658 int i; for (i=1; i<argc; i++) argv[i] = argv[i+1];
1659 argc--;
1660 verbose = true;
1661 }
1662 switch(argc) {
1663 case 1: break;
1664 case 2: inname = argv[1]; break;
1665 case 3: inname = argv[1]; outname = argv[2]; break;
1666 default: usage();
1667 }
1668 /* open output file */
1669 FILE* outstream = stdout;
1670 /* create archive instance */
1671 SCN2kFILE archive(inname);
1672 archive.Init();
1673 if (archive.Deal() == 0) {
1674 fprintf(stderr,"Cannot open / Invalid archive file %s\n",inname);
1675 usage();
1676 }
1677 /* dump files */
1678 archive.InitList();
1679 char* fname;
1680 fprintf(stderr,"Dump start\n");
1681 int system_version = 0;
1682 while( (fname = archive.ListItem()) != 0) {
1683 ARCINFO* info = archive.Find(fname,"");
1684 if (info == 0) continue;
1685 char* data = info->CopyRead();
1686 char* d = data;
1687 char* dend = d + info->Size();
1688 /* version 確認 */
1689 if (read_little_endian_int(d) == 0x1cc) {
1690 system_version = 0;
1691 } else if (read_little_endian_int(d) == 0x1d0) {
1692 system_version = 1;
1693 } else {
1694 continue;
1695 }
1696 if (read_little_endian_int(d+4) == 0x1adb2) ; // little busters!
1697 else if (read_little_endian_int(d+4) != 0x2712) continue;
1698 int header_size;
1699 if (system_version == 0) {
1700 header_size = 0x1cc + read_little_endian_int(d+0x20) * 4;
1701 } else {
1702 header_size = read_little_endian_int(d+0x20);
1703 }
1704 d += header_size;
1705
1706 const char* dcur = d;
1707 const char* dstart = d;
1708 fprintf(stderr,"Dumping %s\n",fname);
1709 Flags flags;
1710 /* 最初から最後までコマンド取得 -> 出力を繰り返す */
1711 while(dcur<dend) {
1712 const char* dprev = dcur;
1713 Cmd cmd(flags, system_version); cmd.ClearError();
1714
1715 /* end? */
1716 if (*dcur == -1) {
1717 /* 0xff x 32byte + 0x00 : end sign */
1718 int i; for (i=0; i<0x20; i++)
1719 if (dcur[i] != -1) break;
1720 if (i == 0x20 && dcur[i] == 0) break;
1721 }
1722 dprintf("%d : ",dcur-dstart);
1723 cmd.GetCmd(flags, dcur);
1724 if (cmd.IsError()) {
1725 fprintf(outstream, "Error at %6d\n",dprev-dstart);
1726 while(dcur < dend) {
1727 if (*dcur == 0x29 && dcur[1] == 0x0a) {dcur++;break;}
1728 dcur++;
1729 }
1730 dprev -= 2*16;
1731 int ilen = (dcur-dprev+15)/16;
1732 int i; for (i=0; i<ilen; i++) {
1733 fprintf(outstream, "%6d: ",dprev-dstart);
1734 int j; for (j=0; j<16; j++) {
1735 if (dprev >= dend) break;
1736 if (dprev < data) continue;
1737 fprintf(outstream, "%02x ",*(unsigned char*)(dprev));
1738 dprev++;
1739 }
1740 fprintf(outstream, "\n");
1741 }
1742 }
1743 }
1744 delete info;
1745 }
1746 return 0;
1747 }
1748 #endif
1749