/* * VisPatch : Quake level patcher for water visibility. * * Copyright (C) 1996-1997 Id Software, Inc. * Copyright (C) 1997-2006 Andy Bay * Copyright (C) 2006-2011 O. Sezer * * $Id: utilslib.c,v 1.13 2011/10/08 12:33:03 sezero Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to: * * Free Software Foundation, Inc. * 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ #include "arch_def.h" #include "compiler.h" #include "q_stdinc.h" #include "q_endian.h" #include #if defined(PLATFORM_WINDOWS) #include #include #include #endif /* PLATFORM_WINDOWS */ #if defined(PLATFORM_DOS) #include #include #include #include #include #endif /* PLATFORM_DOS */ #if defined(PLATFORM_UNIX) #include #include #include #endif /* PLATFORM_UNIX */ #include #include "utilslib.h" /*============================================================================*/ #if defined(__DJGPP__) && \ (!defined(__DJGPP_MINOR__) || __DJGPP_MINOR__ < 4) /* DJGPP < v2.04 doesn't have [v]snprintf(). */ /* to ensure a proper version check, include stdio.h * or go32.h which includes sys/version.h since djgpp * versions >= 2.02 and defines __DJGPP_MINOR__ */ #include "djlib/vsnprntf.c" #endif /* __DJGPP_MINOR__ < 4 */ int q_vsnprintf(char *str, size_t size, const char *format, va_list args) { int ret; ret = vsnprintf_func (str, size, format, args); if (ret < 0) ret = (int)size; if ((size_t)ret >= size) str[size - 1] = '\0'; return ret; } int q_snprintf (char *str, size_t size, const char *format, ...) { int ret; va_list argptr; va_start (argptr, format); ret = q_vsnprintf (str, size, format, argptr); va_end (argptr); return ret; } char *q_strlwr (char *str) { char *c; c = str; while (*c) { *c = tolower(*c); c++; } return str; } char *q_strrev (char *str) { char a, *b, *e; b = e = str; while (*e++) ; e -= 2; while ( b < e ) { a = *b; *b = *e; *e = a; b++; e--; } return str; } /*============================================================================*/ void Error (const char *error, ...) { va_list argptr; fprintf (stderr, "*** ERROR: ***\n"); va_start (argptr, error); vfprintf (stderr, error, argptr); va_end (argptr); fprintf (stderr, "\n"); exit (1); } /*============================================================================*/ #if defined(PLATFORM_WINDOWS) static HANDLE findhandle = INVALID_HANDLE_VALUE; static WIN32_FIND_DATA finddata; char *Sys_FindFirstFile (const char *path, const char *pattern) { char tmp_buf[256]; if (findhandle != INVALID_HANDLE_VALUE) Error ("Sys_FindFirst without FindClose"); q_snprintf (tmp_buf, sizeof(tmp_buf), "%s/%s", path, pattern); findhandle = FindFirstFile(tmp_buf, &finddata); if (findhandle == INVALID_HANDLE_VALUE) return NULL; if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) return Sys_FindNextFile(); return finddata.cFileName; } char *Sys_FindNextFile (void) { if (findhandle == INVALID_HANDLE_VALUE) return NULL; while (FindNextFile(findhandle, &finddata) != 0) { if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; return finddata.cFileName; } return NULL; } void Sys_FindClose (void) { if (findhandle != INVALID_HANDLE_VALUE) { FindClose(findhandle); findhandle = INVALID_HANDLE_VALUE; } } int Sys_filesize (const char *filename) { HANDLE fh; WIN32_FIND_DATA data; int size; fh = FindFirstFile(filename, &data); if (fh == INVALID_HANDLE_VALUE) return -1; FindClose(fh); if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) return -1; // we're not dealing with gigabytes of files. // size should normally smaller than INT_MAX. // size = (data.nFileSizeHigh * (MAXDWORD + 1)) + data.nFileSizeLow; size = (int) data.nFileSizeLow; return size; } int Sys_getcwd (char *buf, size_t size) { if (_getcwd(buf, size) == NULL) return 1; return 0; } #endif /* PLATFORM_WINDOWS */ //============================================================================ #if defined(PLATFORM_DOS) static struct ffblk finddata; static int findhandle = -1; char *Sys_FindFirstFile (const char *path, const char *pattern) { char tmp_buf[256]; if (findhandle == 0) Error ("Sys_FindFirst without FindClose"); q_snprintf (tmp_buf, sizeof(tmp_buf), "%s/%s", path, pattern); memset (&finddata, 0, sizeof(finddata)); findhandle = findfirst(tmp_buf, &finddata, FA_ARCH | FA_RDONLY); if (findhandle == 0) return finddata.ff_name; return NULL; } char *Sys_FindNextFile (void) { if (findhandle != 0) return NULL; if (findnext(&finddata) == 0) return finddata.ff_name; return NULL; } void Sys_FindClose (void) { findhandle = -1; } int Sys_filesize (const char *filename) { struct ffblk f; if (findfirst(filename, &f, FA_ARCH | FA_RDONLY) != 0) return -1; return (int) f.ff_fsize; } int Sys_getcwd (char *buf, size_t size) { if (getcwd(buf, size) == NULL) return 1; return 0; } #endif /* PLATFORM_DOS */ //============================================================================ #if defined(PLATFORM_UNIX) static DIR *finddir; static struct dirent *finddata; static char *findpath, *findpattern; static char matchpath[256]; char *Sys_FindFirstFile (const char *path, const char *pattern) { if (finddir) Error ("Sys_FindFirst without FindClose"); finddir = opendir (path); if (!finddir) return NULL; findpattern = strdup (pattern); if (!findpattern) { Sys_FindClose(); return NULL; } findpath = strdup (path); if (!findpath) { Sys_FindClose(); return NULL; } if (*findpath != '\0') { /* searching under "/" won't be a good idea, for example.. */ size_t siz = strlen(findpath) - 1; if (findpath[siz] == '/' || findpath[siz] == '\\') findpath[siz] = '\0'; } return Sys_FindNextFile(); } char *Sys_FindNextFile (void) { struct stat test; if (!finddir) return NULL; while ((finddata = readdir(finddir)) != NULL) { if (!fnmatch (findpattern, finddata->d_name, FNM_PATHNAME)) { q_snprintf(matchpath, sizeof(matchpath), "%s/%s", findpath, finddata->d_name); if ( (stat(matchpath, &test) == 0) && S_ISREG(test.st_mode)) return finddata->d_name; } } return NULL; } void Sys_FindClose (void) { if (finddir != NULL) { closedir(finddir); finddir = NULL; } if (findpath != NULL) { free (findpath); findpath = NULL; } if (findpattern != NULL) { free (findpattern); findpattern = NULL; } } int Sys_filesize (const char *filename) { struct stat status; if (stat(filename, &status) == -1) return -1; if (! S_ISREG(status.st_mode)) return -1; return (int) status.st_size; } int Sys_getcwd (char *buf, size_t size) { if (getcwd(buf, size) == NULL) return 1; return 0; } #endif /* PLATFORM_UNIX */ /*============================================================================*/ /*========== BYTE ORDER STUFF ================================================*/ #if ENDIAN_RUNTIME_DETECT #define __byteswap_func static #else #define __byteswap_func #endif /* ENDIAN_RUNTIME_DETECT */ #if ENDIAN_RUNTIME_DETECT /* # warning "Byte order will be detected at runtime" */ #elif defined(ENDIAN_ASSUMED_UNSAFE) # warning "Cannot determine byte order:" # if (ENDIAN_ASSUMED_UNSAFE == LITTLE_ENDIAN) # warning "Using LIL endian as an UNSAFE default." # elif (ENDIAN_ASSUMED_UNSAFE == BIG_ENDIAN) # warning "Using BIG endian as an UNSAFE default." # endif # warning "Revise the macros in q_endian.h for this" # warning "machine or use runtime detection !!!" #endif /* ENDIAN_ASSUMED_UNSAFE */ int host_byteorder; int host_bigendian; /* bool */ int DetectByteorder (void) { int i = 0x12345678; /* U N I X */ /* BE_ORDER: 12 34 56 78 U N I X LE_ORDER: 78 56 34 12 X I N U PDP_ORDER: 34 12 78 56 N U X I */ if ( *(char *)&i == 0x12 ) return BIG_ENDIAN; else if ( *(char *)&i == 0x78 ) return LITTLE_ENDIAN; else if ( *(char *)&i == 0x34 ) return PDP_ENDIAN; return -1; } __byteswap_func int LongSwap (int l) { unsigned char b1, b2, b3, b4; b1 = l & 255; b2 = (l>>8 ) & 255; b3 = (l>>16) & 255; b4 = (l>>24) & 255; return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; } #if ENDIAN_RUNTIME_DETECT __byteswap_func int LongNoSwap (int l) { return l; } int (*BigLong) (int); int (*LittleLong) (int); #endif /* ENDIAN_RUNTIME_DETECT */ void ByteOrder_Init (void) { host_byteorder = DetectByteorder (); host_bigendian = (host_byteorder == BIG_ENDIAN); #if ENDIAN_RUNTIME_DETECT switch (host_byteorder) { case BIG_ENDIAN: BigLong = LongNoSwap; LittleLong = LongSwap; break; case LITTLE_ENDIAN: BigLong = LongSwap; LittleLong = LongNoSwap; break; default: break; } #endif /* ENDIAN_RUNTIME_DETECT */ } void ValidateByteorder (void) { const char *endianism[] = { "BE", "LE", "PDP", "Unknown" }; int i; ByteOrder_Init (); switch (host_byteorder) { case BIG_ENDIAN: i = 0; break; case LITTLE_ENDIAN: i = 1; break; case PDP_ENDIAN: host_byteorder = -1; /* not supported */ i = 2; break; default: i = 3; break; } if (host_byteorder < 0) Error ("Unsupported byte order."); /* printf("Detected byte order: %s\n", endianism[i]); */ #if !ENDIAN_RUNTIME_DETECT if (host_byteorder != BYTE_ORDER) { int j; switch (BYTE_ORDER) { case BIG_ENDIAN: j = 0; break; case LITTLE_ENDIAN: j = 1; break; case PDP_ENDIAN: j = 2; break; default: j = 3; break; } Error ("Detected byte order %s doesn't match compiled %s order!", endianism[i], endianism[j]); } #endif /* ENDIAN_RUNTIME_DETECT */ }