1 /*
2  * scriplib.c
3  * MACT library Script file parsing and writing
4  *
5  * by Jonathon Fowler
6  *
7  * Since we weren't given the source for MACT386.LIB so I've had to do some
8  * creative interpolation here.
9  *
10  * This all should be rewritten in a much much cleaner fashion.
11  *
12  */
13 //-------------------------------------------------------------------------
14 /*
15 Duke Nukem Copyright (C) 1996, 2003 3D Realms Entertainment
16 
17 This file is part of Duke Nukem 3D version 1.5 - Atomic Edition
18 
19 Duke Nukem 3D is free software; you can redistribute it and/or
20 modify it under the terms of the GNU General Public License
21 as published by the Free Software Foundation; either version 2
22 of the License, or (at your option) any later version.
23 
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
27 
28 See the GNU General Public License for more details.
29 
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33 */
34 //-------------------------------------------------------------------------
35 
36 #include "compat.h"
37 #include "types.h"
38 #include "scriplib.h"
39 #include "util_lib.h"
40 #include "file_lib.h"
41 #include "_scrplib.h"
42 #include <string.h>
43 #include <stdio.h>
44 #include <ctype.h>
45 
46 #ifdef __WATCOMC__
47 #include <malloc.h>
48 #endif
49 
50 
51 static script_t *scriptfiles[MAXSCRIPTFILES];
52 
53 
54 #define SC(s) scriptfiles[s]
55 
56 
SCRIPT_New(void)57 int32 SCRIPT_New(void)
58 {
59 	int32 i;
60 
61 	for (i=0; i<MAXSCRIPTFILES; i++) {
62 		if (!SC(i)) {
63 			SC(i) = (script_t *)SafeMalloc(sizeof(script_t));
64 			if (!SC(i)) return -1;
65 			memset(SC(i), 0, sizeof(script_t));
66 			return i;
67 		}
68 	}
69 
70 	return -1;
71 }
72 
SCRIPT_Delete(int32 scripthandle)73 void SCRIPT_Delete(int32 scripthandle)
74 {
75 	ScriptSectionType *s;
76 
77 	if (scripthandle < 0 || scripthandle >= MAXSCRIPTFILES) return;
78 
79 	if (!SC(scripthandle)) return;
80 
81 	if (SCRIPT(scripthandle,script)) {
82 		while (SCRIPT(scripthandle,script)->nextsection != SCRIPT(scripthandle,script)) {
83 			s = SCRIPT(scripthandle,script)->nextsection;
84 			SCRIPT_FreeSection(SCRIPT(scripthandle,script));
85 			SafeFree(SCRIPT(scripthandle,script));
86 			SCRIPT(scripthandle,script) = s;
87 		}
88 
89 		SafeFree(SCRIPT(scripthandle,script));
90 	}
91 
92 	SafeFree(SC(scripthandle));
93 	SC(scripthandle) = 0;
94 }
95 
SCRIPT_FreeSection(ScriptSectionType * section)96 void SCRIPT_FreeSection(ScriptSectionType * section)
97 {
98 	ScriptEntryType *e;
99 
100 	if (!section) return;
101 	if (!section->entries) return;
102 
103 	while (section->entries->nextentry != section->entries) {
104 		e = section->entries->nextentry;
105 		SafeFree(section->entries);
106 		section->entries = e;
107 	}
108 
109 	SafeFree(section->entries);
110 	free(section->name);
111 }
112 
113 #define AllocSection(s) \
114 	{ \
115 		(s) = SafeMalloc(sizeof(ScriptSectionType)); \
116 		(s)->name = NULL; \
117 		(s)->entries = NULL; \
118 		(s)->lastline = NULL; \
119 		(s)->nextsection = (s); \
120 		(s)->prevsection = (s); \
121 	}
122 #define AllocEntry(e) \
123 	{ \
124 		(e) = SafeMalloc(sizeof(ScriptEntryType)); \
125 		(e)->name = NULL; \
126 		(e)->value = NULL; \
127 		(e)->nextentry = (e); \
128 		(e)->preventry = (e); \
129 	}
130 
SCRIPT_SectionExists(int32 scripthandle,const char * sectionname)131 ScriptSectionType * SCRIPT_SectionExists( int32 scripthandle, const char * sectionname )
132 {
133 	ScriptSectionType *s, *ls=NULL;
134 
135 	if (scripthandle < 0 || scripthandle >= MAXSCRIPTFILES) return NULL;
136 	if (!sectionname) return NULL;
137 	if (!SC(scripthandle)) return NULL;
138 	if (!SCRIPT(scripthandle,script)) return NULL;
139 
140 	for (s = SCRIPT(scripthandle,script); ls != s; ls=s,s=s->nextsection)
141 		if (!Bstrcasecmp(s->name, sectionname)) return s;
142 
143 	return NULL;
144 }
145 
SCRIPT_AddSection(int32 scripthandle,const char * sectionname)146 ScriptSectionType * SCRIPT_AddSection( int32 scripthandle, const char * sectionname )
147 {
148 	ScriptSectionType *s,*s2;
149 
150 	if (scripthandle < 0 || scripthandle >= MAXSCRIPTFILES) return NULL;
151 	if (!sectionname) return NULL;
152 	if (!SC(scripthandle)) return NULL;
153 
154 	s = SCRIPT_SectionExists(scripthandle, sectionname);
155 	if (s) return s;
156 
157 	AllocSection(s);
158 	s->name = strdup(sectionname);
159 	if (!SCRIPT(scripthandle,script)) {
160 		SCRIPT(scripthandle,script) = s;
161 	} else {
162 		s2 = SCRIPT(scripthandle,script);
163 		while (s2->nextsection != s2) s2=s2->nextsection;
164 		s2->nextsection = s;
165 		s->prevsection = s2;
166 	}
167 
168 	return s;
169 }
170 
SCRIPT_EntryExists(ScriptSectionType * section,const char * entryname)171 ScriptEntryType * SCRIPT_EntryExists ( ScriptSectionType * section, const char * entryname )
172 {
173 	ScriptEntryType *e,*le=NULL;
174 
175 	if (!section) return NULL;
176 	if (!entryname) return NULL;
177 	if (!section->entries) return NULL;
178 
179 	for (e = section->entries; le != e; le=e,e=e->nextentry)
180 		if (!Bstrcasecmp(e->name, entryname)) return e;
181 
182 	return NULL;
183 }
184 
SCRIPT_AddEntry(int32 scripthandle,const char * sectionname,const char * entryname,const char * entryvalue)185 void SCRIPT_AddEntry ( int32 scripthandle, const char * sectionname, const char * entryname, const char * entryvalue )
186 {
187 	ScriptSectionType *s;
188 	ScriptEntryType *e,*e2;
189 
190 	if (scripthandle < 0 || scripthandle >= MAXSCRIPTFILES) return;
191 	if (!sectionname || !entryname || !entryvalue) return;
192 	if (!SC(scripthandle)) return;
193 
194 //	s = SCRIPT_SectionExists(scripthandle, sectionname);
195 //	if (!s) {
196 		s = SCRIPT_AddSection(scripthandle, sectionname);
197 		if (!s) return;
198 //	}
199 
200 	e = SCRIPT_EntryExists(s, entryname);
201 	if (!e) {
202 		AllocEntry(e);
203 		e->name = strdup(entryname);
204 		if (!s->entries) {
205 			s->entries = e;
206 		} else {
207 			e2 = s->entries;
208 			while (e2->nextentry != e2) e2=e2->nextentry;
209 			e2->nextentry = e;
210 			e->preventry = e2;
211 		}
212 	}
213 
214 	if (e->value) free(e->value);
215 	e->value = strdup(entryvalue);
216 }
217 
218 
SCRIPT_ParseBuffer(int32 scripthandle,char * data,int32 length)219 int32 SCRIPT_ParseBuffer(int32 scripthandle, char *data, int32 length)
220 {
221 	char *fence = data + length;
222 	char *dp, *sp, ch=0, lastch=0;
223 	char *currentsection = "";
224 	char *currententry = NULL;
225 	char *currentvalue = NULL;
226 	enum {
227 		ParsingIdle,
228 		ParsingSectionBegin,
229 		ParsingSectionName,
230 		ParsingEntry,
231 		ParsingValueBegin,
232 		ParsingValue
233 	};
234 	enum {
235 		ExpectingSection = 1,
236 		ExpectingEntry = 2,
237 		ExpectingAssignment = 4,
238 		ExpectingValue = 8,
239 		ExpectingComment = 16
240 	};
241 	int state;
242 	int expect;
243 	int linenum=1;
244 	int rv = 0;
245 #define SETRV(v) if (v>rv||rv==0) rv=v
246 
247 	if (!data) return 1;
248 	if (length < 0) return 1;
249 
250 	dp = sp = data;
251 	state = ParsingIdle;
252 	expect = ExpectingSection | ExpectingEntry;
253 
254 #define EATLINE(p) while (length > 0 && *p != '\n' && *p != '\r') { p++; length--; }
255 #define LETTER() { lastch = ch; ch = *(sp++); length--; }
256 
257 	while (length > 0) {
258 		switch (state) {
259 			case ParsingIdle:
260 				LETTER();
261 				switch (ch) {
262 					// whitespace
263 					case ' ':
264 					case '\t': continue;
265 					case '\n': if (lastch == '\r') continue; linenum++; continue;
266 					case '\r': linenum++; continue;
267 
268 					case ';':
269 					/*case '#':*/
270 						  EATLINE(sp);
271 						  continue;
272 
273 					case '[': if (!(expect & ExpectingSection)) {
274 							  // Unexpected section start
275 							  printf("Unexpected start of section on line %d.\n", linenum);
276 							  SETRV(-1);
277 							  EATLINE(sp);
278 							  continue;
279 						  } else {
280 							  state = ParsingSectionBegin;
281 							  continue;
282 						  }
283 
284 					default:  if (isalpha(ch)) {
285 							  if (!(expect & ExpectingEntry)) {
286 								  // Unexpected name start
287 								  printf("Unexpected entry label on line %d.\n", linenum);
288 								  SETRV(-1);
289 								  EATLINE(sp);
290 								  continue;
291 							  } else {
292 								  currententry = dp = sp-1;
293 								  state = ParsingEntry;
294 								  continue;
295 							  }
296 						  } else {
297 							  // Unexpected character
298 							  printf("Illegal character (ASCII %d) on line %d.\n", ch, linenum);
299 							  SETRV(-1);
300 							  EATLINE(sp);
301 							  continue;
302 						  }
303 				}
304 
305 			case ParsingSectionBegin:
306 				currentsection = dp = sp;
307 				state = ParsingSectionName;
308 			case ParsingSectionName:
309 				LETTER();
310 				switch (ch) {
311 					case '\n':
312 					case '\r':	// Unexpected newline
313 						printf("Unexpected newline on line %d.\n", linenum);
314 						SETRV(-1);
315 						state = ParsingIdle;
316 						linenum++;
317 						continue;
318 
319 					case ']':
320 						*(dp) = 0;	// Add new section
321 						expect = ExpectingSection | ExpectingEntry;
322 						state = ParsingIdle;
323 						EATLINE(sp);
324 						continue;
325 
326 					default:
327 						dp++;
328 						continue;
329 				}
330 
331 			case ParsingEntry:
332 				LETTER();
333 				switch (ch) {
334 					case ';':
335 					/*case '#':*/
336 						// unexpected comment
337 						EATLINE(sp);
338 						printf("Unexpected comment on line %d.\n", linenum);
339 						SETRV(-1);
340 					case '\n':
341 					case '\r':
342 						// Unexpected newline
343 						printf("Unexpected newline on line %d.\n", linenum);
344 						SETRV(-1);
345 						expect = ExpectingSection | ExpectingEntry;
346 						state = ParsingIdle;
347 						linenum++;
348 						continue;
349 
350 					case '=':
351 						// Entry name finished, now for the value
352 						while (*dp == ' ' || *dp == '\t') dp--;
353 						*(++dp) = 0;
354 						state = ParsingValueBegin;
355 						continue;
356 
357 					default:
358 						dp++;
359 						continue;
360 				}
361 
362 			case ParsingValueBegin:
363 				currentvalue = dp = sp;
364 				state = ParsingValue;
365 			case ParsingValue:
366 				LETTER();
367 				switch (ch) {
368 					case '\n':
369 					case '\r':
370 						// value complete, add it using parsed name
371 						while (*dp == ' ' && *dp == '\t') dp--;
372 						*(dp) = 0;
373 						while (*currentvalue == ' ' || *currentvalue == '\t') currentvalue++;
374 						state = ParsingIdle;
375 						linenum++;
376 
377 						SCRIPT_AddSection(scripthandle,currentsection);
378 						SCRIPT_AddEntry(scripthandle,currentsection,currententry,currentvalue);
379 						continue;
380 
381 					default:
382 						dp++;
383 						continue;
384 				}
385 
386 			default: length=0;
387 				 continue;
388 		}
389 	}
390 
391 	if (sp > fence) printf("Stepped outside the fence!\n");
392 
393 	return rv;
394 }
395 
396 
397 //---
398 
SCRIPT_Init(const char * name)399 int32 SCRIPT_Init( const char * name )
400 {
401 	int32 h = SCRIPT_New();
402 
403 	if (h >= 0) strncpy(SCRIPT(h,scriptfilename), name, 127);
404 
405 	return h;
406 }
407 
SCRIPT_Free(int32 scripthandle)408 void SCRIPT_Free( int32 scripthandle )
409 {
410 	SCRIPT_Delete(scripthandle);
411 }
412 
SCRIPT_Parse(char * UNUSED (data),int32 UNUSED (length),char * UNUSED (name))413 int32 SCRIPT_Parse ( char *UNUSED(data), int32 UNUSED(length), char * UNUSED(name) )
414 {
415 	return 0;
416 }
417 
SCRIPT_Load(const char * filename)418 int32 SCRIPT_Load ( const char * filename )
419 {
420 	int32 s,h,l;
421 	char *b;
422 
423 	h = SafeOpenRead(filename, filetype_binary);
424 	l = SafeFileLength(h)+1;
425 	b = (char *)SafeMalloc(l);
426 	SafeRead(h,b,l-1);
427 	b[l-1] = '\n';	// JBF 20040111: evil nasty hack to trick my evil nasty parser
428 	SafeClose(h);
429 
430 	s = SCRIPT_Init(filename);
431 	if (s<0) {
432 		SafeFree(b);
433 		return -1;
434 	}
435 
436 	SCRIPT_ParseBuffer(s,b,l);
437 
438 	SafeFree(b);
439 
440 	return s;
441 }
442 
SCRIPT_Save(int32 scripthandle,const char * filename)443 void SCRIPT_Save (int32 scripthandle, const char * filename)
444 {
445 	const char *section, *entry, *value;
446 	int sec, ent, numsect, nument;
447 	FILE *fp;
448 
449 
450 	if (!filename) return;
451 	if (!SC(scripthandle)) return;
452 
453 	fp = fopen(filename, "w");
454 	if (!fp) return;
455 
456 	numsect = SCRIPT_NumberSections(scripthandle);
457 	for (sec=0; sec<numsect; sec++) {
458 		section = SCRIPT_Section(scripthandle, sec);
459 		if (sec>0) fprintf(fp, "\n");
460 		if (section[0] != 0)
461 			fprintf(fp, "[%s]\n", section);
462 
463 		nument = SCRIPT_NumberEntries(scripthandle,section);
464 		for (ent=0; ent<nument; ent++) {
465 			entry = SCRIPT_Entry(scripthandle,section,ent);
466 			value = SCRIPT_GetRaw(scripthandle,section,entry);
467 
468 			fprintf(fp, "%s = %s\n", entry, value);
469 		}
470 	}
471 
472 	fclose(fp);
473 }
474 
SCRIPT_NumberSections(int32 scripthandle)475 int32 SCRIPT_NumberSections( int32 scripthandle )
476 {
477 	int32 c=0;
478 	ScriptSectionType *s,*ls=NULL;
479 
480 	if (!SC(scripthandle)) return 0;
481 	if (!SCRIPT(scripthandle,script)) return 0;
482 
483 	for (s = SCRIPT(scripthandle,script); ls != s; ls=s,s=s->nextsection) c++;
484 
485 	return c;
486 }
487 
SCRIPT_Section(int32 scripthandle,int32 which)488 char * SCRIPT_Section( int32 scripthandle, int32 which )
489 {
490 	ScriptSectionType *s,*ls=NULL;
491 
492 	if (!SC(scripthandle)) return "";
493 	if (!SCRIPT(scripthandle,script)) return "";
494 
495 	for (s = SCRIPT(scripthandle,script); which>0 && ls != s; ls=s, s=s->nextsection, which--) ;
496 
497 	return s->name;
498 }
499 
SCRIPT_NumberEntries(int32 scripthandle,const char * sectionname)500 int32 SCRIPT_NumberEntries( int32 scripthandle, const char * sectionname )
501 {
502 	ScriptSectionType *s;
503 	ScriptEntryType *e,*le=NULL;
504 	int32 c=0;
505 
506 	if (!SC(scripthandle)) return 0;
507 	if (!SCRIPT(scripthandle,script)) return 0;
508 
509 	s = SCRIPT_SectionExists(scripthandle, sectionname);
510 	if (!s) return 0;
511 
512 	for (e = s->entries; le != e; le=e,e=e->nextentry) c++;
513 	return c;
514 }
515 
SCRIPT_Entry(int32 scripthandle,const char * sectionname,int32 which)516 const char * SCRIPT_Entry( int32 scripthandle, const char * sectionname, int32 which )
517 {
518 	ScriptSectionType *s;
519 	ScriptEntryType *e,*le=NULL;
520 
521 	if (!SC(scripthandle)) return 0;
522 	if (!SCRIPT(scripthandle,script)) return 0;
523 
524 	s = SCRIPT_SectionExists(scripthandle, sectionname);
525 	if (!s) return "";
526 
527 	for (e = s->entries; which>0 && le != e; le=e, e=e->nextentry, which--) ;
528 	return e->name;
529 }
530 
SCRIPT_GetRaw(int32 scripthandle,const char * sectionname,const char * entryname)531 const char * SCRIPT_GetRaw(int32 scripthandle, const char * sectionname, const char * entryname)
532 {
533 	ScriptSectionType *s;
534 	ScriptEntryType *e;
535 
536 	if (!SC(scripthandle)) return 0;
537 	if (!SCRIPT(scripthandle,script)) return 0;
538 
539 	s = SCRIPT_SectionExists(scripthandle, sectionname);
540 	e = SCRIPT_EntryExists(s, entryname);
541 
542 	if (!e) return "";
543 	return e->value;
544 }
545 
SCRIPT_GetString(int32 scripthandle,const char * sectionname,const char * entryname,char * dest,size_t destlen)546 boolean SCRIPT_GetString( int32 scripthandle, const char * sectionname, const char * entryname, char * dest, size_t destlen )
547 {
548 	ScriptSectionType *s;
549 	ScriptEntryType *e;
550 	const char *p;
551 	char ch, done;
552 	size_t c;
553 
554 	if (!SC(scripthandle)) return 1;
555 	if (!SCRIPT(scripthandle,script)) return 1;
556 
557 	s = SCRIPT_SectionExists(scripthandle, sectionname);
558 	e = SCRIPT_EntryExists(s, entryname);
559 
560 	if (!e) return 1;
561 	if (destlen < 1) return 1;
562 
563 	// Deduct the terminating null.
564 	destlen--;
565 
566 	p = e->value;
567 	c = 0;
568 	done = 0;
569 
570 	if (*p == '\"') {
571 		// quoted string
572 		p++;
573 		while (!done && (ch = *(p++))) {
574 			switch (ch) {
575 				case '\\':
576 					ch = *(p++);
577 					if (ch == 0) {
578 						done = 1;
579 					} else if (c < destlen) {
580 						switch (ch) {
581 							case 'n': dest[c++] = '\n'; break;
582 							case 'r': dest[c++] = '\r'; break;
583 							case 't': dest[c++] = '\t'; break;
584 							default:  dest[c++] = ch; break;
585 						}
586 					}
587 					break;
588 				case '\"':
589 					done = 1;
590 					break;
591 				default:
592 					if (c < destlen) {
593 						dest[c++] = ch;
594 					}
595 					break;
596 			}
597 		}
598 	} else {
599 		while ((ch = *(p++))) {
600 			if (ch == ' ' || ch == '\t') {
601 				break;
602 			} else if (c < destlen) {
603 				dest[c++] = ch;
604 			}
605 		}
606 	}
607 
608 	dest[c] = 0;
609 
610 	return 0;
611 }
612 
SCRIPT_GetDoubleString(int32 scripthandle,const char * sectionname,const char * entryname,char * dest1,char * dest2,size_t dest1len,size_t dest2len)613 boolean SCRIPT_GetDoubleString( int32 scripthandle, const char * sectionname, const char * entryname, char * dest1, char * dest2, size_t dest1len, size_t dest2len )
614 {
615 	ScriptSectionType *s;
616 	ScriptEntryType *e;
617 	const char *p;
618     char ch, done;
619 	size_t c;
620 
621 	if (!SC(scripthandle)) return 1;
622 	if (!SCRIPT(scripthandle,script)) return 1;
623 
624 	s = SCRIPT_SectionExists(scripthandle, sectionname);
625 	e = SCRIPT_EntryExists(s, entryname);
626 
627 	if (!e) return 1;
628 	if (dest1len < 1) return 1;
629 	if (dest2len < 1) return 1;
630 
631 	// Deduct the terminating nulls.
632 	dest1len--;
633 	dest2len--;
634 
635 	p = e->value;
636 	c = 0;
637 	done = 0;
638 
639 	if (*p == '\"') {
640 		// quoted string
641 		p++;
642 		while (!done && (ch = *(p++))) {
643 			switch (ch) {
644 				case '\\':
645 					ch = *(p++);
646 					if (ch == 0) {
647 						done = 1;
648 					} else if (c < dest1len) {
649 						switch (ch) {
650 							case 'n': dest1[c++] = '\n'; break;
651 							case 'r': dest1[c++] = '\r'; break;
652 							case 't': dest1[c++] = '\t'; break;
653 							default:  dest1[c++] = ch; break;
654 						}
655 					}
656 					break;
657 				case '\"':
658 					done = 1;
659 					break;
660 				default:
661 					if (c < dest1len) {
662 						dest1[c++] = ch;
663 					}
664 					break;
665 			}
666 		}
667 	} else {
668 		while ((ch = *(p++))) {
669 			if (ch == ' ' || ch == '\t') {
670 				break;
671 			} else if (c < dest1len) {
672 				dest1[c++] = ch;
673 			}
674 		}
675 	}
676 
677 	dest1[c] = 0;
678 
679 	while (*p == ' ' || *p == '\t') p++;
680 	if (*p == 0) return 0;
681 
682 	c = 0;
683 	done = 0;
684 
685 	if (*p == '\"') {
686 		// quoted string
687 		p++;
688 		while (!done && (ch = *(p++))) {
689 			switch (ch) {
690 				case '\\':
691 					ch = *(p++);
692 					if (ch == 0) {
693 						done = 1;
694 					} else if (c < dest2len) {
695 						switch (ch) {
696 							case 'n': dest2[c++] = '\n'; break;
697 							case 'r': dest2[c++] = '\r'; break;
698 							case 't': dest2[c++] = '\t'; break;
699 							default:  dest2[c++] = ch; break;
700 						}
701 					}
702 					break;
703 				case '\"':
704 					done = 1;
705 					break;
706 				default:
707 					if (c < dest2len) {
708 						dest2[c++] = ch;
709 					}
710 					break;
711 			}
712 		}
713 	} else {
714 		while ((ch = *(p++))) {
715 			if (ch == ' ' || ch == '\t') {
716 				break;
717 			} else if (c < dest2len) {
718 				dest2[c++] = ch;
719 			}
720 		}
721 	}
722 
723 	dest2[c] = 0;
724 
725 	return 0;
726 }
727 
SCRIPT_GetNumber(int32 scripthandle,const char * sectionname,const char * entryname,int32 * number)728 boolean SCRIPT_GetNumber( int32 scripthandle, const char * sectionname, const char * entryname, int32 * number )
729 {
730 	ScriptSectionType *s;
731 	ScriptEntryType *e;
732 	char *p;
733 
734 	if (!SC(scripthandle)) return 1;
735 	if (!SCRIPT(scripthandle,script)) return 1;
736 
737 	s = SCRIPT_SectionExists(scripthandle, sectionname);
738 	e = SCRIPT_EntryExists(s, entryname);
739 
740 	if (!e) return 1;// *number = 0;
741 	else {
742 		if (e->value[0] == '0' && e->value[1] == 'x') {
743 			// hex
744 			*number = strtol(e->value+2, &p, 16);
745 			if (p == e->value || *p != 0 || *p != ' ' || *p != '\t') return 1;
746 		} else {
747 			// decimal
748 			*number = strtol(e->value, &p, 10);
749 			if (p == e->value || *p != 0 || *p != ' ' || *p != '\t') return 1;
750 		}
751 	}
752 
753 	return 0;
754 }
755 
SCRIPT_GetBoolean(int32 scripthandle,const char * sectionname,const char * entryname,boolean * boole)756 boolean SCRIPT_GetBoolean( int32 scripthandle, const char * sectionname, const char * entryname, boolean * boole )
757 {
758 	ScriptSectionType *s;
759 	ScriptEntryType *e;
760 
761 	if (!SC(scripthandle)) return 1;
762 	if (!SCRIPT(scripthandle,script)) return 1;
763 
764 	s = SCRIPT_SectionExists(scripthandle, sectionname);
765 	e = SCRIPT_EntryExists(s, entryname);
766 
767 	if (!e) return 1;// *boole = 0;
768 	else {
769 		if (!Bstrncasecmp(e->value, "true", 4)) *boole = 1;
770 		else if (!Bstrncasecmp(e->value, "false", 5)) *boole = 0;
771 		else if (e->value[0] == '1' && (e->value[1] == ' ' || e->value[1] == '\t' || e->value[1] == 0)) *boole = 1;
772 		else if (e->value[0] == '0' && (e->value[1] == ' ' || e->value[1] == '\t' || e->value[1] == 0)) *boole = 0;
773 	}
774 
775 	return 0;
776 }
777 
SCRIPT_GetDouble(int32 scripthandle,const char * sectionname,const char * entryname,double * UNUSED (number))778 boolean SCRIPT_GetDouble( int32 scripthandle, const char * sectionname, const char * entryname, double * UNUSED(number) )
779 {
780 	ScriptSectionType *s;
781 	ScriptEntryType *e;
782 
783 	if (!SC(scripthandle)) return 1;
784 	if (!SCRIPT(scripthandle,script)) return 1;
785 
786 	s = SCRIPT_SectionExists(scripthandle, sectionname);
787 	e = SCRIPT_EntryExists(s, entryname);
788 
789 	if (!e) return 1;// *number = 0.0;
790 	else {
791         //XXX
792 	}
793 
794 	return 0;
795 }
796 
SCRIPT_PutComment(int32 UNUSED (scripthandle),const char * UNUSED (sectionname),const char * UNUSED (comment))797 void SCRIPT_PutComment( int32 UNUSED(scripthandle), const char * UNUSED(sectionname), const char * UNUSED(comment) )
798 {
799     //XXX
800 }
801 
SCRIPT_PutEOL(int32 UNUSED (scripthandle),const char * UNUSED (sectionname))802 void SCRIPT_PutEOL( int32 UNUSED(scripthandle), const char * UNUSED(sectionname) )
803 {
804     //XXX
805 }
806 
SCRIPT_PutMultiComment(int32 UNUSED (scripthandle),const char * UNUSED (sectionname),const char * UNUSED (comment),...)807 void SCRIPT_PutMultiComment
808    (
809    int32 UNUSED(scripthandle),
810    const char * UNUSED(sectionname),
811    const char * UNUSED(comment),
812    ...
813    )
814 {
815 }
816 
SCRIPT_PutSection(int32 scripthandle,const char * sectionname)817 void SCRIPT_PutSection( int32 scripthandle, const char * sectionname )
818 {
819 	SCRIPT_AddSection(scripthandle, sectionname);
820 }
821 
SCRIPT_PutRaw(int32 scripthandle,const char * sectionname,const char * entryname,const char * raw)822 void SCRIPT_PutRaw
823    (
824    int32 scripthandle,
825    const char * sectionname,
826    const char * entryname,
827    const char * raw
828    )
829 {
830 	SCRIPT_AddEntry(scripthandle, sectionname, entryname, raw);
831 }
832 
SCRIPT_PutString(int32 scripthandle,const char * sectionname,const char * entryname,const char * string)833 void SCRIPT_PutString
834    (
835    int32 scripthandle,
836    const char * sectionname,
837    const char * entryname,
838    const char * string
839    )
840 {
841 	char *raw,*p;
842     const char *q;
843 	int len = 3;
844 	if (!string) string = "";
845 
846 	for (q=string; *q; q++) {
847 		if (*q == '\r' || *q == '\n' || *q == '\t' || *q == '\\' || *q == '"') len+=2;
848 		else if (*q >= ' ') len++;
849 	}
850 	p = raw = Bmalloc(len);
851 	*(p++) = '"';
852 	for (q=string; *q; q++) {
853 		if (*q == '\r') { *(p++) = '\\'; *(p++) = 'r'; }
854 		else if (*q == '\n') { *(p++) = '\\'; *(p++) = 'n'; }
855 		else if (*q == '\t') { *(p++) = '\\'; *(p++) = 't'; }
856 		else if (*q == '\\' || *q == '"') { *(p++) = '\\'; *(p++) = *q; }
857 		else if (*q >= ' ') *(p++) = *q;
858 	}
859 	*(p++) = '"';
860 	*p=0;
861 
862 	SCRIPT_AddEntry(scripthandle, sectionname, entryname, raw);
863 	Bfree(raw);
864 }
865 
SCRIPT_PutDoubleString(int32 scripthandle,const char * sectionname,const char * entryname,const char * string1,const char * string2)866 void SCRIPT_PutDoubleString
867    (
868    int32 scripthandle,
869    const char * sectionname,
870    const char * entryname,
871    const char * string1,
872    const char * string2
873    )
874 {
875 	char *raw,*p;
876     const char *q;
877 	int len = 6;
878 	if (!string1) string1 = "";
879 	if (!string2) string2 = "";
880 
881 	for (q=string1; *q; q++) {
882 		if (*q == '\r' || *q == '\n' || *q == '\t' || *q == '\\' || *q == '"') len+=2;
883 		else if (*q >= ' ') len++;
884 	}
885 	for (q=string2; *q; q++) {
886 		if (*q == '\r' || *q == '\n' || *q == '\t' || *q == '\\' || *q == '"') len+=2;
887 		else if (*q >= ' ') len++;
888 	}
889 	p = raw = Bmalloc(len);
890 	*(p++) = '"';
891 	for (q=string1; *q; q++) {
892 		if (*q == '\r') { *(p++) = '\\'; *(p++) = 'r'; }
893 		else if (*q == '\n') { *(p++) = '\\'; *(p++) = 'n'; }
894 		else if (*q == '\t') { *(p++) = '\\'; *(p++) = 't'; }
895 		else if (*q == '\\' || *q == '"') { *(p++) = '\\'; *(p++) = *q; }
896 		else if (*q >= ' ') *(p++) = *q;
897 	}
898 	*(p++) = '"';
899 	*(p++) = ' ';
900 	*(p++) = '"';
901 	for (q=string2; *q; q++) {
902 		if (*q == '\r') { *(p++) = '\\'; *(p++) = 'r'; }
903 		else if (*q == '\n') { *(p++) = '\\'; *(p++) = 'n'; }
904 		else if (*q == '\t') { *(p++) = '\\'; *(p++) = 't'; }
905 		else if (*q == '\\' || *q == '"') { *(p++) = '\\'; *(p++) = *q; }
906 		else if (*q >= ' ') *(p++) = *q;
907 	}
908 	*(p++) = '"';
909 	*p=0;
910 
911 	SCRIPT_AddEntry(scripthandle, sectionname, entryname, raw);
912 	Bfree(raw);
913 }
914 
SCRIPT_PutNumber(int32 scripthandle,const char * sectionname,const char * entryname,int32 number,boolean hexadecimal,boolean UNUSED (defaultvalue))915 void SCRIPT_PutNumber
916    (
917    int32 scripthandle,
918    const char * sectionname,
919    const char * entryname,
920    int32 number,
921    boolean hexadecimal,
922    boolean UNUSED(defaultvalue)
923    )
924 {
925 	char raw[64];
926 
927 	if (hexadecimal) sprintf(raw, "0x%X", number);
928 	else sprintf(raw, "%d", number);
929 
930 	SCRIPT_AddEntry(scripthandle, sectionname, entryname, raw);
931 }
932 
SCRIPT_PutBoolean(int32 scripthandle,const char * sectionname,const char * entryname,boolean boole)933 void SCRIPT_PutBoolean
934    (
935    int32 scripthandle,
936    const char * sectionname,
937    const char * entryname,
938    boolean boole
939    )
940 {
941 	char raw[2] = "0";
942 
943 	if (boole) raw[0] = '1';
944 
945 	SCRIPT_AddEntry(scripthandle, sectionname, entryname, raw);
946 }
947 
SCRIPT_PutDouble(int32 scripthandle,const char * sectionname,const char * entryname,double number,boolean UNUSED (defaultvalue))948 void SCRIPT_PutDouble
949    (
950    int32 scripthandle,
951    const char * sectionname,
952    const char * entryname,
953    double number,
954    boolean UNUSED(defaultvalue)
955    )
956 {
957 	char raw[64];
958 
959 	sprintf(raw, "%g", number);
960 
961 	SCRIPT_AddEntry(scripthandle, sectionname, entryname, raw);
962 }
963 
964