// cmdlib.c #include "qcc.h" #include //#include #define PATHSEPERATOR '/' #ifndef QCC extern jmp_buf qcccompileerror; #endif // I put the following here to resolve "undefined reference to `__imp__vsnprintf'" with MinGW64 ~ Moodles #ifdef _WIN32 #if (_MSC_VER >= 1400) //with MSVC 8, use MS extensions #define snprintf linuxlike_snprintf_vc8 int VARGS linuxlike_snprintf_vc8(char *buffer, int size, const char *format, ...) LIKEPRINTF(3); #define vsnprintf(a, b, c, d) vsnprintf_s(a, b, _TRUNCATE, c, d) #else //msvc crap #define snprintf linuxlike_snprintf int VARGS linuxlike_snprintf(char *buffer, int size, const char *format, ...) LIKEPRINTF(3); #define vsnprintf linuxlike_vsnprintf int VARGS linuxlike_vsnprintf(char *buffer, int size, const char *format, va_list argptr); #endif #endif // set these before calling CheckParm int myargc; char **myargv; char qcc_token[1024]; int qcc_eof; const unsigned int type_size[12] = {1, //void sizeof(string_t)/4, //string 1, //float 3, //vector 1, //entity 1, //field sizeof(func_t)/4,//function 1, //pointer (its an int index) 1, //integer 1, //fixme: how big should a variant be? 0, //ev_struct. variable sized. 0 //ev_union. variable sized. }; /* ============================================================================ BYTE ORDER FUNCTIONS ============================================================================ */ short (*PRBigShort) (short l); short (*PRLittleShort) (short l); int (*PRBigLong) (int l); int (*PRLittleLong) (int l); float (*PRBigFloat) (float l); float (*PRLittleFloat) (float l); short QCC_SwapShort (short l) { qbyte b1,b2; b1 = l&255; b2 = (l>>8)&255; return (b1<<8) + b2; } short QCC_Short (short l) { return l; } int QCC_SwapLong (int l) { qbyte b1,b2,b3,b4; b1 = (qbyte)l; b2 = (qbyte)(l>>8); b3 = (qbyte)(l>>16); b4 = (qbyte)(l>>24); return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; } int QCC_Long (int l) { return l; } float QCC_SwapFloat (float l) { union {qbyte b[4]; float f;} in, out; in.f = l; out.b[0] = in.b[3]; out.b[1] = in.b[2]; out.b[2] = in.b[1]; out.b[3] = in.b[0]; return out.f; } float QCC_Float (float l) { return l; } void SetEndian(void) { union {qbyte b[2]; unsigned short s;} ed; ed.s = 255; if (ed.b[0] == 255) { PRBigShort = QCC_SwapShort; PRLittleShort = QCC_Short; PRBigLong = QCC_SwapLong; PRLittleLong = QCC_Long; PRBigFloat = QCC_SwapFloat; PRLittleFloat = QCC_Float; } else { PRBigShort = QCC_Short; PRLittleShort = QCC_SwapShort; PRBigLong = QCC_Long; PRLittleLong = QCC_SwapLong; PRBigFloat = QCC_Float; PRLittleFloat = QCC_SwapFloat; } } #ifndef MINIMAL /* ================ I_FloatTime ================ */ /* double I_FloatTime (void) { struct timeval tp; struct timezone tzp; static int secbase; gettimeofday(&tp, &tzp); if (!secbase) { secbase = tp.tv_sec; return tp.tv_usec/1000000.0; } return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; } */ #ifdef QCC int QC_strncasecmp (const char *s1, const char *s2, int n) { int c1, c2; while (1) { c1 = *s1++; c2 = *s2++; if (!n--) return 0; // strings are equal until end point if (c1 != c2) { if (c1 >= 'a' && c1 <= 'z') c1 -= ('a' - 'A'); if (c2 >= 'a' && c2 <= 'z') c2 -= ('a' - 'A'); if (c1 != c2) return -1; // strings not equal } if (!c1) return 0; // strings are equal // s1++; // s2++; } return -1; } int QC_strcasecmp (const char *s1, const char *s2) { return QC_strncasecmp(s1, s2, 0x7fffffff); } #else int QC_strncasecmp(const char *s1, const char *s2, int n); int QC_strcasecmp (const char *s1, const char *s2) { return QC_strncasecmp(s1, s2, 0x7fffffff); } #endif #endif //minimal /* ============== COM_Parse Parse a token out of a string ============== */ char *QCC_COM_Parse (char *data) { int c; int len; len = 0; qcc_token[0] = 0; if (!data) return NULL; // skip whitespace skipwhite: while ( (c = *data) <= ' ') { if (c == 0) { qcc_eof = true; return NULL; // end of file; } data++; } // skip // comments if (c=='/' && data[1] == '/') { while (*data && *data != '\n') data++; goto skipwhite; } // skip /* comments if (c=='/' && data[1] == '*') { while (data[1] && (data[0] != '*' || data[1] != '/')) data++; data+=2; goto skipwhite; } // handle quoted strings specially if (c == '\"') { data++; do { c = *data++; if (c=='\\' && *data == '\"') c = *data++; //allow C-style string escapes else if (c=='\\' && *data == '\\') c = *data++; // \ is now a special character so it needs to be marked up using itself else if (c=='\\' && *data == 'n') { // and do new lines while we're at it. c = '\n'; data++; } else if (c=='\"') { qcc_token[len] = 0; return data; } else if (c=='\0'||c=='\n') { qcc_token[len] = 0; return data; } qcc_token[len] = c; len++; } while (1); } // parse single characters if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':' || c==',') { qcc_token[len] = c; len++; qcc_token[len] = 0; return data+1; } // parse a regular word do { qcc_token[len] = c; data++; len++; c = *data; if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':' || c=='\"' || c==',') break; } while (c>32); qcc_token[len] = 0; return data; } //more C tokens... char *QCC_COM_Parse2 (char *data) { int c; int len; len = 0; qcc_token[0] = 0; if (!data) return NULL; // skip whitespace skipwhite: while ( (c = *data) <= ' ') { if (c == 0) { qcc_eof = true; return NULL; // end of file; } data++; } // skip // comments if (c=='/' && data[1] == '/') { while (*data && *data != '\n') data++; goto skipwhite; } // handle quoted strings specially if (c == '\"') { data++; do { c = *data++; if (c=='\\' && *data == '\"') c = *data++; //allow C-style string escapes else if (c=='\\' && *data == '\\') c = *data++; // \ is now a special character so it needs to be marked up using itself else if (c=='\\' && *data == 'n') { // and do new lines while we're at it. c = '\n'; data++; } else if (c=='\"'||c=='\0') qcc_token[len] = c; len++; } while (1); } // parse numbers if (c >= '0' && c <= '9') { if (c == '0' && data[1] == 'x') { //parse hex qcc_token[0] = '0'; c='x'; len=1; data++; for(;;) { //parse regular number qcc_token[len] = c; data++; len++; c = *data; if ((c<'0'|| c>'9') && (c<'a'||c>'f') && (c<'A'||c>'F') && c != '.') break; } } else { for(;;) { //parse regular number qcc_token[len] = c; data++; len++; c = *data; if ((c<'0'|| c>'9') && c != '.') break; } } qcc_token[len] = 0; return data; } // parse words else if ((c>= 'a' && c <= 'z') || (c>= 'A' && c <= 'Z') || c == '_') { do { qcc_token[len] = c; data++; len++; c = *data; } while ((c>= 'a' && c <= 'z') || (c>= 'A' && c <= 'Z') || c == '_'); qcc_token[len] = 0; return data; } else { qcc_token[len] = c; len++; qcc_token[len] = 0; return data+1; } } char *VARGS qcva (char *text, ...) { va_list argptr; static char msg[2048]; va_start (argptr,text); QC_vsnprintf (msg,sizeof(msg)-1, text,argptr); va_end (argptr); return msg; } #ifndef MINIMAL char *QC_strupr (char *start) { char *in; in = start; while (*in) { *in = toupper(*in); in++; } return start; } char *QC_strlower (char *start) { char *in; in = start; while (*in) { *in = tolower(*in); in++; } return start; } /* ============================================================================= MISC FUNCTIONS ============================================================================= */ /* ================= Error For abnormal program terminations ================= */ void VARGS QCC_Error (int errortype, const char *error, ...) { extern int numsourcefiles; va_list argptr; char msg[2048]; va_start (argptr,error); QC_vsnprintf (msg,sizeof(msg)-1, error,argptr); va_end (argptr); printf ("\n************ ERROR ************\n%s\n", msg); editbadfile(strings+s_file, pr_source_line); numsourcefiles = 0; #ifndef QCC longjmp(qcccompileerror, 1); #else print ("Press any key\n"); getch(); #endif exit (1); } /* ================= CheckParm Checks for the given parameter in the program's command line arguments Returns the argument number (1 to argc-1) or 0 if not present ================= */ int QCC_CheckParm (char *check) { int i; for (i = 1;i 0 && path[length] != PATHSEPERATOR) length--; path[length] = 0; } /* ==================== Extract file parts ==================== */ void ExtractFilePath (char *path, char *dest) { char *src; src = path + strlen(path) - 1; // // back up until a \ or the start // while (src != path && *(src-1) != PATHSEPERATOR) src--; memcpy (dest, path, src-path); dest[src-path] = 0; } void ExtractFileBase (char *path, char *dest) { char *src; src = path + strlen(path) - 1; // // back up until a \ or the start // while (src != path && *(src-1) != PATHSEPERATOR) src--; while (*src && *src != '.') { *dest++ = *src++; } *dest = 0; } void ExtractFileExtension (char *path, char *dest) { char *src; src = path + strlen(path) - 1; // // back up until a . or the start // while (src != path && *(src-1) != '.') src--; if (src == path) { *dest = 0; // no extension return; } strcpy (dest,src); } /* ============== ParseNum / ParseHex ============== */ long ParseHex (char *hex) { char *str; long num; num = 0; str = hex; while (*str) { num <<= 4; if (*str >= '0' && *str <= '9') num += *str-'0'; else if (*str >= 'a' && *str <= 'f') num += 10 + *str-'a'; else if (*str >= 'A' && *str <= 'F') num += 10 + *str-'A'; else QCC_Error (ERR_BADHEX, "Bad hex number: %s",hex); str++; } return num; } long ParseNum (char *str) { if (str[0] == '$') return ParseHex (str+1); if (str[0] == '0' && str[1] == 'x') return ParseHex (str+2); return atol (str); } //buffer size and max size are different. buffer is bigger. #define MAXQCCFILES 3 struct { char name[64]; char *buff; // int buffismalloc; int buffsize; int ofs; int maxofs; } qccfile[MAXQCCFILES]; int SafeOpenWrite (char *filename, int maxsize) { int i; for (i = 0; i < MAXQCCFILES; i++) { if (!qccfile[i].buff) { strcpy(qccfile[i].name, filename); qccfile[i].buffsize = maxsize; qccfile[i].maxofs = 0; qccfile[i].ofs = 0; // if (maxsize > 8192) // qccfile[i].buffismalloc = 1; // else // qccfile[i].buffismalloc = 0; // if (qccfile[i].buffismalloc) qccfile[i].buff = malloc(qccfile[i].buffsize); // else // qccfile[i].buff = memalloc(qccfile[i].buffsize); return i; } } QCC_Error(ERR_TOOMANYOPENFILES, "Too many open files on file %s", filename); return -1; } void ResizeBuf(int hand, int newsize) { // int wasmal = qccfile[hand].buffismalloc; char *nb; if (qccfile[hand].buffsize >= newsize) return; //already big enough // if (newsize > 8192) // { // qccfile[hand].buffismalloc = true; nb = malloc(newsize); // } // else // { // qccfile[hand].buffismalloc = false; // nb = memalloc(newsize); // } memcpy(nb, qccfile[hand].buff, qccfile[hand].maxofs); // if (wasmal) free(qccfile[hand].buff); // else // memfree(qccfile[hand].buff); qccfile[hand].buff = nb; qccfile[hand].buffsize = newsize; } void SafeWrite(int hand, void *buf, long count) { if (qccfile[hand].ofs +count >= qccfile[hand].buffsize) ResizeBuf(hand, qccfile[hand].ofs + count+(64*1024)); memcpy(&qccfile[hand].buff[qccfile[hand].ofs], buf, count); qccfile[hand].ofs+=count; if (qccfile[hand].ofs > qccfile[hand].maxofs) qccfile[hand].maxofs = qccfile[hand].ofs; } int SafeSeek(int hand, int ofs, int mode) { if (mode == SEEK_CUR) return qccfile[hand].ofs; else { ResizeBuf(hand, ofs+1024); qccfile[hand].ofs = ofs; if (qccfile[hand].ofs > qccfile[hand].maxofs) qccfile[hand].maxofs = qccfile[hand].ofs; return 0; } } void SafeClose(int hand) { externs->WriteFile(qccfile[hand].name, qccfile[hand].buff, qccfile[hand].maxofs); // if (qccfile[hand].buffismalloc) free(qccfile[hand].buff); // else // memfree(qccfile[hand].buff); qccfile[hand].buff = NULL; } qcc_cachedsourcefile_t *qcc_sourcefile; long QCC_LoadFile (char *filename, void **bufferptr) { char *mem; int len; len = externs->FileSize(filename); if (len < 0) { QCC_Error(ERR_COULDNTOPENFILE, "Couldn't open file %s", filename); // if (!Abort) return -1; // Abort("failed to find file %s", filename); } mem = qccHunkAlloc(sizeof(qcc_cachedsourcefile_t) + len+2); ((qcc_cachedsourcefile_t*)mem)->next = qcc_sourcefile; qcc_sourcefile = (qcc_cachedsourcefile_t*)mem; qcc_sourcefile->size = len; mem += sizeof(qcc_cachedsourcefile_t); strcpy(qcc_sourcefile->filename, filename); qcc_sourcefile->file = mem; qcc_sourcefile->type = FT_CODE; externs->ReadFile(filename, mem, len+2); mem[len] = '\n'; mem[len+1] = '\0'; *bufferptr=mem; return len; } void QCC_AddFile (char *filename) { char *mem; int len; len = externs->FileSize(filename); if (len < 0) Abort("failed to find file %s", filename); mem = qccHunkAlloc(sizeof(qcc_cachedsourcefile_t) + len+1); ((qcc_cachedsourcefile_t*)mem)->next = qcc_sourcefile; qcc_sourcefile = (qcc_cachedsourcefile_t*)mem; qcc_sourcefile->size = len; mem += sizeof(qcc_cachedsourcefile_t); strcpy(qcc_sourcefile->filename, filename); qcc_sourcefile->file = mem; qcc_sourcefile->type = FT_DATA; externs->ReadFile(filename, mem, len+1); mem[len] = '\0'; } void *FS_ReadToMem(char *filename, void *mem, int *len) { if (!mem) { *len = externs->FileSize(filename); mem = memalloc(*len); } return externs->ReadFile(filename, mem, *len); } void FS_CloseFromMem(void *mem) { memfree(mem); } #endif void StripExtension (char *path) { int length; length = strlen(path)-1; while (length > 0 && path[length] != '.') { length--; if (path[length] == '/') return; // no extension } if (length) path[length] = 0; }