1 /*
2 	idstuff.c
3 
4 	qcc compatable output stuff
5 
6 	Copyright (C) 2002 Bill Currie <bill@taniwha.org>
7 	Copyright (C) 1996-1997  Id Software, Inc.
8 
9 	Author: Bill Currie <bill@taniwha.org>
10 	Date: 2002/06/04
11 
12 	This program is free software; you can redistribute it and/or
13 	modify it under the terms of the GNU General Public License
14 	as published by the Free Software Foundation; either version 2
15 	of the License, or (at your option) any later version.
16 
17 	This program is distributed in the hope that it will be useful,
18 	but WITHOUT ANY WARRANTY; without even the implied warranty of
19 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 
21 	See the GNU General Public License for more details.
22 
23 	You should have received a copy of the GNU General Public License
24 	along with this program; if not, write to:
25 
26 		Free Software Foundation, Inc.
27 		59 Temple Place - Suite 330
28 		Boston, MA  02111-1307, USA
29 
30 */
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34 
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #endif
38 #ifdef HAVE_STRINGS_H
39 # include <strings.h>
40 #endif
41 
42 #include <QF/crc.h>
43 #include <QF/dstring.h>
44 #include <QF/quakeio.h>
45 
46 #include "def.h"
47 #include "defspace.h"
48 #include "diagnostic.h"
49 #include "qfcc.h"
50 #include "expr.h"
51 #include "idstuff.h"
52 #include "options.h"
53 #include "strpool.h"
54 #include "symtab.h"
55 #include "type.h"
56 
57 #define	MAX_SOUNDS		1024
58 #define	MAX_MODELS		1024
59 #define	MAX_FILES		1024
60 #define	MAX_DATA_PATH	64
61 
62 static char precache_sounds[MAX_SOUNDS][MAX_DATA_PATH];
63 static int  precache_sounds_block[MAX_SOUNDS];
64 static int  numsounds;
65 
66 static char precache_models[MAX_MODELS][MAX_DATA_PATH];
67 static int  precache_models_block[MAX_SOUNDS];
68 static int  nummodels;
69 
70 static char precache_files[MAX_FILES][MAX_DATA_PATH];
71 static int  precache_files_block[MAX_SOUNDS];
72 static int  numfiles;
73 
74 void
PrecacheSound(const char * n,int ch)75 PrecacheSound (const char *n, int ch)
76 {
77 	int         i;
78 
79 	for (i = 0; i < numsounds; i++) {
80 		if (!strcmp (n, precache_sounds[i])) {
81 			return;
82 		}
83 	}
84 
85 	if (numsounds == MAX_SOUNDS) {
86 		error (0, "PrecacheSound: numsounds == MAX_SOUNDS");
87 		return;
88 	}
89 
90 	strcpy (precache_sounds[i], n);
91 	if (ch >= '1' && ch <= '9')
92 		precache_sounds_block[i] = ch - '0';
93 	else
94 		precache_sounds_block[i] = 1;
95 
96 	numsounds++;
97 }
98 
99 void
PrecacheModel(const char * n,int ch)100 PrecacheModel (const char *n, int ch)
101 {
102 	int         i;
103 
104 	for (i = 0; i < nummodels; i++) {
105 		if (!strcmp (n, precache_models[i])) {
106 			return;
107 		}
108 	}
109 
110 	if (nummodels == MAX_MODELS) {
111 		error (0, "PrecacheModels: nummodels == MAX_MODELS");
112 		return;
113 	}
114 
115 	strcpy (precache_models[i], n);
116 	if (ch >= '1' && ch <= '9')
117 		precache_models_block[i] = ch - '0';
118 	else
119 		precache_models_block[i] = 1;
120 
121 	nummodels++;
122 }
123 
124 void
PrecacheFile(const char * n,int ch)125 PrecacheFile (const char *n, int ch)
126 {
127 	int         i;
128 
129 	for (i = 0; i < numfiles; i++) {
130 		if (!strcmp (n, precache_files[i])) {
131 			return;
132 		}
133 	}
134 
135 	if (numfiles == MAX_FILES) {
136 		error (0, "PrecacheFile: numfiles == MAX_FILES");
137 		return;
138 	}
139 
140 	strcpy (precache_files[i], n);
141 	if (ch >= '1' && ch <= '9')
142 		precache_files_block[i] = ch - '0';
143 	else
144 		precache_files_block[i] = 1;
145 
146 	numfiles++;
147 }
148 
149 /*
150 	WriteFiles
151 
152 	Generates files.dat, which contains all of the data files actually used by
153 	the game, to be processed by qfiles
154 */
155 int
WriteFiles(const char * sourcedir)156 WriteFiles (const char *sourcedir)
157 {
158 	FILE       *f;
159 	int         i;
160 	dstring_t  *filename = dstring_newstr ();
161 
162 	dsprintf (filename, "%s%cfiles.dat", sourcedir, PATH_SEPARATOR);
163 	f = fopen (filename->str, "wb");
164 	if (!f) {
165 		fprintf (stderr, "Couldn't open %s", filename->str);
166 		return 1;
167 	}
168 
169 	fprintf (f, "%i\n", numsounds);
170 	for (i = 0; i < numsounds; i++)
171 		fprintf (f, "%i %s\n", precache_sounds_block[i], precache_sounds[i]);
172 
173 	fprintf (f, "%i\n", nummodels);
174 	for (i = 0; i < nummodels; i++)
175 		fprintf (f, "%i %s\n", precache_models_block[i], precache_models[i]);
176 
177 	fprintf (f, "%i\n", numfiles);
178 	for (i = 0; i < numfiles; i++)
179 		fprintf (f, "%i %s\n", precache_files_block[i], precache_files[i]);
180 
181 	fclose (f);
182 	dstring_delete (filename);
183 	return 0;
184 }
185 
186 /*
187 	WriteProgdefs
188 
189 	Writes the global and entity structures out.
190 	Returns a crc of the header, to be stored in the progs file for comparison
191 	at load time.
192 */
193 int
WriteProgdefs(dprograms_t * progs,const char * filename)194 WriteProgdefs (dprograms_t *progs, const char *filename)
195 {
196 	ddef_t     *def;
197 	ddef_t     *fdef;
198 	dstring_t  *dstr;
199 	QFile      *f;
200 	unsigned short crc;
201 	unsigned    i, j;
202 	const char *strings;
203 	const char *name;
204 
205 	if (options.verbosity >= 1)
206 		printf ("Calculating CRC\n");
207 
208 	dstr = dstring_newstr();
209 
210 	// print global vars until the first field is defined
211 	dasprintf (dstr, "\n/* file generated by qcc, do not modify */"
212 					 "\n\ntypedef struct\n{\tint\tpad[%i];\n",
213 			 RESERVED_OFS);
214 
215 	strings = (char *) progs + progs->ofs_strings;
216 	for (i = 0; i < progs->numglobaldefs; i++) {
217 		def = (ddef_t *) ((char *) progs + progs->ofs_globaldefs) + i;
218 		name = strings + def->s_name;
219 		if (!strcmp (name, "end_sys_globals"))
220 			break;
221 		if (!def->ofs)
222 			continue;
223 		if (*name == '.' || !*name)
224 			continue;
225 
226 		switch (def->type & ~DEF_SAVEGLOBAL) {
227 			case ev_float:
228 				dasprintf (dstr, "\tfloat\t%s;\n", name);
229 				break;
230 			case ev_vector:
231 				dasprintf (dstr, "\tvec3_t\t%s;\n", name);
232 				break;
233 			case ev_quat:
234 				dasprintf (dstr, "\tquat_t\t%s;\n", name);
235 				break;
236 			case ev_string:
237 				dasprintf (dstr, "\tstring_t\t%s;\n", name);
238 				break;
239 			case ev_func:
240 				dasprintf (dstr, "\tfunc_t\t%s;\n", name);
241 				break;
242 			case ev_entity:
243 				dasprintf (dstr, "\tint\t%s;\n", name);
244 				break;
245 			default:
246 				dasprintf (dstr, "\tint\t%s;\n", name);
247 				break;
248 		}
249 	}
250 	dasprintf (dstr, "} globalvars_t;\n\n");
251 
252 	// print all fields
253 	dasprintf (dstr, "typedef struct\n{\n");
254 	for (i = 0, j = 0; i < progs->numglobaldefs; i++) {
255 		def = (ddef_t *) ((char *) progs + progs->ofs_globaldefs) + i;
256 		name = strings + def->s_name;
257 		if (!strcmp (name, "end_sys_fields"))
258 			break;
259 
260 		if (!def->ofs)
261 			continue;
262 		if (def->type != ev_field)
263 			continue;
264 		if (!strcmp (name, ".imm"))
265 			continue;
266 
267 		fdef = (ddef_t *) ((char *) progs + progs->ofs_fielddefs) + j++;
268 		if (fdef->s_name != def->s_name)
269 			internal_error (0, "def and field order messup");
270 
271 		switch (fdef->type) {
272 			case ev_float:
273 				dasprintf (dstr, "\tfloat\t%s;\n", name);
274 				break;
275 			case ev_vector:
276 				dasprintf (dstr, "\tvec3_t\t%s;\n", name);
277 				break;
278 			case ev_string:
279 				dasprintf (dstr, "\tstring_t\t%s;\n", name);
280 				break;
281 			case ev_func:
282 				dasprintf (dstr, "\tfunc_t\t%s;\n", name);
283 				break;
284 			case ev_entity:
285 				dasprintf (dstr, "\tint\t%s;\n", name);
286 				break;
287 			default:
288 				dasprintf (dstr, "\tint\t%s;\n", name);
289 				break;
290 		}
291 	}
292 	dasprintf (dstr, "} entvars_t;\n\n");
293 
294 	// do a crc of the structs
295 	crc = CRC_Block ((byte *) dstr->str, dstr->size - 1);
296 
297 	dasprintf (dstr, "#define PROGHEADER_CRC %u\n", crc);
298 	dstring_insertstr (dstr, 0, "/* Actually, generated by qfcc, be one must "
299 					   "maintain formalities */");
300 
301 	if (filename) {
302 		if (options.verbosity >= 1)
303 			printf ("writing %s\n", filename);
304 		f = Qopen (filename, "wt");
305 		Qwrite (f, dstr->str, dstr->size - 1);
306 		Qclose (f);
307 	}
308 
309 	return crc;
310 }
311