]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - misc/source/fteqcc-src/qcc_cmdlib.c
f93e3e9c19683e8e884803e36543417f135d8eb0
[voretournament/voretournament.git] / misc / source / fteqcc-src / qcc_cmdlib.c
1 // cmdlib.c
2
3 #include "qcc.h"
4 #include <ctype.h>
5 //#include <sys/time.h>
6
7 #define PATHSEPERATOR   '/'
8
9 #ifndef QCC
10 extern jmp_buf qcccompileerror;
11 #endif
12
13 // I put the following here to resolve "undefined reference to `__imp__vsnprintf'" with MinGW64 ~ Moodles
14 #ifdef __MINGW64__
15 #ifndef QCCONLY
16         #if (_MSC_VER >= 1400)
17                 //with MSVC 8, use MS extensions
18                 #define snprintf linuxlike_snprintf_vc8
19                 int VARGS linuxlike_snprintf_vc8(char *buffer, int size, const char *format, ...) LIKEPRINTF(3);
20                 #define vsnprintf(a, b, c, d) vsnprintf_s(a, b, _TRUNCATE, c, d)
21         #else
22                 //msvc crap
23                 #define snprintf linuxlike_snprintf
24                 int VARGS linuxlike_snprintf(char *buffer, int size, const char *format, ...) LIKEPRINTF(3);
25                 #define vsnprintf linuxlike_vsnprintf
26                 int VARGS linuxlike_vsnprintf(char *buffer, int size, const char *format, va_list argptr);
27         #endif
28 #endif
29 #endif
30
31 // set these before calling CheckParm
32 int myargc;
33 char **myargv;
34
35 char    qcc_token[1024];
36 int             qcc_eof;
37
38 const unsigned int              type_size[12] = {1,     //void
39                                                 sizeof(string_t)/4,     //string
40                                                 1,      //float
41                                                 3,      //vector
42                                                 1,      //entity
43                                                 1,      //field
44                                                 sizeof(func_t)/4,//function
45                                                 1,  //pointer (its an int index)
46                                                 1,      //integer
47                                                 1,      //fixme: how big should a variant be?
48                                                 0,      //ev_struct. variable sized.
49                                                 0       //ev_union. variable sized.
50                                                 };
51
52 /*
53 ============================================================================
54
55                                         BYTE ORDER FUNCTIONS
56
57 ============================================================================
58 */
59 short   (*PRBigShort) (short l);
60 short   (*PRLittleShort) (short l);
61 int     (*PRBigLong) (int l);
62 int     (*PRLittleLong) (int l);
63 float   (*PRBigFloat) (float l);
64 float   (*PRLittleFloat) (float l);
65
66
67 short   QCC_SwapShort (short l)
68 {
69         qbyte    b1,b2;
70
71         b1 = l&255;
72         b2 = (l>>8)&255;
73
74         return (b1<<8) + b2;
75 }
76
77 short   QCC_Short (short l)
78 {
79         return l;
80 }
81
82
83 int    QCC_SwapLong (int l)
84 {
85         qbyte    b1,b2,b3,b4;
86
87         b1 = (qbyte)l;
88         b2 = (qbyte)(l>>8);
89         b3 = (qbyte)(l>>16);
90         b4 = (qbyte)(l>>24);
91
92         return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
93 }
94
95 int    QCC_Long (int l)
96 {
97         return l;
98 }
99
100
101 float   QCC_SwapFloat (float l)
102 {
103         union {qbyte b[4]; float f;} in, out;
104
105         in.f = l;
106         out.b[0] = in.b[3];
107         out.b[1] = in.b[2];
108         out.b[2] = in.b[1];
109         out.b[3] = in.b[0];
110
111         return out.f;
112 }
113
114 float   QCC_Float (float l)
115 {
116         return l;
117 }
118
119 void SetEndian(void)
120 {
121         union {qbyte b[2]; unsigned short s;} ed;
122         ed.s = 255;
123         if (ed.b[0] == 255)
124         {
125                 PRBigShort              = QCC_SwapShort;
126                 PRLittleShort   = QCC_Short;
127                 PRBigLong               = QCC_SwapLong;
128                 PRLittleLong    = QCC_Long;
129                 PRBigFloat              = QCC_SwapFloat;
130                 PRLittleFloat   = QCC_Float;
131         }
132         else
133         {
134                 PRBigShort              = QCC_Short;
135                 PRLittleShort   = QCC_SwapShort;
136                 PRBigLong               = QCC_Long;
137                 PRLittleLong    = QCC_SwapLong;
138                 PRBigFloat              = QCC_Float;
139                 PRLittleFloat   = QCC_SwapFloat;
140         }
141 }
142
143
144
145 #ifndef MINIMAL
146 /*
147 ================
148 I_FloatTime
149 ================
150 */
151 /*
152 double I_FloatTime (void)
153 {
154         struct timeval tp;
155         struct timezone tzp;
156         static int              secbase;
157
158         gettimeofday(&tp, &tzp);
159
160         if (!secbase)
161         {
162                 secbase = tp.tv_sec;
163                 return tp.tv_usec/1000000.0;
164         }
165
166         return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
167 }
168
169   */
170
171
172 #ifdef QCC
173 int QC_strncasecmp (const char *s1, const char *s2, int n)
174 {
175         int             c1, c2;
176
177         while (1)
178         {
179                 c1 = *s1++;
180                 c2 = *s2++;
181
182                 if (!n--)
183                         return 0;               // strings are equal until end point
184
185                 if (c1 != c2)
186                 {
187                         if (c1 >= 'a' && c1 <= 'z')
188                                 c1 -= ('a' - 'A');
189                         if (c2 >= 'a' && c2 <= 'z')
190                                 c2 -= ('a' - 'A');
191                         if (c1 != c2)
192                                 return -1;              // strings not equal
193                 }
194                 if (!c1)
195                         return 0;               // strings are equal
196 //              s1++;
197 //              s2++;
198         }
199
200         return -1;
201 }
202
203 int QC_strcasecmp (const char *s1, const char *s2)
204 {
205         return QC_strncasecmp(s1, s2, 0x7fffffff);
206 }
207
208 #else
209 int QC_strncasecmp(const char *s1, const char *s2, int n);
210 int QC_strcasecmp (const char *s1, const char *s2)
211 {
212         return QC_strncasecmp(s1, s2, 0x7fffffff);
213 }
214
215 #endif
216
217
218
219 #endif  //minimal
220 /*
221 ==============
222 COM_Parse
223
224 Parse a token out of a string
225 ==============
226 */
227 char *QCC_COM_Parse (char *data)
228 {
229         int             c;
230         int             len;
231
232         len = 0;
233         qcc_token[0] = 0;
234
235         if (!data)
236                 return NULL;
237
238 // skip whitespace
239 skipwhite:
240         while ( (c = *data) <= ' ')
241         {
242                 if (c == 0)
243                 {
244                         qcc_eof = true;
245                         return NULL;                    // end of file;
246                 }
247                 data++;
248         }
249
250 // skip // comments
251         if (c=='/' && data[1] == '/')
252         {
253                 while (*data && *data != '\n')
254                         data++;
255                 goto skipwhite;
256         }
257
258         // skip /* comments
259         if (c=='/' && data[1] == '*')
260         {
261                 while (data[1] && (data[0] != '*' || data[1] != '/'))
262                         data++;
263                 data+=2;
264                 goto skipwhite;
265         }
266
267
268 // handle quoted strings specially
269         if (c == '\"')
270         {
271                 data++;
272                 do
273                 {
274                         c = *data++;
275                         if (c=='\\' && *data == '\"')
276                                 c = *data++;    //allow C-style string escapes
277                         else if (c=='\\' && *data == '\\')
278                                 c = *data++;    // \ is now a special character so it needs to be marked up using itself
279                         else if (c=='\\' && *data == 'n')
280                         {                                       // and do new lines while we're at it.
281                                 c = '\n';
282                                 data++;
283                         }
284                         else if (c=='\"')
285                         {
286                                 qcc_token[len] = 0;
287                                 return data;
288                         }
289                         else if (c=='\0'||c=='\n')
290                         {
291                                 qcc_token[len] = 0;
292                                 return data;
293                         }
294                         qcc_token[len] = c;
295                         len++;
296                 } while (1);
297         }
298
299 // parse single characters
300         if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':' || c==',')
301         {
302                 qcc_token[len] = c;
303                 len++;
304                 qcc_token[len] = 0;
305                 return data+1;
306         }
307
308 // parse a regular word
309         do
310         {
311                 qcc_token[len] = c;
312                 data++;
313                 len++;
314                 c = *data;
315                 if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':' || c=='\"' || c==',')
316                         break;
317         } while (c>32);
318
319         qcc_token[len] = 0;
320         return data;
321 }
322
323 //more C tokens...
324 char *QCC_COM_Parse2 (char *data)
325 {
326         int             c;
327         int             len;
328
329         len = 0;
330         qcc_token[0] = 0;
331
332         if (!data)
333                 return NULL;
334
335 // skip whitespace
336 skipwhite:
337         while ( (c = *data) <= ' ')
338         {
339                 if (c == 0)
340                 {
341                         qcc_eof = true;
342                         return NULL;                    // end of file;
343                 }
344                 data++;
345         }
346
347 // skip // comments
348         if (c=='/' && data[1] == '/')
349         {
350                 while (*data && *data != '\n')
351                         data++;
352                 goto skipwhite;
353         }
354
355
356 // handle quoted strings specially
357         if (c == '\"')
358         {
359                 data++;
360                 do
361                 {
362                         c = *data++;
363                         if (c=='\\' && *data == '\"')
364                                 c = *data++;    //allow C-style string escapes
365                         else if (c=='\\' && *data == '\\')
366                                 c = *data++;    // \ is now a special character so it needs to be marked up using itself
367                         else if (c=='\\' && *data == 'n')
368                         {                                       // and do new lines while we're at it.
369                                 c = '\n';
370                                 data++;
371                         }
372                         else if (c=='\"'||c=='\0')
373                         qcc_token[len] = c;
374                         len++;
375                 } while (1);
376         }
377
378 // parse numbers
379         if (c >= '0' && c <= '9')
380         {
381                 if (c == '0' && data[1] == 'x')
382                 {       //parse hex
383                         qcc_token[0] = '0';
384                         c='x';
385                         len=1;
386                         data++;
387                         for(;;)
388                         {       //parse regular number
389                                 qcc_token[len] = c;
390                                 data++;
391                                 len++;
392                                 c = *data;
393                                 if ((c<'0'|| c>'9') && (c<'a'||c>'f') && (c<'A'||c>'F') && c != '.')
394                                         break;
395                         }
396
397                 }
398                 else
399                 {
400                         for(;;)
401                         {       //parse regular number
402                                 qcc_token[len] = c;
403                                 data++;
404                                 len++;
405                                 c = *data;
406                                 if ((c<'0'|| c>'9') && c != '.')
407                                         break;
408                         }
409                 }
410
411                 qcc_token[len] = 0;
412                 return data;
413         }
414 // parse words
415         else if ((c>= 'a' && c <= 'z') || (c>= 'A' && c <= 'Z') || c == '_')
416         {
417                 do
418                 {
419                         qcc_token[len] = c;
420                         data++;
421                         len++;
422                         c = *data;
423                 } while ((c>= 'a' && c <= 'z') || (c>= 'A' && c <= 'Z') || c == '_');
424
425                 qcc_token[len] = 0;
426                 return data;
427         }
428         else
429         {
430                 qcc_token[len] = c;
431                 len++;
432                 qcc_token[len] = 0;
433                 return data+1;
434         }
435 }
436
437 char *VARGS qcva (char *text, ...)
438 {
439         va_list argptr;
440         static char msg[2048];
441
442         va_start (argptr,text);
443         QC_vsnprintf (msg,sizeof(msg)-1, text,argptr);
444         va_end (argptr);
445
446         return msg;
447 }
448
449
450 #ifndef MINIMAL
451
452 char *QC_strupr (char *start)
453 {
454         char    *in;
455         in = start;
456         while (*in)
457         {
458                 *in = toupper(*in);
459                 in++;
460         }
461         return start;
462 }
463
464 char *QC_strlower (char *start)
465 {
466         char    *in;
467         in = start;
468         while (*in)
469         {
470                 *in = tolower(*in);
471                 in++;
472         }
473         return start;
474 }
475
476
477 /*
478 =============================================================================
479
480                                                 MISC FUNCTIONS
481
482 =============================================================================
483 */
484
485 /*
486 =================
487 Error
488
489 For abnormal program terminations
490 =================
491 */
492 void VARGS QCC_Error (int errortype, const char *error, ...)
493 {
494         extern int numsourcefiles;
495         va_list argptr;
496         char msg[2048];
497
498         va_start (argptr,error);
499         QC_vsnprintf (msg,sizeof(msg)-1, error,argptr);
500         va_end (argptr);
501
502         printf ("\n************ ERROR ************\n%s\n", msg);
503
504
505         editbadfile(strings+s_file, pr_source_line);
506
507         numsourcefiles = 0;
508
509 #ifndef QCC
510         longjmp(qcccompileerror, 1);
511 #else
512         print ("Press any key\n");
513         getch();
514 #endif
515         exit (1);
516 }
517
518
519 /*
520 =================
521 CheckParm
522
523 Checks for the given parameter in the program's command line arguments
524 Returns the argument number (1 to argc-1) or 0 if not present
525 =================
526 */
527 int QCC_CheckParm (char *check)
528 {
529         int             i;
530
531         for (i = 1;i<myargc;i++)
532         {
533                 if ( !QC_strcasecmp(check, myargv[i]) )
534                         return i;
535         }
536
537         return 0;
538 }
539
540 /*
541
542
543 #ifndef O_BINARY
544 #define O_BINARY 0
545 #endif
546
547 #ifdef QCC
548 int SafeOpenWrite (char *filename)
549 {
550         int     handle;
551
552         umask (0);
553
554         handle = open(filename,O_WRONLY | O_CREAT | O_TRUNC | O_BINARY
555         , 0666);
556
557         if (handle == -1)
558                 QCC_Error ("Error opening %s: %s",filename,strerror(errno));
559
560         return handle;
561 }
562 #endif
563
564 int SafeOpenRead (char *filename)
565 {
566         int     handle;
567
568         handle = open(filename,O_RDONLY | O_BINARY);
569
570         if (handle == -1)
571                 QCC_Error ("Error opening %s: %s",filename,strerror(errno));
572
573         return handle;
574 }
575
576
577 void SafeRead (int handle, void *buffer, long count)
578 {
579         if (read (handle,buffer,count) != count)
580                 QCC_Error ("File read failure");
581 }
582
583 #ifdef QCC
584 void SafeWrite (int handle, void *buffer, long count)
585 {
586         if (write (handle,buffer,count) != count)
587                 QCC_Error ("File write failure");
588 }
589 #endif
590
591
592 void *SafeMalloc (long size)
593 {
594         void *ptr;
595
596         ptr = (void *)Hunk_Alloc (size);
597
598         if (!ptr)
599                 QCC_Error ("Malloc failure for %lu bytes",size);
600
601         return ptr;
602 }
603
604 */
605
606
607
608 void DefaultExtension (char *path, char *extension)
609 {
610         char    *src;
611 //
612 // if path doesn't have a .EXT, append extension
613 // (extension should include the .)
614 //
615         src = path + strlen(path) - 1;
616
617         while (*src != PATHSEPERATOR && src != path)
618         {
619                 if (*src == '.')
620                         return;                 // it has an extension
621                 src--;
622         }
623
624         strcat (path, extension);
625 }
626
627
628 void DefaultPath (char *path, char *basepath)
629 {
630         char    temp[128];
631
632         if (path[0] == PATHSEPERATOR)
633                 return;                   // absolute path location
634         strcpy (temp,path);
635         strcpy (path,basepath);
636         strcat (path,temp);
637 }
638
639
640 void    StripFilename (char *path)
641 {
642         int             length;
643
644         length = strlen(path)-1;
645         while (length > 0 && path[length] != PATHSEPERATOR)
646                 length--;
647         path[length] = 0;
648 }
649
650 /*
651 ====================
652 Extract file parts
653 ====================
654 */
655 void ExtractFilePath (char *path, char *dest)
656 {
657         char    *src;
658
659         src = path + strlen(path) - 1;
660
661 //
662 // back up until a \ or the start
663 //
664         while (src != path && *(src-1) != PATHSEPERATOR)
665                 src--;
666
667         memcpy (dest, path, src-path);
668         dest[src-path] = 0;
669 }
670
671 void ExtractFileBase (char *path, char *dest)
672 {
673         char    *src;
674
675         src = path + strlen(path) - 1;
676
677 //
678 // back up until a \ or the start
679 //
680         while (src != path && *(src-1) != PATHSEPERATOR)
681                 src--;
682
683         while (*src && *src != '.')
684         {
685                 *dest++ = *src++;
686         }
687         *dest = 0;
688 }
689
690 void ExtractFileExtension (char *path, char *dest)
691 {
692         char    *src;
693
694         src = path + strlen(path) - 1;
695
696 //
697 // back up until a . or the start
698 //
699         while (src != path && *(src-1) != '.')
700                 src--;
701         if (src == path)
702         {
703                 *dest = 0;      // no extension
704                 return;
705         }
706
707         strcpy (dest,src);
708 }
709
710
711 /*
712 ==============
713 ParseNum / ParseHex
714 ==============
715 */
716 long ParseHex (char *hex)
717 {
718         char    *str;
719         long    num;
720
721         num = 0;
722         str = hex;
723
724         while (*str)
725         {
726                 num <<= 4;
727                 if (*str >= '0' && *str <= '9')
728                         num += *str-'0';
729                 else if (*str >= 'a' && *str <= 'f')
730                         num += 10 + *str-'a';
731                 else if (*str >= 'A' && *str <= 'F')
732                         num += 10 + *str-'A';
733                 else
734                         QCC_Error (ERR_BADHEX, "Bad hex number: %s",hex);
735                 str++;
736         }
737
738         return num;
739 }
740
741
742 long ParseNum (char *str)
743 {
744         if (str[0] == '$')
745                 return ParseHex (str+1);
746         if (str[0] == '0' && str[1] == 'x')
747                 return ParseHex (str+2);
748         return atol (str);
749 }
750
751
752
753
754
755
756
757
758 //buffer size and max size are different. buffer is bigger.
759
760 #define MAXQCCFILES 3
761 struct {
762         char name[64];
763         char *buff;
764 //      int buffismalloc;
765         int buffsize;
766         int ofs;
767         int maxofs;
768 } qccfile[MAXQCCFILES];
769 int SafeOpenWrite (char *filename, int maxsize)
770 {
771         int i;
772         for (i = 0; i < MAXQCCFILES; i++)
773         {
774                 if (!qccfile[i].buff)
775                 {
776                         strcpy(qccfile[i].name, filename);
777                         qccfile[i].buffsize = maxsize;
778                         qccfile[i].maxofs = 0;
779                         qccfile[i].ofs = 0;
780 //                      if (maxsize > 8192)
781 //                              qccfile[i].buffismalloc = 1;
782 //                      else
783 //                              qccfile[i].buffismalloc = 0;
784 //                      if (qccfile[i].buffismalloc)
785                                 qccfile[i].buff = malloc(qccfile[i].buffsize);
786 //                      else
787 //                              qccfile[i].buff = memalloc(qccfile[i].buffsize);
788                         return i;
789                 }
790         }
791         QCC_Error(ERR_TOOMANYOPENFILES, "Too many open files on file %s", filename);
792         return -1;
793 }
794
795 void ResizeBuf(int hand, int newsize)
796 {
797 //      int wasmal = qccfile[hand].buffismalloc;
798         char *nb;
799
800         if (qccfile[hand].buffsize >= newsize)
801                 return; //already big enough
802
803 //      if (newsize > 8192)
804 //      {
805 //              qccfile[hand].buffismalloc = true;
806                 nb = malloc(newsize);
807 //      }
808 //      else
809 //      {
810 //              qccfile[hand].buffismalloc = false;
811 //              nb = memalloc(newsize);
812 //      }
813
814         memcpy(nb, qccfile[hand].buff, qccfile[hand].maxofs);
815 //      if (wasmal)
816                 free(qccfile[hand].buff);
817 //      else
818 //              memfree(qccfile[hand].buff);
819         qccfile[hand].buff = nb;
820         qccfile[hand].buffsize = newsize;
821 }
822 void SafeWrite(int hand, void *buf, long count)
823 {
824         if (qccfile[hand].ofs +count >= qccfile[hand].buffsize)
825                 ResizeBuf(hand, qccfile[hand].ofs + count+(64*1024));
826
827         memcpy(&qccfile[hand].buff[qccfile[hand].ofs], buf, count);
828         qccfile[hand].ofs+=count;
829         if (qccfile[hand].ofs > qccfile[hand].maxofs)
830                 qccfile[hand].maxofs = qccfile[hand].ofs;
831 }
832 int SafeSeek(int hand, int ofs, int mode)
833 {
834         if (mode == SEEK_CUR)
835                 return qccfile[hand].ofs;
836         else
837         {
838                 ResizeBuf(hand, ofs+1024);
839                 qccfile[hand].ofs = ofs;
840                 if (qccfile[hand].ofs > qccfile[hand].maxofs)
841                         qccfile[hand].maxofs = qccfile[hand].ofs;
842                 return 0;
843         }
844 }
845 void SafeClose(int hand)
846 {
847         externs->WriteFile(qccfile[hand].name, qccfile[hand].buff, qccfile[hand].maxofs);
848 //      if (qccfile[hand].buffismalloc)
849                 free(qccfile[hand].buff);
850 //      else
851 //              memfree(qccfile[hand].buff);
852         qccfile[hand].buff = NULL;
853 }
854
855 qcc_cachedsourcefile_t *qcc_sourcefile;
856 long    QCC_LoadFile (char *filename, void **bufferptr)
857 {
858         char *mem;
859         int len;
860         len = externs->FileSize(filename);
861         if (len < 0)
862         {
863                 QCC_Error(ERR_COULDNTOPENFILE, "Couldn't open file %s", filename);
864 //              if (!Abort)
865                         return -1;
866 //              Abort("failed to find file %s", filename);
867         }
868         mem = qccHunkAlloc(sizeof(qcc_cachedsourcefile_t) + len+2);
869
870         ((qcc_cachedsourcefile_t*)mem)->next = qcc_sourcefile;
871         qcc_sourcefile = (qcc_cachedsourcefile_t*)mem;
872         qcc_sourcefile->size = len;
873         mem += sizeof(qcc_cachedsourcefile_t);
874         strcpy(qcc_sourcefile->filename, filename);
875         qcc_sourcefile->file = mem;
876         qcc_sourcefile->type = FT_CODE;
877
878         externs->ReadFile(filename, mem, len+2);
879         mem[len] = '\n';
880         mem[len+1] = '\0';
881         *bufferptr=mem;
882
883         return len;
884 }
885 void    QCC_AddFile (char *filename)
886 {
887         char *mem;
888         int len;
889         len = externs->FileSize(filename);
890         if (len < 0)
891                 Abort("failed to find file %s", filename);
892         mem = qccHunkAlloc(sizeof(qcc_cachedsourcefile_t) + len+1);
893
894         ((qcc_cachedsourcefile_t*)mem)->next = qcc_sourcefile;
895         qcc_sourcefile = (qcc_cachedsourcefile_t*)mem;
896         qcc_sourcefile->size = len;
897         mem += sizeof(qcc_cachedsourcefile_t);
898         strcpy(qcc_sourcefile->filename, filename);
899         qcc_sourcefile->file = mem;
900         qcc_sourcefile->type = FT_DATA;
901
902         externs->ReadFile(filename, mem, len+1);
903         mem[len] = '\0';
904 }
905 void *FS_ReadToMem(char *filename, void *mem, int *len)
906 {
907         if (!mem)
908         {
909                 *len = externs->FileSize(filename);
910                 mem = memalloc(*len);
911         }
912         return externs->ReadFile(filename, mem, *len);
913 }
914
915 void FS_CloseFromMem(void *mem)
916 {
917         memfree(mem);
918 }
919
920
921 #endif
922
923 void    StripExtension (char *path)
924 {
925         int             length;
926
927         length = strlen(path)-1;
928         while (length > 0 && path[length] != '.')
929         {
930                 length--;
931                 if (path[length] == '/')
932                         return;         // no extension
933         }
934         if (length)
935                 path[length] = 0;
936 }