CMDscan.l 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. %{
  2. // flex --nounput -o CMDscan.cpp -P CMD CMDscan.l
  3. #define YYLMAX 4096
  4. #define YY_NO_UNISTD_H
  5. #include <stdio.h>
  6. #include "platform/platform.h"
  7. #include "core/stringTable.h"
  8. #include "console/console.h"
  9. #include "console/compiler.h"
  10. #include "console/dynamicTypes.h"
  11. #include "core/strings/stringFunctions.h"
  12. template< typename T >
  13. struct Token
  14. {
  15. T value;
  16. S32 lineNumber;
  17. };
  18. // Can't have ctors in structs used in unions, so we have this.
  19. template< typename T >
  20. inline Token< T > MakeToken( T value, U32 lineNumber )
  21. {
  22. Token< T > result;
  23. result.value = value;
  24. result.lineNumber = lineNumber;
  25. return result;
  26. }
  27. #include "console/cmdgram.h"
  28. // HACK: C++17 and beyond can't use register keyword
  29. #define register
  30. using namespace Compiler;
  31. #define YY_NEVER_INTERACTIVE 1
  32. // Some basic parsing primitives...
  33. static int Sc_ScanDocBlock();
  34. static int Sc_ScanString(int ret);
  35. static int Sc_ScanNum();
  36. static int Sc_ScanVar();
  37. static int Sc_ScanHex();
  38. static int Sc_ScanIdent();
  39. // Deal with debuggability of FLEX.
  40. #ifdef TORQUE_DEBUG
  41. #define FLEX_DEBUG 1
  42. #else
  43. #define FLEX_DEBUG 0
  44. #endif
  45. // Install our own input code...
  46. #undef CMDgetc
  47. int CMDgetc();
  48. // Hack to make windows lex happy.
  49. #ifndef isatty
  50. inline int isatty(int) { return 0; }
  51. #endif
  52. // Wrap our getc, so that lex doesn't try to do its own buffering/file IO.
  53. #define YY_INPUT(buf,result,max_size) \
  54. { \
  55. int c = '*', n; \
  56. for ( n = 0; n < max_size && \
  57. (c = CMDgetc()) != EOF && c != '\n'; ++n ) \
  58. buf[n] = (char) c; \
  59. if ( c == '\n' ) \
  60. buf[n++] = (char) c; \
  61. result = n; \
  62. }
  63. // General helper stuff.
  64. static int lineIndex;
  65. // File state
  66. void CMDSetScanBuffer(const char *sb, const char *fn);
  67. const char * CMDgetFileLine(int &lineNumber);
  68. // Error reporting
  69. void CMDerror(const char * s, ...);
  70. // Reset the parser.
  71. void CMDrestart(FILE *in);
  72. %}
  73. DIGIT [0-9]
  74. INTEGER {DIGIT}+
  75. FLOAT ({INTEGER}?\.{INTEGER})|({INTEGER}(\.{INTEGER})?[eE][+-]?{INTEGER})
  76. LETTER [A-Za-z_]
  77. FILECHAR [A-Za-z_\.]
  78. VARMID [:A-Za-z0-9_]
  79. IDTAIL [A-Za-z0-9_]
  80. VARTAIL {VARMID}*{IDTAIL}
  81. VAR [$%]{LETTER}{VARTAIL}*
  82. ID {LETTER}{IDTAIL}*
  83. ILID [$%]{DIGIT}+{LETTER}{VARTAIL}*
  84. FILENAME {FILECHAR}+
  85. SPACE [ \t\v\f]
  86. HEXDIGIT [a-fA-F0-9]
  87. %%
  88. ;
  89. {SPACE}+ { }
  90. ("///"([^/\n\r][^\n\r]*)?[\n\r]+)+ { return(Sc_ScanDocBlock()); }
  91. "//"[^\n\r]* ;
  92. [\r] ;
  93. [\n] {lineIndex++;}
  94. \"(\\.|[^\\"\n\r])*\" { return(Sc_ScanString(STRATOM)); }
  95. \'(\\.|[^\\'\n\r])*\' { return(Sc_ScanString(TAGATOM)); }
  96. "==" { CMDlval.i = MakeToken< int >( opEQ, lineIndex ); return opEQ; }
  97. "!=" { CMDlval.i = MakeToken< int >( opNE, lineIndex ); return opNE; }
  98. ">=" { CMDlval.i = MakeToken< int >( opGE, lineIndex ); return opGE; }
  99. "<=" { CMDlval.i = MakeToken< int >( opLE, lineIndex ); return opLE; }
  100. "&&" { CMDlval.i = MakeToken< int >( opAND, lineIndex ); return opAND; }
  101. "||" { CMDlval.i = MakeToken< int >( opOR, lineIndex ); return opOR; }
  102. "::" { CMDlval.i = MakeToken< int >( opCOLONCOLON, lineIndex ); return opCOLONCOLON; }
  103. "--" { CMDlval.i = MakeToken< int >( opMINUSMINUS, lineIndex ); return opMINUSMINUS; }
  104. "++" { CMDlval.i = MakeToken< int >( opPLUSPLUS, lineIndex ); return opPLUSPLUS; }
  105. "$=" { CMDlval.i = MakeToken< int >( opSTREQ, lineIndex ); return opSTREQ; }
  106. "!$=" { CMDlval.i = MakeToken< int >( opSTRNE, lineIndex ); return opSTRNE; }
  107. "<<" { CMDlval.i = MakeToken< int >( opSHL, lineIndex ); return opSHL; }
  108. ">>" { CMDlval.i = MakeToken< int >( opSHR, lineIndex ); return opSHR; }
  109. "+=" { CMDlval.i = MakeToken< int >( opPLASN, lineIndex ); return opPLASN; }
  110. "-=" { CMDlval.i = MakeToken< int >( opMIASN, lineIndex ); return opMIASN; }
  111. "*=" { CMDlval.i = MakeToken< int >( opMLASN, lineIndex ); return opMLASN; }
  112. "/=" { CMDlval.i = MakeToken< int >( opDVASN, lineIndex ); return opDVASN; }
  113. "%=" { CMDlval.i = MakeToken< int >( opMODASN, lineIndex ); return opMODASN; }
  114. "&=" { CMDlval.i = MakeToken< int >( opANDASN, lineIndex ); return opANDASN; }
  115. "^=" { CMDlval.i = MakeToken< int >( opXORASN, lineIndex ); return opXORASN; }
  116. "|=" { CMDlval.i = MakeToken< int >( opORASN, lineIndex ); return opORASN; }
  117. "<<=" { CMDlval.i = MakeToken< int >( opSLASN, lineIndex ); return opSLASN; }
  118. ">>=" { CMDlval.i = MakeToken< int >( opSRASN, lineIndex ); return opSRASN; }
  119. "->" { CMDlval.i = MakeToken< int >( opINTNAME, lineIndex ); return opINTNAME; }
  120. "-->" { CMDlval.i = MakeToken< int >( opINTNAMER, lineIndex ); return opINTNAMER; }
  121. "NL" { CMDlval.i = MakeToken< int >( '\n', lineIndex ); return '@'; }
  122. "TAB" { CMDlval.i = MakeToken< int >( '\t', lineIndex ); return '@'; }
  123. "SPC" { CMDlval.i = MakeToken< int >( ' ', lineIndex ); return '@'; }
  124. "@" { CMDlval.i = MakeToken< int >( 0, lineIndex ); return '@'; }
  125. "/*" { /* this comment stops syntax highlighting from getting messed up when editing the lexer in TextPad */
  126. int c = 0, l;
  127. for ( ; ; )
  128. {
  129. l = c;
  130. c = yyinput();
  131. // Is this an open comment?
  132. if ( c == EOF )
  133. {
  134. CMDerror( "unexpected end of file found in comment" );
  135. break;
  136. }
  137. // Increment line numbers.
  138. else if ( c == '\n' )
  139. lineIndex++;
  140. // Did we find the end of the comment?
  141. else if ( l == '*' && c == '/' )
  142. break;
  143. }
  144. }
  145. "?" |
  146. "[" |
  147. "]" |
  148. "(" |
  149. ")" |
  150. "+" |
  151. "-" |
  152. "*" |
  153. "/" |
  154. "<" |
  155. ">" |
  156. "|" |
  157. "." |
  158. "!" |
  159. ":" |
  160. ";" |
  161. "{" |
  162. "}" |
  163. "," |
  164. "&" |
  165. "%" |
  166. "^" |
  167. "~" |
  168. "=" { CMDlval.i = MakeToken< int >( CMDtext[ 0 ], lineIndex ); return CMDtext[ 0 ]; }
  169. "in" { CMDlval.i = MakeToken< int >( rwIN, lineIndex ); return(rwIN); }
  170. "or" { CMDlval.i = MakeToken< int >( rwCASEOR, lineIndex ); return(rwCASEOR); }
  171. "break" { CMDlval.i = MakeToken< int >( rwBREAK, lineIndex ); return(rwBREAK); }
  172. "return" { CMDlval.i = MakeToken< int >( rwRETURN, lineIndex ); return(rwRETURN); }
  173. "else" { CMDlval.i = MakeToken< int >( rwELSE, lineIndex ); return(rwELSE); }
  174. "assert" { CMDlval.i = MakeToken< int >( rwASSERT, lineIndex ); return(rwASSERT); }
  175. "while" { CMDlval.i = MakeToken< int >( rwWHILE, lineIndex ); return(rwWHILE); }
  176. "do" { CMDlval.i = MakeToken< int >( rwDO, lineIndex ); return(rwDO); }
  177. "if" { CMDlval.i = MakeToken< int >( rwIF, lineIndex ); return(rwIF); }
  178. "foreach$" { CMDlval.i = MakeToken< int >( rwFOREACHSTR, lineIndex ); return(rwFOREACHSTR); }
  179. "foreach" { CMDlval.i = MakeToken< int >( rwFOREACH, lineIndex ); return(rwFOREACH); }
  180. "for" { CMDlval.i = MakeToken< int >( rwFOR, lineIndex ); return(rwFOR); }
  181. "continue" { CMDlval.i = MakeToken< int >( rwCONTINUE, lineIndex ); return(rwCONTINUE); }
  182. "function" { CMDlval.i = MakeToken< int >( rwDEFINE, lineIndex ); return(rwDEFINE); }
  183. "new" { CMDlval.i = MakeToken< int >( rwDECLARE, lineIndex ); return(rwDECLARE); }
  184. "singleton" { CMDlval.i = MakeToken< int >( rwDECLARESINGLETON, lineIndex ); return(rwDECLARESINGLETON); }
  185. "datablock" { CMDlval.i = MakeToken< int >( rwDATABLOCK, lineIndex ); return(rwDATABLOCK); }
  186. "case" { CMDlval.i = MakeToken< int >( rwCASE, lineIndex ); return(rwCASE); }
  187. "switch$" { CMDlval.i = MakeToken< int >( rwSWITCHSTR, lineIndex ); return(rwSWITCHSTR); }
  188. "switch" { CMDlval.i = MakeToken< int >( rwSWITCH, lineIndex ); return(rwSWITCH); }
  189. "default" { CMDlval.i = MakeToken< int >( rwDEFAULT, lineIndex ); return(rwDEFAULT); }
  190. "package" { CMDlval.i = MakeToken< int >( rwPACKAGE, lineIndex ); return(rwPACKAGE); }
  191. "namespace" { CMDlval.i = MakeToken< int >( rwNAMESPACE, lineIndex ); return(rwNAMESPACE); }
  192. "true" { CMDlval.i = MakeToken< int >( 1, lineIndex ); return INTCONST; }
  193. "false" { CMDlval.i = MakeToken< int >( 0, lineIndex ); return INTCONST; }
  194. {VAR} { return(Sc_ScanVar()); }
  195. {ID} { return Sc_ScanIdent(); }
  196. 0[xX]{HEXDIGIT}+ return(Sc_ScanHex());
  197. {INTEGER} { CMDtext[CMDleng] = 0; CMDlval.i = MakeToken< int >( dAtoi(CMDtext), lineIndex ); return INTCONST; }
  198. {FLOAT} return Sc_ScanNum();
  199. {ILID} return(ILLEGAL_TOKEN);
  200. . return(ILLEGAL_TOKEN);
  201. %%
  202. static const char *scanBuffer;
  203. static const char *fileName;
  204. static int scanIndex;
  205. const char * CMDGetCurrentFile()
  206. {
  207. return fileName;
  208. }
  209. int CMDGetCurrentLine()
  210. {
  211. return lineIndex;
  212. }
  213. extern bool gConsoleSyntaxError;
  214. void CMDerror(const char *format, ...)
  215. {
  216. Compiler::gSyntaxError = true;
  217. const int BUFMAX = 1024;
  218. char tempBuf[BUFMAX];
  219. va_list args;
  220. va_start( args, format );
  221. #ifdef TORQUE_OS_WIN
  222. _vsnprintf( tempBuf, BUFMAX, format, args );
  223. #else
  224. vsnprintf( tempBuf, BUFMAX, format, args );
  225. #endif
  226. va_end(args);
  227. if(fileName)
  228. {
  229. Con::errorf(ConsoleLogEntry::Script, "%s Line: %d - %s", fileName, lineIndex, tempBuf);
  230. #ifndef NO_ADVANCED_ERROR_REPORT
  231. // dhc - lineIndex is bogus. let's try to add some sanity back in.
  232. int i,j,n;
  233. char c;
  234. int linediv = 1;
  235. // first, walk the buffer, trying to detect line ending type.
  236. // this is imperfect, if inconsistant line endings exist...
  237. for (i=0; i<scanIndex; i++)
  238. {
  239. c = scanBuffer[i];
  240. if (c=='\r' && scanBuffer[i+1]=='\n') linediv = 2; // crlf detected
  241. if (c=='\r' || c=='\n' || c==0) break; // enough for us to stop.
  242. }
  243. // grab some of the chars starting at the error location - lineending.
  244. i = 1; j = 0; n = 1;
  245. // find prev lineending
  246. while (n<BUFMAX-8 && i<scanIndex) // cap at file start
  247. {
  248. c = scanBuffer[scanIndex-i];
  249. if ((c=='\r' || c=='\n') && i>BUFMAX>>2) break; // at least get a little data
  250. n++; i++;
  251. }
  252. // find next lineending
  253. while (n<BUFMAX-8 && j<BUFMAX>>1) // cap at half-buf-size forward
  254. {
  255. c = scanBuffer[scanIndex+j];
  256. if (c==0) break;
  257. if ((c=='\r' || c=='\n') && j>BUFMAX>>2) break; // at least get a little data
  258. n++; j++;
  259. }
  260. if (i) i--; // chop off extra linefeed.
  261. if (j) j--; // chop off extra linefeed.
  262. // build our little text block
  263. if (i) dStrncpy(tempBuf,scanBuffer+scanIndex-i,i);
  264. dStrncpy(tempBuf+i,"##", 2); // bracketing.
  265. tempBuf[i+2] = scanBuffer[scanIndex]; // copy the halt character.
  266. dStrncpy(tempBuf+i+3,"##", 2); // bracketing.
  267. if (j) dStrncpy(tempBuf+i+5,scanBuffer+scanIndex+1,j); // +1 to go past current char.
  268. tempBuf[i+j+5] = 0; // null terminate
  269. for(n=0; n<i+j+5; n++) // convert CR to LF if alone...
  270. if (tempBuf[n]=='\r' && tempBuf[n+1]!='\n') tempBuf[n] = '\n';
  271. // write out to console the advanced error report
  272. Con::warnf(ConsoleLogEntry::Script, ">>> Advanced script error report. Line %d.", lineIndex);
  273. Con::warnf(ConsoleLogEntry::Script, ">>> Some error context, with ## on sides of error halt:");
  274. Con::errorf(ConsoleLogEntry::Script, "%s", tempBuf);
  275. Con::warnf(ConsoleLogEntry::Script, ">>> Error report complete.\n");
  276. #endif
  277. // Update the script-visible error buffer.
  278. const char *prevStr = Con::getVariable("$ScriptError");
  279. if (prevStr[0])
  280. dSprintf(tempBuf, sizeof(tempBuf), "%s\n%s Line: %d - Syntax error.", prevStr, fileName, lineIndex);
  281. else
  282. dSprintf(tempBuf, sizeof(tempBuf), "%s Line: %d - Syntax error.", fileName, lineIndex);
  283. Con::setVariable("$ScriptError", tempBuf);
  284. // We also need to mark that we came up with a new error.
  285. static S32 sScriptErrorHash=1000;
  286. Con::setIntVariable("$ScriptErrorHash", sScriptErrorHash++);
  287. }
  288. else
  289. Con::errorf(ConsoleLogEntry::Script, tempBuf);
  290. }
  291. void CMDSetScanBuffer(const char *sb, const char *fn)
  292. {
  293. scanBuffer = sb;
  294. fileName = fn;
  295. scanIndex = 0;
  296. lineIndex = 1;
  297. }
  298. int CMDgetc()
  299. {
  300. int ret = scanBuffer[scanIndex];
  301. if(ret)
  302. scanIndex++;
  303. else
  304. ret = -1;
  305. return ret;
  306. }
  307. int CMDwrap()
  308. {
  309. return 1;
  310. }
  311. static int Sc_ScanVar()
  312. {
  313. // Truncate the temp buffer...
  314. CMDtext[CMDleng] = 0;
  315. // Make it a stringtable string!
  316. CMDlval.s = MakeToken< StringTableEntry >( StringTable->insert(CMDtext), lineIndex );
  317. return(VAR);
  318. }
  319. static int charConv(int in)
  320. {
  321. switch(in)
  322. {
  323. case 'r':
  324. return '\r';
  325. case 'n':
  326. return '\n';
  327. case 't':
  328. return '\t';
  329. default:
  330. return in;
  331. }
  332. }
  333. static int getHexDigit(char c)
  334. {
  335. if(c >= '0' && c <= '9')
  336. return c - '0';
  337. if(c >= 'A' && c <= 'F')
  338. return c - 'A' + 10;
  339. if(c >= 'a' && c <= 'f')
  340. return c - 'a' + 10;
  341. return -1;
  342. }
  343. static int Sc_ScanDocBlock()
  344. {
  345. S32 len = dStrlen(CMDtext);
  346. char* text = (char *) consoleAlloc(len + 1);
  347. S32 line = lineIndex;
  348. for( S32 i = 0, j = 0; j <= len; j++ )
  349. {
  350. if( ( j <= (len - 2) ) && ( CMDtext[j] == '/' ) && ( CMDtext[j + 1] == '/' ) && ( CMDtext[j + 2] == '/' ) )
  351. {
  352. j += 2;
  353. continue;
  354. }
  355. if( CMDtext[j] == '\r' )
  356. continue;
  357. if( CMDtext[j] == '\n' )
  358. lineIndex++;
  359. text[i++] = CMDtext[j];
  360. }
  361. CMDlval.str = MakeToken< char* >( text, line );
  362. return(DOCBLOCK);
  363. }
  364. static int Sc_ScanString(int ret)
  365. {
  366. CMDtext[CMDleng - 1] = 0;
  367. if(!collapseEscape(CMDtext+1))
  368. return -1;
  369. dsize_t bufferLen = dStrlen( CMDtext );
  370. char* buffer = ( char* ) consoleAlloc( bufferLen );
  371. dStrcpy( buffer, CMDtext + 1, bufferLen );
  372. CMDlval.str = MakeToken< char* >( buffer, lineIndex );
  373. return ret;
  374. }
  375. static int Sc_ScanIdent()
  376. {
  377. ConsoleBaseType *type;
  378. CMDtext[CMDleng] = 0;
  379. if((type = ConsoleBaseType::getTypeByName(CMDtext)) != NULL)
  380. {
  381. /* It's a type */
  382. CMDlval.i = MakeToken< int >( type->getTypeID(), lineIndex );
  383. return TYPEIDENT;
  384. }
  385. /* It's an identifier */
  386. CMDlval.s = MakeToken< StringTableEntry >( StringTable->insert(CMDtext), lineIndex );
  387. return IDENT;
  388. }
  389. void expandEscape(char *dest, const char *src)
  390. {
  391. U8 c;
  392. while((c = (U8) *src++) != 0)
  393. {
  394. if(c == '\"')
  395. {
  396. *dest++ = '\\';
  397. *dest++ = '\"';
  398. }
  399. else if(c == '\\')
  400. {
  401. *dest++ = '\\';
  402. *dest++ = '\\';
  403. }
  404. else if(c == '\r')
  405. {
  406. *dest++ = '\\';
  407. *dest++ = 'r';
  408. }
  409. else if(c == '\n')
  410. {
  411. *dest++ = '\\';
  412. *dest++ = 'n';
  413. }
  414. else if(c == '\t')
  415. {
  416. *dest++ = '\\';
  417. *dest++ = 't';
  418. }
  419. else if(c == '\'')
  420. {
  421. *dest++ = '\\';
  422. *dest++ = '\'';
  423. }
  424. else if((c >= 1 && c <= 7) ||
  425. (c >= 11 && c <= 12) ||
  426. (c >= 14 && c <= 15))
  427. {
  428. /* Remap around: \b = 0x8, \t = 0x9, \n = 0xa, \r = 0xd */
  429. static U8 expandRemap[15] = { 0x0,
  430. 0x0,
  431. 0x1,
  432. 0x2,
  433. 0x3,
  434. 0x4,
  435. 0x5,
  436. 0x6,
  437. 0x0,
  438. 0x0,
  439. 0x0,
  440. 0x7,
  441. 0x8,
  442. 0x0,
  443. 0x9 };
  444. *dest++ = '\\';
  445. *dest++ = 'c';
  446. if(c == 15)
  447. *dest++ = 'r';
  448. else if(c == 16)
  449. *dest++ = 'p';
  450. else if(c == 17)
  451. *dest++ = 'o';
  452. else
  453. *dest++ = expandRemap[c] + '0';
  454. }
  455. else if(c < 32)
  456. {
  457. *dest++ = '\\';
  458. *dest++ = 'x';
  459. S32 dig1 = c >> 4;
  460. S32 dig2 = c & 0xf;
  461. if(dig1 < 10)
  462. dig1 += '0';
  463. else
  464. dig1 += 'A' - 10;
  465. if(dig2 < 10)
  466. dig2 += '0';
  467. else
  468. dig2 += 'A' - 10;
  469. *dest++ = dig1;
  470. *dest++ = dig2;
  471. }
  472. else
  473. *dest++ = c;
  474. }
  475. *dest = '\0';
  476. }
  477. bool collapseEscape(char *buf)
  478. {
  479. S32 len = dStrlen(buf) + 1;
  480. for(S32 i = 0; i < len;)
  481. {
  482. if(buf[i] == '\\')
  483. {
  484. if(buf[i+1] == 'x')
  485. {
  486. S32 dig1 = getHexDigit(buf[i+2]);
  487. if(dig1 == -1)
  488. return false;
  489. S32 dig2 = getHexDigit(buf[i+3]);
  490. if(dig2 == -1)
  491. return false;
  492. buf[i] = dig1 * 16 + dig2;
  493. dMemmove(buf + i + 1, buf + i + 4, len - i - 3);
  494. len -= 3;
  495. i++;
  496. }
  497. else if(buf[i+1] == 'c')
  498. {
  499. /* Remap around: \b = 0x8, \t = 0x9, \n = 0xa, \r = 0xd */
  500. static U8 collapseRemap[10] = { 0x1,
  501. 0x2,
  502. 0x3,
  503. 0x4,
  504. 0x5,
  505. 0x6,
  506. 0x7,
  507. 0xb,
  508. 0xc,
  509. 0xe };
  510. if(buf[i+2] == 'r')
  511. buf[i] = 15;
  512. else if(buf[i+2] == 'p')
  513. buf[i] = 16;
  514. else if(buf[i+2] == 'o')
  515. buf[i] = 17;
  516. else
  517. {
  518. int dig1 = buf[i+2] - '0';
  519. if(dig1 < 0 || dig1 > 9)
  520. return false;
  521. buf[i] = collapseRemap[dig1];
  522. }
  523. // Make sure we don't put 0x1 at the beginning of the string.
  524. if ((buf[i] == 0x1) && (i == 0))
  525. {
  526. buf[i] = 0x2;
  527. buf[i+1] = 0x1;
  528. dMemmove(buf + i + 2, buf + i + 3, len - i - 1);
  529. len -= 1;
  530. }
  531. else
  532. {
  533. dMemmove(buf + i + 1, buf + i + 3, len - i - 2);
  534. len -= 2;
  535. }
  536. i++;
  537. }
  538. else
  539. {
  540. buf[i] = charConv(buf[i+1]);
  541. dMemmove(buf + i + 1, buf + i + 2, len - i - 1);
  542. len--;
  543. i++;
  544. }
  545. }
  546. else
  547. i++;
  548. }
  549. return true;
  550. }
  551. static int Sc_ScanNum()
  552. {
  553. CMDtext[CMDleng] = 0;
  554. CMDlval.f = MakeToken< double >( dAtof(CMDtext), lineIndex );
  555. return(FLTCONST);
  556. }
  557. static int Sc_ScanHex()
  558. {
  559. S32 val = 0;
  560. dSscanf(CMDtext, "%x", &val);
  561. CMDlval.i = MakeToken< int >( val, lineIndex );
  562. return INTCONST;
  563. }
  564. void CMD_reset()
  565. {
  566. CMDrestart(NULL);
  567. }