PageRenderTime 21ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/botlib/l_struct.c

http://bzzwolfmp.googlecode.com/
C | 507 lines | 383 code | 18 blank | 106 comment | 107 complexity | 6e0d6a916eab05c634071d427260a53f MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. ===========================================================================
  3. Return to Castle Wolfenstein multiplayer GPL Source Code
  4. Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (?RTCW MP Source Code?).
  6. RTCW MP Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. RTCW MP Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. /*****************************************************************************
  21. * name: l_struct.c
  22. *
  23. * desc: structure reading / writing
  24. *
  25. *
  26. *****************************************************************************/
  27. #ifdef BOTLIB
  28. #include "../game/q_shared.h"
  29. #include "../game/botlib.h" //for the include of be_interface.h
  30. #include "l_script.h"
  31. #include "l_precomp.h"
  32. #include "l_struct.h"
  33. #include "l_utils.h"
  34. #include "be_interface.h"
  35. #endif //BOTLIB
  36. #ifdef BSPC
  37. //include files for usage in the BSP Converter
  38. #include "../bspc/qbsp.h"
  39. #include "../bspc/l_log.h"
  40. #include "../bspc/l_mem.h"
  41. #include "l_precomp.h"
  42. #include "l_struct.h"
  43. #define qtrue true
  44. #define qfalse false
  45. #endif //BSPC
  46. //===========================================================================
  47. //
  48. // Parameter: -
  49. // Returns: -
  50. // Changes Globals: -
  51. //===========================================================================
  52. fielddef_t *FindField( fielddef_t *defs, char *name ) {
  53. int i;
  54. for ( i = 0; defs[i].name; i++ )
  55. {
  56. if ( !strcmp( defs[i].name, name ) ) {
  57. return &defs[i];
  58. }
  59. } //end for
  60. return NULL;
  61. } //end of the function FindField
  62. //===========================================================================
  63. //
  64. // Parameter: -
  65. // Returns: -
  66. // Changes Globals: -
  67. //===========================================================================
  68. qboolean ReadNumber( source_t *source, fielddef_t *fd, void *p ) {
  69. token_t token;
  70. int negative = qfalse;
  71. long int intval, intmin = 0, intmax = 0;
  72. double floatval;
  73. if ( !PC_ExpectAnyToken( source, &token ) ) {
  74. return 0;
  75. }
  76. //check for minus sign
  77. if ( token.type == TT_PUNCTUATION ) {
  78. if ( fd->type & FT_UNSIGNED ) {
  79. SourceError( source, "expected unsigned value, found %s", token.string );
  80. return 0;
  81. } //end if
  82. //if not a minus sign
  83. if ( strcmp( token.string, "-" ) ) {
  84. SourceError( source, "unexpected punctuation %s", token.string );
  85. return 0;
  86. } //end if
  87. negative = qtrue;
  88. //read the number
  89. if ( !PC_ExpectAnyToken( source, &token ) ) {
  90. return 0;
  91. }
  92. } //end if
  93. //check if it is a number
  94. if ( token.type != TT_NUMBER ) {
  95. SourceError( source, "expected number, found %s", token.string );
  96. return 0;
  97. } //end if
  98. //check for a float value
  99. if ( token.subtype & TT_FLOAT ) {
  100. if ( ( fd->type & FT_TYPE ) != FT_FLOAT ) {
  101. SourceError( source, "unexpected float" );
  102. return 0;
  103. } //end if
  104. floatval = token.floatvalue;
  105. if ( negative ) {
  106. floatval = -floatval;
  107. }
  108. if ( fd->type & FT_BOUNDED ) {
  109. if ( floatval < fd->floatmin || floatval > fd->floatmax ) {
  110. SourceError( source, "float out of range [%f, %f]", fd->floatmin, fd->floatmax );
  111. return 0;
  112. } //end if
  113. } //end if
  114. *(float *) p = (float) floatval;
  115. return 1;
  116. } //end if
  117. //
  118. intval = token.intvalue;
  119. if ( negative ) {
  120. intval = -intval;
  121. }
  122. //check bounds
  123. if ( ( fd->type & FT_TYPE ) == FT_CHAR ) {
  124. if ( fd->type & FT_UNSIGNED ) {
  125. intmin = 0; intmax = 255;
  126. } else {intmin = -128; intmax = 127;}
  127. } //end if
  128. if ( ( fd->type & FT_TYPE ) == FT_INT ) {
  129. if ( fd->type & FT_UNSIGNED ) {
  130. intmin = 0; intmax = 65535;
  131. } else {intmin = -32768; intmax = 32767;}
  132. } //end else if
  133. if ( ( fd->type & FT_TYPE ) == FT_CHAR || ( fd->type & FT_TYPE ) == FT_INT ) {
  134. if ( fd->type & FT_BOUNDED ) {
  135. intmin = Maximum( intmin, fd->floatmin );
  136. intmax = Minimum( intmax, fd->floatmax );
  137. } //end if
  138. if ( intval < intmin || intval > intmax ) {
  139. SourceError( source, "value %d out of range [%d, %d]", intval, intmin, intmax );
  140. return 0;
  141. } //end if
  142. } //end if
  143. else if ( ( fd->type & FT_TYPE ) == FT_FLOAT ) {
  144. if ( fd->type & FT_BOUNDED ) {
  145. if ( intval < fd->floatmin || intval > fd->floatmax ) {
  146. SourceError( source, "value %d out of range [%f, %f]", intval, fd->floatmin, fd->floatmax );
  147. return 0;
  148. } //end if
  149. } //end if
  150. } //end else if
  151. //store the value
  152. if ( ( fd->type & FT_TYPE ) == FT_CHAR ) {
  153. if ( fd->type & FT_UNSIGNED ) {
  154. *(unsigned char *) p = (unsigned char) intval;
  155. } else { *(char *) p = (char) intval;}
  156. } //end if
  157. else if ( ( fd->type & FT_TYPE ) == FT_INT ) {
  158. if ( fd->type & FT_UNSIGNED ) {
  159. *(unsigned int *) p = (unsigned int) intval;
  160. } else { *(int *) p = (int) intval;}
  161. } //end else
  162. else if ( ( fd->type & FT_TYPE ) == FT_FLOAT ) {
  163. *(float *) p = (float) intval;
  164. } //end else
  165. return 1;
  166. } //end of the function ReadNumber
  167. //===========================================================================
  168. //
  169. // Parameter: -
  170. // Returns: -
  171. // Changes Globals: -
  172. //===========================================================================
  173. qboolean ReadChar( source_t *source, fielddef_t *fd, void *p ) {
  174. token_t token;
  175. if ( !PC_ExpectAnyToken( source, &token ) ) {
  176. return 0;
  177. }
  178. //take literals into account
  179. if ( token.type == TT_LITERAL ) {
  180. StripSingleQuotes( token.string );
  181. *(char *) p = token.string[0];
  182. } //end if
  183. else
  184. {
  185. PC_UnreadLastToken( source );
  186. if ( !ReadNumber( source, fd, p ) ) {
  187. return 0;
  188. }
  189. } //end if
  190. return 1;
  191. } //end of the function ReadChar
  192. //===========================================================================
  193. //
  194. // Parameter: -
  195. // Returns: -
  196. // Changes Globals: -
  197. //===========================================================================
  198. int ReadString( source_t *source, fielddef_t *fd, void *p ) {
  199. token_t token;
  200. if ( !PC_ExpectTokenType( source, TT_STRING, 0, &token ) ) {
  201. return 0;
  202. }
  203. //remove the double quotes
  204. StripDoubleQuotes( token.string );
  205. //copy the string
  206. strncpy( (char *) p, token.string, MAX_STRINGFIELD );
  207. //make sure the string is closed with a zero
  208. ( (char *)p )[MAX_STRINGFIELD - 1] = '\0';
  209. //
  210. return 1;
  211. } //end of the function ReadString
  212. //===========================================================================
  213. //
  214. // Parameter: -
  215. // Returns: -
  216. // Changes Globals: -
  217. //===========================================================================
  218. int ReadStructure( source_t *source, structdef_t *def, char *structure ) {
  219. token_t token;
  220. fielddef_t *fd;
  221. void *p;
  222. int num;
  223. if ( !PC_ExpectTokenString( source, "{" ) ) {
  224. return 0;
  225. }
  226. while ( 1 )
  227. {
  228. if ( !PC_ExpectAnyToken( source, &token ) ) {
  229. return qfalse;
  230. }
  231. //if end of structure
  232. if ( !strcmp( token.string, "}" ) ) {
  233. break;
  234. }
  235. //find the field with the name
  236. fd = FindField( def->fields, token.string );
  237. if ( !fd ) {
  238. SourceError( source, "unknown structure field %s", token.string );
  239. return qfalse;
  240. } //end if
  241. if ( fd->type & FT_ARRAY ) {
  242. num = fd->maxarray;
  243. if ( !PC_ExpectTokenString( source, "{" ) ) {
  244. return qfalse;
  245. }
  246. } //end if
  247. else
  248. {
  249. num = 1;
  250. } //end else
  251. p = ( void * )( structure + fd->offset );
  252. while ( num-- > 0 )
  253. {
  254. if ( fd->type & FT_ARRAY ) {
  255. if ( PC_CheckTokenString( source, "}" ) ) {
  256. break;
  257. }
  258. } //end if
  259. switch ( fd->type & FT_TYPE )
  260. {
  261. case FT_CHAR:
  262. {
  263. if ( !ReadChar( source, fd, p ) ) {
  264. return qfalse;
  265. }
  266. p = (char *) p + sizeof( char );
  267. break;
  268. } //end case
  269. case FT_INT:
  270. {
  271. if ( !ReadNumber( source, fd, p ) ) {
  272. return qfalse;
  273. }
  274. p = (char *) p + sizeof( int );
  275. break;
  276. } //end case
  277. case FT_FLOAT:
  278. {
  279. if ( !ReadNumber( source, fd, p ) ) {
  280. return qfalse;
  281. }
  282. p = (char *) p + sizeof( float );
  283. break;
  284. } //end case
  285. case FT_STRING:
  286. {
  287. if ( !ReadString( source, fd, p ) ) {
  288. return qfalse;
  289. }
  290. p = (char *) p + MAX_STRINGFIELD;
  291. break;
  292. } //end case
  293. case FT_STRUCT:
  294. {
  295. if ( !fd->substruct ) {
  296. SourceError( source, "BUG: no sub structure defined" );
  297. return qfalse;
  298. } //end if
  299. ReadStructure( source, fd->substruct, (char *) p );
  300. p = (char *) p + fd->substruct->size;
  301. break;
  302. } //end case
  303. } //end switch
  304. if ( fd->type & FT_ARRAY ) {
  305. if ( !PC_ExpectAnyToken( source, &token ) ) {
  306. return qfalse;
  307. }
  308. if ( !strcmp( token.string, "}" ) ) {
  309. break;
  310. }
  311. if ( strcmp( token.string, "," ) ) {
  312. SourceError( source, "expected a comma, found %s", token.string );
  313. return qfalse;
  314. } //end if
  315. } //end if
  316. } //end while
  317. } //end while
  318. return qtrue;
  319. } //end of the function ReadStructure
  320. //===========================================================================
  321. //
  322. // Parameter: -
  323. // Returns: -
  324. // Changes Globals: -
  325. //===========================================================================
  326. int WriteIndent( FILE *fp, int indent ) {
  327. while ( indent-- > 0 )
  328. {
  329. if ( fprintf( fp, "\t" ) < 0 ) {
  330. return qfalse;
  331. }
  332. } //end while
  333. return qtrue;
  334. } //end of the function WriteIndent
  335. //===========================================================================
  336. //
  337. // Parameter: -
  338. // Returns: -
  339. // Changes Globals: -
  340. //===========================================================================
  341. int WriteFloat( FILE *fp, float value ) {
  342. char buf[128];
  343. int l;
  344. sprintf( buf, "%f", value );
  345. l = strlen( buf );
  346. //strip any trailing zeros
  347. while ( l-- > 1 )
  348. {
  349. if ( buf[l] != '0' && buf[l] != '.' ) {
  350. break;
  351. }
  352. if ( buf[l] == '.' ) {
  353. buf[l] = 0;
  354. break;
  355. } //end if
  356. buf[l] = 0;
  357. } //end while
  358. //write the float to file
  359. if ( fprintf( fp, "%s", buf ) < 0 ) {
  360. return 0;
  361. }
  362. return 1;
  363. } //end of the function WriteFloat
  364. //===========================================================================
  365. //
  366. // Parameter: -
  367. // Returns: -
  368. // Changes Globals: -
  369. //===========================================================================
  370. int WriteStructWithIndent( FILE *fp, structdef_t *def, char *structure, int indent ) {
  371. int i, num;
  372. void *p;
  373. fielddef_t *fd;
  374. if ( !WriteIndent( fp, indent ) ) {
  375. return qfalse;
  376. }
  377. if ( fprintf( fp, "{\r\n" ) < 0 ) {
  378. return qfalse;
  379. }
  380. indent++;
  381. for ( i = 0; def->fields[i].name; i++ )
  382. {
  383. fd = &def->fields[i];
  384. if ( !WriteIndent( fp, indent ) ) {
  385. return qfalse;
  386. }
  387. if ( fprintf( fp, "%s\t", fd->name ) < 0 ) {
  388. return qfalse;
  389. }
  390. p = ( void * )( structure + fd->offset );
  391. if ( fd->type & FT_ARRAY ) {
  392. num = fd->maxarray;
  393. if ( fprintf( fp, "{" ) < 0 ) {
  394. return qfalse;
  395. }
  396. } //end if
  397. else
  398. {
  399. num = 1;
  400. } //end else
  401. while ( num-- > 0 )
  402. {
  403. switch ( fd->type & FT_TYPE )
  404. {
  405. case FT_CHAR:
  406. {
  407. if ( fprintf( fp, "%d", *(char *) p ) < 0 ) {
  408. return qfalse;
  409. }
  410. p = (char *) p + sizeof( char );
  411. break;
  412. } //end case
  413. case FT_INT:
  414. {
  415. if ( fprintf( fp, "%d", *(int *) p ) < 0 ) {
  416. return qfalse;
  417. }
  418. p = (char *) p + sizeof( int );
  419. break;
  420. } //end case
  421. case FT_FLOAT:
  422. {
  423. if ( !WriteFloat( fp, *(float *)p ) ) {
  424. return qfalse;
  425. }
  426. p = (char *) p + sizeof( float );
  427. break;
  428. } //end case
  429. case FT_STRING:
  430. {
  431. if ( fprintf( fp, "\"%s\"", (char *) p ) < 0 ) {
  432. return qfalse;
  433. }
  434. p = (char *) p + MAX_STRINGFIELD;
  435. break;
  436. } //end case
  437. case FT_STRUCT:
  438. {
  439. if ( !WriteStructWithIndent( fp, fd->substruct, structure, indent ) ) {
  440. return qfalse;
  441. }
  442. p = (char *) p + fd->substruct->size;
  443. break;
  444. } //end case
  445. } //end switch
  446. if ( fd->type & FT_ARRAY ) {
  447. if ( num > 0 ) {
  448. if ( fprintf( fp, "," ) < 0 ) {
  449. return qfalse;
  450. }
  451. } //end if
  452. else
  453. {
  454. if ( fprintf( fp, "}" ) < 0 ) {
  455. return qfalse;
  456. }
  457. } //end else
  458. } //end if
  459. } //end while
  460. if ( fprintf( fp, "\r\n" ) < 0 ) {
  461. return qfalse;
  462. }
  463. } //end for
  464. indent--;
  465. if ( !WriteIndent( fp, indent ) ) {
  466. return qfalse;
  467. }
  468. if ( fprintf( fp, "}\r\n" ) < 0 ) {
  469. return qfalse;
  470. }
  471. return qtrue;
  472. } //end of the function WriteStructWithIndent
  473. //===========================================================================
  474. //
  475. // Parameter: -
  476. // Returns: -
  477. // Changes Globals: -
  478. //===========================================================================
  479. int WriteStructure( FILE *fp, structdef_t *def, char *structure ) {
  480. return WriteStructWithIndent( fp, def, structure, 0 );
  481. } //end of the function WriteStructure