1 #include "qcc.h"
2 #include "hash.h"
3
4 char destfile[1024];
5
6 float pr_globals[MAX_REGS];
7 int numpr_globals;
8
9 char strings[MAX_STRINGS];
10 int strofs;
11
12 dstatement_t statements[MAX_STATEMENTS];
13 int numstatements;
14 int statement_linenums[MAX_STATEMENTS];
15
16 dfunction_t functions[MAX_FUNCTIONS];
17 int numfunctions;
18
19 ddef_t globals[MAX_GLOBALS];
20 int numglobaldefs;
21
22 ddef_t fields[MAX_FIELDS];
23 int numfielddefs;
24
25 char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH];
26 int precache_sounds_block[MAX_SOUNDS];
27 int numsounds;
28
29 char precache_models[MAX_MODELS][MAX_DATA_PATH];
30 int precache_models_block[MAX_SOUNDS];
31 int nummodels;
32
33 char precache_files[MAX_FILES][MAX_DATA_PATH];
34 int precache_files_block[MAX_SOUNDS];
35 int numfiles;
36
37 int pr_optimize_eliminate_temps;
38 int pr_optimize_shorten_ifs;
39 int pr_optimize_nonvec_parms;
40 int pr_optimize_constant_names;
41 int pr_optimize_defs;
42 int pr_optimize_hash_strings;
43
44 int num_constant_names;
45 int num_temps_removed;
46 int num_stores_shortened;
47 int num_ifs_shortened;
48 int num_nonvec_parms;
49 int num_defs;
50 int num_strings;
51
52 /*
53 =================
54 BspModels
55
56 Runs qbsp and light on all of the models with a .bsp extension
57 =================
58 */
BspModels(void)59 void BspModels (void)
60 {
61 int p;
62 char *gamedir;
63 int i;
64 char *m;
65 char cmd[1024];
66 char name[256];
67
68 p = CheckParm ("-bspmodels");
69 if (!p)
70 return;
71 if (p == myargc-1)
72 Error ("-bspmodels must preceed a game directory");
73 gamedir = myargv[p+1];
74
75 for (i=0 ; i<nummodels ; i++)
76 {
77 m = precache_models[i];
78 if (strcmp(m+strlen(m)-4, ".bsp"))
79 continue;
80 strcpy (name, m);
81 name[strlen(m)-4] = 0;
82 sprintf (cmd, "qbsp %s/%s ; light -extra %s/%s", gamedir, name, gamedir, name);
83 system (cmd);
84 }
85 }
86
87 // CopyString returns an offset from the string heap
CopyString(char * str,int len)88 int CopyString (char *str, int len)
89 {
90 int old;
91 def_t *cn = NULL;
92 struct hash_element *cell = NULL;
93 int allocate;
94 int index;
95
96 allocate = 0;
97 if (!len)
98 {
99 // this is not a string immediate (it's a filename/variable name/function name)
100 len = strlen(str)+1;
101 if (pr_optimize_hash_strings)
102 {
103 allocate = 1;
104 index = hash(str);
105
106 for (cell = htable[index]; cell != NULL; cell = cell->next)
107 {
108 cn = cell->def;
109 if (cn->type)
110 continue;
111 if (!strcmp(strings+cn->ofs, str))
112 {
113 num_strings += len;
114 //printf("found %s\n", str);
115 return cn->ofs;
116 }
117 }
118 }
119 }
120 old = strofs;
121 memcpy (strings+strofs, str, len);
122 strofs += len;
123
124 if (allocate)
125 {
126 def_t *def = (struct def_s *) malloc (sizeof(def_t));
127 def->ofs = old;
128 def->type = NULL; // hack used to indicate def allocated here
129 def->initialized = 0;
130 def->name = "";
131 def->scope = NULL;
132 cell = (struct hash_element *) malloc (sizeof(struct hash_element));
133 cell->next = htable[index];
134 cell->def = def;
135 htable[index] = cell;
136 stats[index]++;
137 }
138 return old;
139 }
140
PrintStrings(void)141 void PrintStrings (void)
142 {
143 int i, l, j;
144
145 for (i=0 ; i<strofs ; i += l)
146 {
147 l = strlen(strings+i) + 1;
148 printf ("%5i : ",i);
149 for (j=0 ; j<l ; j++)
150 {
151 if (strings[i+j] == '\n')
152 {
153 putchar ('\\');
154 putchar ('n');
155 }
156 else
157 putchar (strings[i+j]);
158 }
159 printf ("\n");
160 }
161 }
162
163
PrintFunctions(void)164 void PrintFunctions (void)
165 {
166 int i,j;
167 dfunction_t *d;
168
169 for (i=0 ; i<numfunctions ; i++)
170 {
171 d = &functions[i];
172 printf ("%s : %s : %i %i (", strings + d->s_file, strings + d->s_name, d->first_statement, d->parm_start);
173 for (j=0 ; j<d->numparms ; j++)
174 printf ("%i ",d->parm_size[j]);
175 printf (")\n");
176 }
177 }
178
PrintFields(void)179 void PrintFields (void)
180 {
181 int i;
182 ddef_t *d;
183
184 for (i=0 ; i<numfielddefs ; i++)
185 {
186 d = &fields[i];
187 printf ("%5i : (%i) %s\n", d->ofs, d->type, strings + d->s_name);
188 }
189 }
190
PrintGlobals(void)191 void PrintGlobals (void)
192 {
193 int i;
194 ddef_t *d;
195
196 for (i=0 ; i<numglobaldefs ; i++)
197 {
198 d = &globals[i];
199 printf ("%5i : (%i) %s\n", d->ofs, d->type, strings + d->s_name);
200 }
201 }
202
203
InitData(void)204 void InitData (void)
205 {
206 int i;
207
208 numstatements = 1;
209 strofs = 1;
210 numfunctions = 1;
211 numglobaldefs = 1;
212 numfielddefs = 1;
213
214 def_ret.ofs = OFS_RETURN;
215 for (i=0 ; i<MAX_PARMS ; i++)
216 def_parms[i].ofs = OFS_PARM0 + 3*i;
217 }
218
219
WriteData(int crc)220 void WriteData (int crc)
221 {
222 def_t *def;
223 ddef_t *dd;
224 dprograms_t progs;
225 int h;
226 int i;
227 int size;
228
229
230 for (def = pr.def_head.next ; def ; def = def->next)
231 {
232 if (def->type->type == ev_field)
233 {
234 dd = &fields[numfielddefs];
235 numfielddefs++;
236 dd->type = def->type->aux_type->type;
237 dd->s_name = CopyString (def->name);
238 dd->ofs = G_INT(def->ofs);
239 }
240 else if (pr_optimize_constant_names && def->initialized && (def->type->type != ev_function))
241 {
242 num_constant_names += strlen(def->name) + 1;
243 num_constant_names += sizeof(ddef_t);
244 continue;
245 }
246 dd = &globals[numglobaldefs];
247 dd->type = def->type->type;
248 if ( !def->initialized && def->type->type != ev_function && def->type->type != ev_field && def->scope == NULL)
249 dd->type |= DEF_SAVEGLOBGAL;
250 dd->s_name = CopyString (def->name);
251 dd->ofs = def->ofs;
252 numglobaldefs++;
253 }
254
255 strofs = (strofs+3)&~3;
256
257 printf ("%6i strofs (%6i)\n", strofs, strofs);
258 printf ("%6i numstatements (%6i)\n", numstatements, numstatements * sizeof(dstatement_t));
259 printf ("%6i numfunctions (%6i)\n", numfunctions, numfunctions * sizeof(dfunction_t));
260 printf ("%6i numglobaldefs (%6i)\n", numglobaldefs, numglobaldefs * sizeof(ddef_t));
261 printf ("%6i numfielddefs (%6i)\n", numfielddefs, numfielddefs * sizeof(ddef_t));
262 printf ("%6i numpr_globals (%6i)\n", numpr_globals, numpr_globals * 4);
263
264 h = SafeOpenWrite (destfile);
265 SafeWrite (h, &progs, sizeof(progs));
266
267 progs.ofs_strings = lseek (h, 0, SEEK_CUR);
268 progs.numstrings = strofs;
269 SafeWrite (h, strings, strofs);
270
271 progs.ofs_statements = lseek (h, 0, SEEK_CUR);
272 progs.numstatements = numstatements;
273 for (i=0 ; i<numstatements ; i++)
274 {
275 statements[i].op = LittleShort(statements[i].op);
276 statements[i].a = LittleShort(statements[i].a);
277 statements[i].b = LittleShort(statements[i].b);
278 statements[i].c = LittleShort(statements[i].c);
279 }
280 SafeWrite (h, statements, numstatements*sizeof(dstatement_t));
281
282 progs.ofs_functions = lseek (h, 0, SEEK_CUR);
283 progs.numfunctions = numfunctions;
284 for (i=0 ; i<numfunctions ; i++)
285 {
286 functions[i].first_statement = LittleLong (functions[i].first_statement);
287 functions[i].parm_start = LittleLong (functions[i].parm_start);
288 functions[i].s_name = LittleLong (functions[i].s_name);
289 functions[i].s_file = LittleLong (functions[i].s_file);
290 functions[i].numparms = LittleLong (functions[i].numparms);
291 functions[i].locals = LittleLong (functions[i].locals);
292 }
293 SafeWrite (h, functions, numfunctions*sizeof(dfunction_t));
294
295 progs.ofs_globaldefs = lseek (h, 0, SEEK_CUR);
296 progs.numglobaldefs = numglobaldefs;
297 for (i=0 ; i<numglobaldefs ; i++)
298 {
299 globals[i].type = LittleShort (globals[i].type);
300 globals[i].ofs = LittleShort (globals[i].ofs);
301 globals[i].s_name = LittleLong (globals[i].s_name);
302 }
303 SafeWrite (h, globals, numglobaldefs*sizeof(ddef_t));
304
305 progs.ofs_fielddefs = lseek (h, 0, SEEK_CUR);
306 progs.numfielddefs = numfielddefs;
307 for (i=0 ; i<numfielddefs ; i++)
308 {
309 fields[i].type = LittleShort (fields[i].type);
310 fields[i].ofs = LittleShort (fields[i].ofs);
311 fields[i].s_name = LittleLong (fields[i].s_name);
312 }
313 SafeWrite (h, fields, numfielddefs*sizeof(ddef_t));
314
315 progs.ofs_globals = lseek (h, 0, SEEK_CUR);
316 progs.numglobals = numpr_globals;
317 for (i=0 ; i<numpr_globals ; i++)
318 ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
319 SafeWrite (h, pr_globals, numpr_globals*4);
320
321 i = (int)lseek(h, 0, SEEK_CUR);
322 size = (i+16)&(~15);
323 printf ("%6i TOTAL SIZE (-> %6i)\n", i, size);
324
325 progs.entityfields = pr.size_fields;
326
327 progs.version = PROG_VERSION;
328 progs.crc = crc;
329 printf("crc = %d\n", crc);
330
331 // byte swap the header and write it out
332 for (i=0 ; i<sizeof(progs)/4 ; i++)
333 ((int *)&progs)[i] = LittleLong ( ((int *)&progs)[i] );
334 lseek (h, 0, SEEK_SET);
335 SafeWrite (h, &progs, sizeof(progs));
336
337 // look for progs
338 if (def = PR_GetDef(&type_entity, "progs", NULL, false))
339 {
340 lseek(h, progs.ofs_globals + 4 * def->ofs, SEEK_SET);
341 i = - (size + 112);
342 SafeWrite (h, &i, 4);
343 }
344
345 close (h);
346 }
347
348
349
350 /*
351 ===============
352 PR_String
353
354 Returns a string suitable for printing (no newlines, max 60 chars length)
355 ===============
356 */
PR_String(char * string)357 char *PR_String (char *string)
358 {
359 static char buf[80];
360 char *s;
361
362 s = buf;
363 *s++ = '"';
364 while (string && *string)
365 {
366 if (s == buf + sizeof(buf) - 2)
367 break;
368 if (*string == '\n')
369 {
370 *s++ = '\\';
371 *s++ = 'n';
372 }
373 else if (*string == '"')
374 {
375 *s++ = '\\';
376 *s++ = '"';
377 }
378 else
379 *s++ = *string;
380 string++;
381 if (s - buf > 60)
382 {
383 *s++ = '.';
384 *s++ = '.';
385 *s++ = '.';
386 break;
387 }
388 }
389 *s++ = '"';
390 *s++ = 0;
391 return buf;
392 }
393
394
395
PR_DefForFieldOfs(gofs_t ofs)396 def_t *PR_DefForFieldOfs (gofs_t ofs)
397 {
398 def_t *d;
399
400 for (d=pr.def_head.next ; d ; d=d->next)
401 {
402 if (d->type->type != ev_field)
403 continue;
404 if (*((int *)&pr_globals[d->ofs]) == ofs)
405 return d;
406 }
407 Error ("PR_DefForFieldOfs: couldn't find %i",ofs);
408 return NULL;
409 }
410
411 /*
412 ============
413 PR_ValueString
414
415 Returns a string describing *data in a type specific manner
416 =============
417 */
PR_ValueString(etype_t type,void * val)418 char *PR_ValueString (etype_t type, void *val)
419 {
420 static char line[256];
421 def_t *def;
422 dfunction_t *f;
423
424 switch (type)
425 {
426 case ev_string:
427 sprintf (line, "%s", PR_String(strings + *(int *)val));
428 break;
429 case ev_entity:
430 sprintf (line, "entity %i", *(int *)val);
431 break;
432 case ev_function:
433 f = functions + *(int *)val;
434 if (!f)
435 sprintf (line, "undefined function");
436 else
437 sprintf (line, "%s()", strings + f->s_name);
438 break;
439 case ev_field:
440 def = PR_DefForFieldOfs ( *(int *)val );
441 sprintf (line, ".%s", def->name);
442 break;
443 case ev_void:
444 sprintf (line, "void");
445 break;
446 case ev_float:
447 {
448 unsigned int high = *(unsigned int*)val & 0xff000000;
449 if (high == 0xff000000 || !high)
450 sprintf (line, "%%%d", *(int*)val);
451 else
452 sprintf (line, "%5.1f", *(float *)val);
453 }
454 break;
455 case ev_vector:
456 sprintf (line, "'%5.1f %5.1f %5.1f'", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]);
457 break;
458 case ev_pointer:
459 sprintf (line, "pointer");
460 break;
461 default:
462 sprintf (line, "bad type %i", type);
463 break;
464 }
465
466 return line;
467 }
468
469 /*
470 ============
471 PR_GlobalString
472
473 Returns a string with a description and the contents of a global,
474 padded to 20 field width
475 ============
476 */
PR_GlobalStringNoContents(gofs_t ofs)477 char *PR_GlobalStringNoContents (gofs_t ofs)
478 {
479 int i;
480 def_t *def;
481 void *val;
482 static char line[128];
483
484 val = (void *)&pr_globals[ofs];
485 def = pr_global_defs[ofs];
486 if (!def)
487 sprintf (line,"%i(?\?\?)", ofs);
488 else
489 sprintf (line,"%i(%s)", ofs, def->name);
490
491 i = strlen(line);
492 for ( ; i<16 ; i++)
493 strcat (line," ");
494 strcat (line," ");
495
496 return line;
497 }
498
PR_GlobalString(gofs_t ofs)499 char *PR_GlobalString (gofs_t ofs)
500 {
501 char *s;
502 int i;
503 def_t *def;
504 void *val;
505 static char line[128];
506
507 val = (void *)&pr_globals[ofs];
508 def = pr_global_defs[ofs];
509 if (!def)
510 return PR_GlobalStringNoContents(ofs);
511 if (def->initialized && def->type->type != ev_function)
512 {
513 s = PR_ValueString (def->type->type, &pr_globals[ofs]);
514 sprintf (line,"%i(%s)", ofs, s);
515 }
516 else
517 sprintf (line,"%i(%s)", ofs, def->name);
518
519 i = strlen(line);
520 for ( ; i<16 ; i++)
521 strcat (line," ");
522 strcat (line," ");
523
524 return line;
525 }
526
527 /*
528 ============
529 PR_PrintOfs
530 ============
531 */
PR_PrintOfs(gofs_t ofs)532 void PR_PrintOfs (gofs_t ofs)
533 {
534 printf ("%s\n",PR_GlobalString(ofs));
535 }
536
537 /*
538 =================
539 PR_PrintStatement
540 =================
541 */
PR_PrintStatement(dstatement_t * s)542 void PR_PrintStatement (dstatement_t *s)
543 {
544 int i;
545 int opindex;
546
547 for (opindex = 0 ; pr_opcodes[opindex].op != s->op ; opindex++);
548
549 printf ("%4i : %4i : %s ", (int)(s - statements), statement_linenums[s-statements], pr_opcodes[opindex].opname);
550 i = strlen(pr_opcodes[opindex].opname);
551 for ( ; i<10 ; i++)
552 printf (" ");
553
554 if (opindex == OP_IF || opindex == OP_IFNOT)
555 printf ("%sbranch %i",PR_GlobalString(s->a),s->b);
556 else if (opindex == OP_GOTO)
557 {
558 printf ("branch %i",s->a);
559 }
560 else if ( (unsigned)(opindex - OP_STORE_F) < 6)
561 {
562 printf ("%s",PR_GlobalString(s->a));
563 printf ("%s", PR_GlobalStringNoContents(s->b));
564 }
565 else
566 {
567 if (s->a)
568 printf ("%s",PR_GlobalString(s->a));
569 if (s->b)
570 printf ("%s",PR_GlobalString(s->b));
571 if (s->c)
572 printf ("%s", PR_GlobalStringNoContents(s->c));
573 }
574 printf ("\n");
575 }
576
577
578 /*
579 ============
580 PR_PrintDefs
581 ============
582 */
PR_PrintDefs(void)583 void PR_PrintDefs (void)
584 {
585 def_t *d;
586
587 for (d=pr.def_head.next ; d ; d=d->next)
588 PR_PrintOfs (d->ofs);
589 }
590
591
592 /*
593 ==============
594 PR_BeginCompilation
595
596 called before compiling a batch of files, clears the pr struct
597 ==============
598 */
PR_BeginCompilation(void * memory,int memsize)599 void PR_BeginCompilation (void *memory, int memsize)
600 {
601 int i;
602
603 pr.memory = (char *) memory;
604 pr.max_memory = memsize;
605
606 numpr_globals = RESERVED_OFS;
607 pr.def_tail = &pr.def_head;
608
609 for (i=0 ; i<RESERVED_OFS ; i++)
610 pr_global_defs[i] = &def_void;
611
612 // link the function type in so state forward declarations match proper type
613 pr.types = &type_function;
614 type_function.next = NULL;
615 pr_error_count = 0;
616
617 num_temps_removed = 0;
618 num_stores_shortened = 0;
619 num_ifs_shortened = 0;
620 num_nonvec_parms = 0;
621 num_constant_names = 0;
622 num_defs = 0;
623 num_strings = 0;
624
625 // JPG - do this once at start; no need ot keep checking
626 inithash();
627 }
628
629 /*
630 ==============
631 PR_FinishCompilation
632
633 called after all files are compiled to check for errors
634 Returns false if errors were detected.
635 ==============
636 */
PR_FinishCompilation(void)637 boolean PR_FinishCompilation (void)
638 {
639 def_t *d;
640 boolean errors;
641
642 errors = false;
643
644 // check to make sure all functions prototyped have code
645 for (d=pr.def_head.next ; d ; d=d->next)
646 {
647 if (d->type->type == ev_function && !d->scope)// function parms are ok
648 {
649 if (!d->initialized)
650 {
651 printf ("function %s was not defined\n",d->name);
652 errors = true;
653 }
654 }
655 }
656
657 return !errors ? true : false;
658 }
659
660 //=============================================================================
661
662 // FIXME: byte swap?
663
664 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
665 // and the initial and final xor values shown below... in other words, the
666 // CCITT standard CRC used by XMODEM
667
668 #define CRC_INIT_VALUE 0xffff
669 #define CRC_XOR_VALUE 0x0000
670
671 static unsigned short crctable[256] =
672 {
673 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
674 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
675 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
676 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
677 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
678 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
679 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
680 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
681 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
682 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
683 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
684 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
685 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
686 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
687 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
688 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
689 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
690 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
691 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
692 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
693 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
694 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
695 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
696 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
697 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
698 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
699 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
700 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
701 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
702 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
703 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
704 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
705 };
706
CRC_Init(unsigned short * crcvalue)707 void CRC_Init(unsigned short *crcvalue)
708 {
709 *crcvalue = CRC_INIT_VALUE;
710 }
711
CRC_ProcessByte(unsigned short * crcvalue,byte data)712 void CRC_ProcessByte(unsigned short *crcvalue, byte data)
713 {
714 *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
715 }
716
CRC_Value(unsigned short crcvalue)717 unsigned short CRC_Value(unsigned short crcvalue)
718 {
719 return crcvalue ^ CRC_XOR_VALUE;
720 }
721 //=============================================================================
722
723 /*
724 ============
725 PR_WriteProgdefs
726
727 Writes the global and entity structures out
728 Returns a crc of the header, to be stored in the progs file for comparison
729 at load time.
730 ============
731 */
PR_WriteProgdefs(char * filename)732 int PR_WriteProgdefs (char *filename)
733 {
734 def_t *d;
735 FILE *f;
736 unsigned short crc;
737 int c;
738
739 printf ("writing %s\n", filename);
740 f = fopen (filename, "w");
741
742 // print global vars until the first field is defined
743 fprintf (f,"\n/* file generated by qcc, do not modify */\n\ntypedef struct\n{\tint\tpad[%i];\n", RESERVED_OFS);
744 for (d=pr.def_head.next ; d ; d=d->next)
745 {
746 if (!strcmp (d->name, "end_sys_globals"))
747 break;
748
749 switch (d->type->type)
750 {
751 case ev_float:
752 fprintf (f, "\tfloat\t%s;\n",d->name);
753 break;
754 case ev_vector:
755 fprintf (f, "\tvec3_t\t%s;\n",d->name);
756 d=d->next->next->next; // skip the elements
757 break;
758 case ev_string:
759 fprintf (f,"\tstring_t\t%s;\n",d->name);
760 break;
761 case ev_function:
762 fprintf (f,"\tfunc_t\t%s;\n",d->name);
763 break;
764 case ev_entity:
765 fprintf (f,"\tint\t%s;\n",d->name);
766 break;
767 default:
768 fprintf (f,"\tint\t%s;\n",d->name);
769 break;
770 }
771 }
772 fprintf (f,"} globalvars_t;\n\n");
773
774 // print all fields
775 fprintf (f,"typedef struct\n{\n");
776 for (d=pr.def_head.next ; d ; d=d->next)
777 {
778 if (!strcmp (d->name, "end_sys_fields"))
779 break;
780
781 if (d->type->type != ev_field)
782 continue;
783
784 switch (d->type->aux_type->type)
785 {
786 case ev_float:
787 fprintf (f,"\tfloat\t%s;\n",d->name);
788 break;
789 case ev_vector:
790 fprintf (f,"\tvec3_t\t%s;\n",d->name);
791 d=d->next->next->next; // skip the elements
792 break;
793 case ev_string:
794 fprintf (f,"\tstring_t\t%s;\n",d->name);
795 break;
796 case ev_function:
797 fprintf (f,"\tfunc_t\t%s;\n",d->name);
798 break;
799 case ev_entity:
800 fprintf (f,"\tint\t%s;\n",d->name);
801 break;
802 default:
803 fprintf (f,"\tint\t%s;\n",d->name);
804 break;
805 }
806 }
807 fprintf (f,"} entvars_t;\n\n");
808
809 fclose (f);
810
811 // do a crc of the file
812 CRC_Init (&crc);
813 f = fopen (filename, "r+");
814 while ((c = fgetc(f)) != EOF)
815 CRC_ProcessByte (&crc, c);
816
817 fprintf (f,"#define PROGHEADER_CRC %i\n", crc);
818 fclose (f);
819
820 return crc;
821 }
822
PrintFunction(char * name)823 void PrintFunction (char *name)
824 {
825 int i;
826 dstatement_t *ds;
827 dfunction_t *df;
828
829 for (i=0 ; i<numfunctions ; i++)
830 if (!strcmp (name, strings + functions[i].s_name))
831 break;
832 if (i==numfunctions)
833 Error ("No function names \"%s\"", name);
834 df = functions + i;
835
836 printf ("Statements for %s:\n", name);
837 ds = statements + df->first_statement;
838 while (1)
839 {
840 PR_PrintStatement (ds);
841 if (!ds->op)
842 break;
843 ds++;
844 }
845 }
846
847 /*
848 ==============================================================================
849
850 DIRECTORY COPYING / PACKFILE CREATION
851
852 ==============================================================================
853 */
854
855 typedef struct
856 {
857 char name[56];
858 int filepos, filelen;
859 } packfile_t;
860
861 typedef struct
862 {
863 char id[4];
864 int dirofs;
865 int dirlen;
866 } packheader_t;
867
868 packfile_t pfiles[4096], *pf;
869 int packhandle;
870 int packbytes;
871
Sys_mkdir(char * path)872 void Sys_mkdir (char *path)
873 {
874 #ifdef WIN32
875 if (mkdir (path) != -1)
876 return;
877 #else
878 if (mkdir (path, 0777) != -1)
879 return;
880 #endif
881 if (errno != EEXIST)
882 Error ("mkdir %s: %s",path, strerror(errno));
883 }
884
885 /*
886 ============
887 CreatePath
888 ============
889 */
CreatePath(char * path)890 void CreatePath (char *path)
891 {
892 char *ofs;
893
894 for (ofs = path+1 ; *ofs ; ofs++)
895 {
896 if (*ofs == '/')
897 { // create the directory
898 *ofs = 0;
899 Sys_mkdir (path);
900 *ofs = '/';
901 }
902 }
903 }
904
905
906 /*
907 ===========
908 PackFile
909
910 Copy a file into the pak file
911 ===========
912 */
PackFile(char * src,char * name)913 void PackFile (char *src, char *name)
914 {
915 int in;
916 int remaining, count;
917 char buf[4096];
918
919 if ( (byte *)pf - (byte *)pfiles > sizeof(pfiles) )
920 Error ("Too many files in pak file");
921
922 in = SafeOpenRead (src);
923 remaining = filelength (in);
924
925 pf->filepos = LittleLong (lseek (packhandle, 0, SEEK_CUR));
926 pf->filelen = LittleLong (remaining);
927 strcpy (pf->name, name);
928 printf ("%64s : %7i\n", pf->name, remaining);
929
930 packbytes += remaining;
931
932 while (remaining)
933 {
934 if (remaining < sizeof(buf))
935 count = remaining;
936 else
937 count = sizeof(buf);
938 SafeRead (in, buf, count);
939 SafeWrite (packhandle, buf, count);
940 remaining -= count;
941 }
942
943 close (in);
944 pf++;
945 }
946
947
948 /*
949 ===========
950 CopyFile
951
952 Copies a file, creating any directories needed
953 ===========
954 */
CopyFile(char * src,char * dest)955 void CopyFile (char *src, char *dest)
956 {
957 int in, out;
958 int remaining, count;
959 char buf[4096];
960
961 printf ("%s to %s\n", src, dest);
962
963 in = SafeOpenRead (src);
964 remaining = filelength (in);
965
966 CreatePath (dest);
967 out = SafeOpenWrite (dest);
968
969 while (remaining)
970 {
971 if (remaining < sizeof(buf))
972 count = remaining;
973 else
974 count = sizeof(buf);
975 SafeRead (in, buf, count);
976 SafeWrite (out, buf, count);
977 remaining -= count;
978 }
979
980 close (in);
981 close (out);
982 }
983
984
985 /*
986 ===========
987 CopyFiles
988 ===========
989 */
CopyFiles(void)990 void CopyFiles (void)
991 {
992 int i, p;
993 char srcdir[1024], destdir[1024];
994 char srcfile[1024], destfile[1024];
995 int copytype;
996 char name[1024];
997 packheader_t header;
998 int dirlen;
999 int blocknum;
1000 unsigned short crc;
1001
1002 printf ("%3i unique precache_sounds\n", numsounds);
1003 printf ("%3i unique precache_models\n", nummodels);
1004
1005 copytype = 0;
1006
1007 p = CheckParm ("-copy");
1008 if (p && p < myargc-2)
1009 { // create a new directory tree
1010 copytype = 1;
1011
1012 strcpy (srcdir, myargv[p+1]);
1013 strcpy (destdir, myargv[p+2]);
1014 if (srcdir[strlen(srcdir)-1] != '/')
1015 strcat (srcdir, "/");
1016 if (destdir[strlen(destdir)-1] != '/')
1017 strcat (destdir, "/");
1018 }
1019
1020 blocknum = 1;
1021 p = CheckParm ("-pak2");
1022 if (p && p <myargc-2)
1023 blocknum = 2;
1024 else
1025 p = CheckParm ("-pak");
1026 if (p && p < myargc-2)
1027 { // create a pak file
1028 strcpy (srcdir, myargv[p+1]);
1029 strcpy (destdir, myargv[p+2]);
1030 if (srcdir[strlen(srcdir)-1] != '/')
1031 strcat (srcdir, "/");
1032 DefaultExtension (destdir, ".pak");
1033
1034 pf = pfiles;
1035 packhandle = SafeOpenWrite (destdir);
1036 SafeWrite (packhandle, &header, sizeof(header));
1037 copytype = 2;
1038 }
1039
1040 if (!copytype)
1041 return;
1042
1043 for (i=0 ; i<numsounds ; i++)
1044 {
1045 if (precache_sounds_block[i] != blocknum)
1046 continue;
1047 sprintf (name, "sound/%s", precache_sounds[i]);
1048 sprintf (srcfile,"%s%s",srcdir, name);
1049 sprintf (destfile,"%s%s",destdir, name);
1050 if (copytype == 1)
1051 CopyFile (srcfile, destfile);
1052 else
1053 PackFile (srcfile, name);
1054 }
1055 for (i=0 ; i<nummodels ; i++)
1056 {
1057 if (precache_models_block[i] != blocknum)
1058 continue;
1059 sprintf (srcfile,"%s%s",srcdir, precache_models[i]);
1060 sprintf (destfile,"%s%s",destdir, precache_models[i]);
1061 if (copytype == 1)
1062 CopyFile (srcfile, destfile);
1063 else
1064 PackFile (srcfile, precache_models[i]);
1065 }
1066 for (i=0 ; i<numfiles ; i++)
1067 {
1068 if (precache_files_block[i] != blocknum)
1069 continue;
1070 sprintf (srcfile,"%s%s",srcdir, precache_files[i]);
1071 sprintf (destfile,"%s%s",destdir, precache_files[i]);
1072 if (copytype == 1)
1073 CopyFile (srcfile, destfile);
1074 else
1075 PackFile (srcfile, precache_files[i]);
1076 }
1077
1078 if (copytype == 2)
1079 {
1080 header.id[0] = 'P';
1081 header.id[1] = 'A';
1082 header.id[2] = 'C';
1083 header.id[3] = 'K';
1084 dirlen = (byte *)pf - (byte *)pfiles;
1085 header.dirofs = LittleLong(lseek (packhandle, 0, SEEK_CUR));
1086 header.dirlen = LittleLong(dirlen);
1087
1088 SafeWrite (packhandle, pfiles, dirlen);
1089
1090 lseek (packhandle, 0, SEEK_SET);
1091 SafeWrite (packhandle, &header, sizeof(header));
1092 close (packhandle);
1093
1094 // do a crc of the file
1095 CRC_Init (&crc);
1096 for (i=0 ; i<dirlen ; i++)
1097 CRC_ProcessByte (&crc, ((byte *)pfiles)[i]);
1098
1099 i = pf - pfiles;
1100 printf ("%i files packed in %i bytes (%i crc)\n",i, packbytes, crc);
1101 }
1102 }
1103
1104 //============================================================================
1105
1106 /*
1107 ============
1108 main
1109 ============
1110 */
main(int argc,char ** argv)1111 int main (int argc, char **argv)
1112 {
1113 char *src;
1114 char *src2;
1115 char filename[1024];
1116 int p, crc;
1117 char sourcedir[1024];
1118
1119 printf("qccx v1.0 by J.P. Grossman, based on fastqcc\n");
1120
1121 myargc = argc;
1122 myargv = argv;
1123
1124 if ( CheckParm ("-?") || CheckParm ("-help") || CheckParm ("-h") || CheckParm("/?"))
1125 {
1126 printf("qcc looks for progs.src in the current directory.\n");
1127 printf("to look in a different directory: qcc -src <directory>\n");
1128 printf("to build a clean data tree: qcc -copy <srcdir> <destdir>\n");
1129 printf("to build a clean pak file: qcc -pak <srcdir> <packfile>\n");
1130 printf("to bsp all bmodels: qcc -bspmodels <gamedir>\n\n");
1131 printf("Optimizations:\n");
1132 printf("\t/Ot\teliminate temps\n");
1133 printf("\t/Oi\tshorten ifs\n");
1134 printf("\t/Op\tnon-vector parms\n");
1135 printf("\t/Oc\teliminate constant defs/names\n");
1136 printf("\t/Od\teliminate duplicate defs\n");
1137 printf("\t/Os\thash lookup in CopyString\n");
1138 printf("\t/O2\tuse all optimizations\n");
1139 return (0);
1140 }
1141
1142 p = CheckParm ("-src");
1143 if (p && p < argc-1 )
1144 {
1145 strcpy (sourcedir, argv[p+1]);
1146 if (sourcedir[strlen(sourcedir)-1] != '/')
1147 strcat (sourcedir, "/");
1148 printf ("Source directory: %s\n", sourcedir);
1149 }
1150 else
1151 strcpy (sourcedir, "");
1152
1153 InitData ();
1154
1155 sprintf (filename, "%sprogs.src", sourcedir);
1156 LoadFile (filename, (void **)&src);
1157
1158 src = COM_Parse (src);
1159 if (!src)
1160 Error ("No destination filename. qcc -help for info.\n");
1161 strcpy (destfile, com_token);
1162 printf ("outputfile: %s\n", destfile);
1163
1164 pr_dumpasm = false;
1165
1166 pr_optimize_eliminate_temps = CheckParm("/Ot");
1167 pr_optimize_shorten_ifs = CheckParm("/Oi");
1168 pr_optimize_nonvec_parms = CheckParm("/Op");
1169 pr_optimize_constant_names = CheckParm("/Oc");
1170 pr_optimize_defs = CheckParm("/Od");
1171 pr_optimize_hash_strings = CheckParm("/Os");
1172 if (CheckParm("/O2"))
1173 pr_optimize_eliminate_temps = pr_optimize_shorten_ifs = pr_optimize_nonvec_parms = pr_optimize_constant_names = pr_optimize_defs = pr_optimize_hash_strings = 1;
1174
1175 if (pr_optimize_eliminate_temps || pr_optimize_shorten_ifs || pr_optimize_nonvec_parms || pr_optimize_constant_names || pr_optimize_defs || pr_optimize_hash_strings)
1176 {
1177 printf("Optimizations: ");
1178 if (pr_optimize_eliminate_temps)
1179 printf("temps ");
1180 if (pr_optimize_shorten_ifs)
1181 printf("ifs ");
1182 if (pr_optimize_nonvec_parms)
1183 printf("parms ");
1184 if (pr_optimize_constant_names)
1185 printf("const_defs ");
1186 if (pr_optimize_defs)
1187 printf("dup_defs ");
1188 if (pr_optimize_hash_strings)
1189 printf("hash_strings ");
1190 printf("\n");
1191 }
1192
1193 PR_BeginCompilation (malloc (0x100000), 0x100000);
1194
1195 // compile all the files
1196 do
1197 {
1198 src = COM_Parse(src);
1199 if (!src)
1200 break;
1201 sprintf (filename, "%s%s", sourcedir, com_token);
1202 printf ("compiling %s\n", filename);
1203 LoadFile (filename, (void **)&src2);
1204
1205 if (!PR_CompileFile (src2, filename) )
1206 exit (1);
1207
1208 } while (1);
1209
1210 if (!PR_FinishCompilation ())
1211 Error ("compilation errors");
1212
1213 p = CheckParm ("-asm");
1214 if (p)
1215 {
1216 for (p++ ; p<argc ; p++)
1217 {
1218 if (argv[p][0] == '-')
1219 break;
1220 PrintFunction (argv[p]);
1221 }
1222 }
1223
1224
1225 // write progdefs.h
1226 crc = PR_WriteProgdefs ("progdefs.h");
1227
1228 // write data file
1229 WriteData (crc);
1230
1231 // regenerate bmodels if -bspmodels
1232 BspModels ();
1233
1234 // report / copy the data files
1235 CopyFiles ();
1236
1237 int sum = 0;
1238 for (int i = 0 ; i < HSIZE1 ; i++)
1239 sum += stats[i] * stats[i];
1240 printf("sum = %d\n", sum);
1241
1242 if (pr_optimize_eliminate_temps)
1243 {
1244 printf("%d bytes of temporary storage eliminated\n", num_temps_removed * 4);
1245 printf("%d stores shortened\n", num_stores_shortened);
1246 }
1247 if (pr_optimize_shorten_ifs)
1248 printf("%d ifs shortened\n", num_ifs_shortened);
1249 if (pr_optimize_nonvec_parms)
1250 printf("%d non-vector parms\n", num_nonvec_parms);
1251 if (pr_optimize_constant_names)
1252 printf("%d bytes of constant defs/names eliminated\n", num_constant_names);
1253 if (pr_optimize_defs)
1254 printf("%d bytes of duplicate defs eliminated\n", num_defs);
1255 if (pr_optimize_hash_strings)
1256 printf("%d bytes of duplicate strings eliminated\n", num_strings);
1257 }
1258