scriplib.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1997-2006 Id Software, Inc.
  4. This file is part of Quake 2 Tools source code.
  5. Quake 2 Tools source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake 2 Tools source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Quake 2 Tools source code; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. // scriplib.c
  19. #include "cmdlib.h"
  20. #include "scriplib.h"
  21. /*
  22. =============================================================================
  23. PARSING STUFF
  24. =============================================================================
  25. */
  26. typedef struct
  27. {
  28. char filename[1024];
  29. char *buffer,*script_p,*end_p;
  30. int line;
  31. } script_t;
  32. #define MAX_INCLUDES 8
  33. script_t scriptstack[MAX_INCLUDES];
  34. script_t *script;
  35. int scriptline;
  36. char token[MAXTOKEN];
  37. qboolean endofscript;
  38. qboolean tokenready; // only true if UnGetToken was just called
  39. /*
  40. ==============
  41. AddScriptToStack
  42. ==============
  43. */
  44. void AddScriptToStack (char *filename)
  45. {
  46. int size;
  47. script++;
  48. if (script == &scriptstack[MAX_INCLUDES])
  49. Error ("script file exceeded MAX_INCLUDES");
  50. strcpy (script->filename, ExpandPath (filename) );
  51. size = LoadFile (script->filename, (void **)&script->buffer);
  52. printf ("entering %s\n", script->filename);
  53. script->line = 1;
  54. script->script_p = script->buffer;
  55. script->end_p = script->buffer + size;
  56. }
  57. /*
  58. ==============
  59. LoadScriptFile
  60. ==============
  61. */
  62. void LoadScriptFile (char *filename)
  63. {
  64. script = scriptstack;
  65. AddScriptToStack (filename);
  66. endofscript = false;
  67. tokenready = false;
  68. }
  69. /*
  70. ==============
  71. ParseFromMemory
  72. ==============
  73. */
  74. void ParseFromMemory (char *buffer, int size)
  75. {
  76. script = scriptstack;
  77. script++;
  78. if (script == &scriptstack[MAX_INCLUDES])
  79. Error ("script file exceeded MAX_INCLUDES");
  80. strcpy (script->filename, "memory buffer" );
  81. script->buffer = buffer;
  82. script->line = 1;
  83. script->script_p = script->buffer;
  84. script->end_p = script->buffer + size;
  85. endofscript = false;
  86. tokenready = false;
  87. }
  88. /*
  89. ==============
  90. UnGetToken
  91. Signals that the current token was not used, and should be reported
  92. for the next GetToken. Note that
  93. GetToken (true);
  94. UnGetToken ();
  95. GetToken (false);
  96. could cross a line boundary.
  97. ==============
  98. */
  99. void UnGetToken (void)
  100. {
  101. tokenready = true;
  102. }
  103. qboolean EndOfScript (qboolean crossline)
  104. {
  105. if (!crossline)
  106. Error ("Line %i is incomplete\n",scriptline);
  107. if (!strcmp (script->filename, "memory buffer"))
  108. {
  109. endofscript = true;
  110. return false;
  111. }
  112. free (script->buffer);
  113. if (script == scriptstack+1)
  114. {
  115. endofscript = true;
  116. return false;
  117. }
  118. script--;
  119. scriptline = script->line;
  120. printf ("returning to %s\n", script->filename);
  121. return GetToken (crossline);
  122. }
  123. /*
  124. ==============
  125. GetToken
  126. ==============
  127. */
  128. qboolean GetToken (qboolean crossline)
  129. {
  130. char *token_p;
  131. if (tokenready) // is a token allready waiting?
  132. {
  133. tokenready = false;
  134. return true;
  135. }
  136. if (script->script_p >= script->end_p)
  137. return EndOfScript (crossline);
  138. //
  139. // skip space
  140. //
  141. skipspace:
  142. while (*script->script_p <= 32)
  143. {
  144. if (script->script_p >= script->end_p)
  145. return EndOfScript (crossline);
  146. if (*script->script_p++ == '\n')
  147. {
  148. if (!crossline)
  149. Error ("Line %i is incomplete\n",scriptline);
  150. scriptline = script->line++;
  151. }
  152. }
  153. if (script->script_p >= script->end_p)
  154. return EndOfScript (crossline);
  155. // ; # // comments
  156. if (*script->script_p == ';' || *script->script_p == '#'
  157. || ( script->script_p[0] == '/' && script->script_p[1] == '/') )
  158. {
  159. if (!crossline)
  160. Error ("Line %i is incomplete\n",scriptline);
  161. while (*script->script_p++ != '\n')
  162. if (script->script_p >= script->end_p)
  163. return EndOfScript (crossline);
  164. goto skipspace;
  165. }
  166. // /* */ comments
  167. if (script->script_p[0] == '/' && script->script_p[1] == '*')
  168. {
  169. if (!crossline)
  170. Error ("Line %i is incomplete\n",scriptline);
  171. script->script_p+=2;
  172. while (script->script_p[0] != '*' && script->script_p[1] != '/')
  173. {
  174. script->script_p++;
  175. if (script->script_p >= script->end_p)
  176. return EndOfScript (crossline);
  177. }
  178. script->script_p += 2;
  179. goto skipspace;
  180. }
  181. //
  182. // copy token
  183. //
  184. token_p = token;
  185. if (*script->script_p == '"')
  186. {
  187. // quoted token
  188. script->script_p++;
  189. while (*script->script_p != '"')
  190. {
  191. *token_p++ = *script->script_p++;
  192. if (script->script_p == script->end_p)
  193. break;
  194. if (token_p == &token[MAXTOKEN])
  195. Error ("Token too large on line %i\n",scriptline);
  196. }
  197. script->script_p++;
  198. }
  199. else // regular token
  200. while ( *script->script_p > 32 && *script->script_p != ';')
  201. {
  202. *token_p++ = *script->script_p++;
  203. if (script->script_p == script->end_p)
  204. break;
  205. if (token_p == &token[MAXTOKEN])
  206. Error ("Token too large on line %i\n",scriptline);
  207. }
  208. *token_p = 0;
  209. if (!strcmp (token, "$include"))
  210. {
  211. GetToken (false);
  212. AddScriptToStack (token);
  213. return GetToken (crossline);
  214. }
  215. return true;
  216. }
  217. /*
  218. ==============
  219. TokenAvailable
  220. Returns true if there is another token on the line
  221. ==============
  222. */
  223. qboolean TokenAvailable (void)
  224. {
  225. char *search_p;
  226. search_p = script->script_p;
  227. if (search_p >= script->end_p)
  228. return false;
  229. while ( *search_p <= 32)
  230. {
  231. if (*search_p == '\n')
  232. return false;
  233. search_p++;
  234. if (search_p == script->end_p)
  235. return false;
  236. }
  237. if (*search_p == ';')
  238. return false;
  239. return true;
  240. }