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