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