unix_shared.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #include <errno.h>
  21. #include <stdio.h>
  22. #include <dirent.h>
  23. #include <unistd.h>
  24. #include <sys/mman.h>
  25. #include <sys/time.h>
  26. #include <pwd.h>
  27. #include "../game/q_shared.h"
  28. #include "../qcommon/qcommon.h"
  29. //=============================================================================
  30. // Used to determine CD Path
  31. static char cdPath[MAX_OSPATH];
  32. // Used to determine local installation path
  33. static char installPath[MAX_OSPATH];
  34. // Used to determine where to store user-specific files
  35. static char homePath[MAX_OSPATH];
  36. /*
  37. ================
  38. Sys_Milliseconds
  39. ================
  40. */
  41. /* base time in seconds, that's our origin
  42. timeval:tv_sec is an int:
  43. assuming this wraps every 0x7fffffff - ~68 years since the Epoch (1970) - we're safe till 2038
  44. using unsigned long data type to work right with Sys_XTimeToSysTime */
  45. unsigned long sys_timeBase = 0;
  46. /* current time in ms, using sys_timeBase as origin
  47. NOTE: sys_timeBase*1000 + curtime -> ms since the Epoch
  48. 0x7fffffff ms - ~24 days
  49. although timeval:tv_usec is an int, I'm not sure wether it is actually used as an unsigned int
  50. (which would affect the wrap period) */
  51. int curtime;
  52. int Sys_Milliseconds (void)
  53. {
  54. struct timeval tp;
  55. gettimeofday(&tp, NULL);
  56. if (!sys_timeBase)
  57. {
  58. sys_timeBase = tp.tv_sec;
  59. return tp.tv_usec/1000;
  60. }
  61. curtime = (tp.tv_sec - sys_timeBase)*1000 + tp.tv_usec/1000;
  62. return curtime;
  63. }
  64. #if defined(__linux__) && !defined(DEDICATED)
  65. /*
  66. ================
  67. Sys_XTimeToSysTime
  68. sub-frame timing of events returned by X
  69. X uses the Time typedef - unsigned long
  70. disable with in_subframe 0
  71. sys_timeBase*1000 is the number of ms since the Epoch of our origin
  72. xtime is in ms and uses the Epoch as origin
  73. Time data type is an unsigned long: 0xffffffff ms - ~49 days period
  74. I didn't find much info in the XWindow documentation about the wrapping
  75. we clamp sys_timeBase*1000 to unsigned long, that gives us the current origin for xtime
  76. the computation will still work if xtime wraps (at ~49 days period since the Epoch) after we set sys_timeBase
  77. ================
  78. */
  79. extern cvar_t *in_subframe;
  80. int Sys_XTimeToSysTime (unsigned long xtime)
  81. {
  82. int ret, time, test;
  83. if (!in_subframe->value)
  84. {
  85. // if you don't want to do any event times corrections
  86. return Sys_Milliseconds();
  87. }
  88. // test the wrap issue
  89. #if 0
  90. // reference values for test: sys_timeBase 0x3dc7b5e9 xtime 0x541ea451 (read these from a test run)
  91. // xtime will wrap in 0xabe15bae ms >~ 0x2c0056 s (33 days from Nov 5 2002 -> 8 Dec)
  92. // NOTE: date -d '1970-01-01 UTC 1039384002 seconds' +%c
  93. // use sys_timeBase 0x3dc7b5e9+0x2c0056 = 0x3df3b63f
  94. // after around 5s, xtime would have wrapped around
  95. // we get 7132, the formula handles the wrap safely
  96. unsigned long xtime_aux,base_aux;
  97. int test;
  98. // Com_Printf("sys_timeBase: %p\n", sys_timeBase);
  99. // Com_Printf("xtime: %p\n", xtime);
  100. xtime_aux = 500; // 500 ms after wrap
  101. base_aux = 0x3df3b63f; // the base a few seconds before wrap
  102. test = xtime_aux - (unsigned long)(base_aux*1000);
  103. Com_Printf("xtime wrap test: %d\n", test);
  104. #endif
  105. // some X servers (like suse 8.1's) report weird event times
  106. // if the game is loading, resolving DNS, etc. we are also getting old events
  107. // so we only deal with subframe corrections that look 'normal'
  108. ret = xtime - (unsigned long)(sys_timeBase*1000);
  109. time = Sys_Milliseconds();
  110. test = time - ret;
  111. //printf("delta: %d\n", test);
  112. if (test < 0 || test > 30) // in normal conditions I've never seen this go above
  113. {
  114. return time;
  115. }
  116. return ret;
  117. }
  118. #endif
  119. //#if 0 // bk001215 - see snapvector.nasm for replacement
  120. #if (defined __APPLE__) // rcg010206 - using this for PPC builds...
  121. long fastftol( float f ) { // bk001213 - from win32/win_shared.c
  122. //static int tmp;
  123. // __asm fld f
  124. //__asm fistp tmp
  125. //__asm mov eax, tmp
  126. return (long)f;
  127. }
  128. void Sys_SnapVector( float *v ) { // bk001213 - see win32/win_shared.c
  129. // bk001213 - old linux
  130. v[0] = rint(v[0]);
  131. v[1] = rint(v[1]);
  132. v[2] = rint(v[2]);
  133. }
  134. #endif
  135. void Sys_Mkdir( const char *path )
  136. {
  137. mkdir (path, 0777);
  138. }
  139. char *strlwr (char *s) {
  140. if ( s==NULL ) { // bk001204 - paranoia
  141. assert(0);
  142. return s;
  143. }
  144. while (*s) {
  145. *s = tolower(*s);
  146. s++;
  147. }
  148. return s; // bk001204 - duh
  149. }
  150. //============================================
  151. #define MAX_FOUND_FILES 0x1000
  152. // bk001129 - new in 1.26
  153. void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles ) {
  154. char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
  155. char filename[MAX_OSPATH];
  156. DIR *fdir;
  157. struct dirent *d;
  158. struct stat st;
  159. if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
  160. return;
  161. }
  162. if (strlen(subdirs)) {
  163. Com_sprintf( search, sizeof(search), "%s/%s", basedir, subdirs );
  164. }
  165. else {
  166. Com_sprintf( search, sizeof(search), "%s", basedir );
  167. }
  168. if ((fdir = opendir(search)) == NULL) {
  169. return;
  170. }
  171. while ((d = readdir(fdir)) != NULL) {
  172. Com_sprintf(filename, sizeof(filename), "%s/%s", search, d->d_name);
  173. if (stat(filename, &st) == -1)
  174. continue;
  175. if (st.st_mode & S_IFDIR) {
  176. if (Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, "..")) {
  177. if (strlen(subdirs)) {
  178. Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s/%s", subdirs, d->d_name);
  179. }
  180. else {
  181. Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", d->d_name);
  182. }
  183. Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
  184. }
  185. }
  186. if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
  187. break;
  188. }
  189. Com_sprintf( filename, sizeof(filename), "%s/%s", subdirs, d->d_name );
  190. if (!Com_FilterPath( filter, filename, qfalse ))
  191. continue;
  192. list[ *numfiles ] = CopyString( filename );
  193. (*numfiles)++;
  194. }
  195. closedir(fdir);
  196. }
  197. // bk001129 - in 1.17 this used to be
  198. // char **Sys_ListFiles( const char *directory, const char *extension, int *numfiles, qboolean wantsubs )
  199. char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs )
  200. {
  201. struct dirent *d;
  202. // char *p; // bk001204 - unused
  203. DIR *fdir;
  204. qboolean dironly = wantsubs;
  205. char search[MAX_OSPATH];
  206. int nfiles;
  207. char **listCopy;
  208. char *list[MAX_FOUND_FILES];
  209. //int flag; // bk001204 - unused
  210. int i;
  211. struct stat st;
  212. int extLen;
  213. if (filter) {
  214. nfiles = 0;
  215. Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
  216. list[ nfiles ] = 0;
  217. *numfiles = nfiles;
  218. if (!nfiles)
  219. return NULL;
  220. listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
  221. for ( i = 0 ; i < nfiles ; i++ ) {
  222. listCopy[i] = list[i];
  223. }
  224. listCopy[i] = NULL;
  225. return listCopy;
  226. }
  227. if ( !extension)
  228. extension = "";
  229. if ( extension[0] == '/' && extension[1] == 0 ) {
  230. extension = "";
  231. dironly = qtrue;
  232. }
  233. extLen = strlen( extension );
  234. // search
  235. nfiles = 0;
  236. if ((fdir = opendir(directory)) == NULL) {
  237. *numfiles = 0;
  238. return NULL;
  239. }
  240. while ((d = readdir(fdir)) != NULL) {
  241. Com_sprintf(search, sizeof(search), "%s/%s", directory, d->d_name);
  242. if (stat(search, &st) == -1)
  243. continue;
  244. if ((dironly && !(st.st_mode & S_IFDIR)) ||
  245. (!dironly && (st.st_mode & S_IFDIR)))
  246. continue;
  247. if (*extension) {
  248. if ( strlen( d->d_name ) < strlen( extension ) ||
  249. Q_stricmp(
  250. d->d_name + strlen( d->d_name ) - strlen( extension ),
  251. extension ) ) {
  252. continue; // didn't match
  253. }
  254. }
  255. if ( nfiles == MAX_FOUND_FILES - 1 )
  256. break;
  257. list[ nfiles ] = CopyString( d->d_name );
  258. nfiles++;
  259. }
  260. list[ nfiles ] = 0;
  261. closedir(fdir);
  262. // return a copy of the list
  263. *numfiles = nfiles;
  264. if ( !nfiles ) {
  265. return NULL;
  266. }
  267. listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
  268. for ( i = 0 ; i < nfiles ; i++ ) {
  269. listCopy[i] = list[i];
  270. }
  271. listCopy[i] = NULL;
  272. return listCopy;
  273. }
  274. void Sys_FreeFileList( char **list ) {
  275. int i;
  276. if ( !list ) {
  277. return;
  278. }
  279. for ( i = 0 ; list[i] ; i++ ) {
  280. Z_Free( list[i] );
  281. }
  282. Z_Free( list );
  283. }
  284. char *Sys_Cwd( void )
  285. {
  286. static char cwd[MAX_OSPATH];
  287. getcwd( cwd, sizeof( cwd ) - 1 );
  288. cwd[MAX_OSPATH-1] = 0;
  289. return cwd;
  290. }
  291. void Sys_SetDefaultCDPath(const char *path)
  292. {
  293. Q_strncpyz(cdPath, path, sizeof(cdPath));
  294. }
  295. char *Sys_DefaultCDPath(void)
  296. {
  297. return cdPath;
  298. }
  299. void Sys_SetDefaultInstallPath(const char *path)
  300. {
  301. Q_strncpyz(installPath, path, sizeof(installPath));
  302. }
  303. char *Sys_DefaultInstallPath(void)
  304. {
  305. if (*installPath)
  306. return installPath;
  307. else
  308. return Sys_Cwd();
  309. }
  310. void Sys_SetDefaultHomePath(const char *path)
  311. {
  312. Q_strncpyz(homePath, path, sizeof(homePath));
  313. }
  314. char *Sys_DefaultHomePath(void)
  315. {
  316. char *p;
  317. if (*homePath)
  318. return homePath;
  319. if ((p = getenv("HOME")) != NULL) {
  320. Q_strncpyz(homePath, p, sizeof(homePath));
  321. #ifdef MACOS_X
  322. Q_strcat(homePath, sizeof(homePath), "/Library/Application Support/Quake3");
  323. #else
  324. Q_strcat(homePath, sizeof(homePath), "/.q3a");
  325. #endif
  326. if (mkdir(homePath, 0777)) {
  327. if (errno != EEXIST)
  328. Sys_Error("Unable to create directory \"%s\", error is %s(%d)\n", homePath, strerror(errno), errno);
  329. }
  330. return homePath;
  331. }
  332. return ""; // assume current dir
  333. }
  334. //============================================
  335. int Sys_GetProcessorId( void )
  336. {
  337. return CPUID_GENERIC;
  338. }
  339. void Sys_ShowConsole( int visLevel, qboolean quitOnClose )
  340. {
  341. }
  342. char *Sys_GetCurrentUser( void )
  343. {
  344. struct passwd *p;
  345. if ( (p = getpwuid( getuid() )) == NULL ) {
  346. return "player";
  347. }
  348. return p->pw_name;
  349. }
  350. #if defined(__linux__)
  351. // TTimo
  352. // sysconf() in libc, POSIX.1 compliant
  353. unsigned int Sys_ProcessorCount()
  354. {
  355. return sysconf(_SC_NPROCESSORS_ONLN);
  356. }
  357. #endif