platform/unix.c
changeset 20 efdde0d21521
parent 17 7337737f5120
child 23 bd6ba9c8717c
--- a/platform/unix.c	Sat Jul 07 09:05:19 2001 +0000
+++ b/platform/unix.c	Sun Jul 08 03:25:12 2001 +0000
@@ -6,9 +6,39 @@
  *  This file written by Ryan C. Gordon.
  */
 
+#if (defined __STRICT_ANSI__)
+#define __PHYSFS_DOING_STRICT_ANSI__
+#endif
+
+/*
+ * We cheat a little: I want the symlink version of stat() (lstat), and
+ *  GCC/Linux will not declare it if compiled with the -ansi flag.
+ *  If you are really lacking symlink support on your platform,
+ *  you should #define __PHYSFS_NO_SYMLINKS__ before compiling this
+ *  file. That will open a security hole, though, if you really DO have
+ *  symlinks on your platform; it renders PHYSFS_permitSymbolicLinks(0)
+ *  useless, since every symlink will be reported as a regular file/dir.
+ */
+#if (defined __PHYSFS_DOING_STRICT_ANSI__)
+#undef __STRICT_ANSI__
+#endif
 #include <stdio.h>
+#if (defined __PHYSFS_DOING_STRICT_ANSI__)
+#define __STRICT_ANSI__
+#endif
+
 #include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
 #include <pthread.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <time.h>
+#include <errno.h>
+
 
 #define __PHYSICSFS_INTERNAL__
 #include "physfs_internal.h"
@@ -18,22 +48,88 @@
 
 char **__PHYSFS_platformDetectAvailableCDs(void)
 {
+    /* !!! write me. */
+    char **retval = malloc(sizeof (char *));
+    if (retval != NULL)
+        *retval = NULL;
+
+    return(retval);
 } /* __PHYSFS_detectAvailableCDs */
 
 
 char *__PHYSFS_platformCalcBaseDir(char *argv0)
 {
-    return(NULL);
+    return(NULL);  /* default PhysicsFS behaviour is acceptable. */
 } /* __PHYSFS_platformCalcBaseDir */
 
 
+static char *copyEnvironmentVariable(const char *varname)
+{
+    const char *envr = getenv(varname);
+    char *retval = NULL;
+
+    if (envr != NULL)
+    {
+        retval = malloc(strlen(envr) + 1);
+        if (retval != NULL)
+            strcpy(retval, envr);
+    } /* if */
+
+    return(retval);
+} /* copyEnvironmentVariable */
+
+
+static char *getUserNameByUID(void)
+{
+    uid_t uid = getuid();
+    struct passwd *pw;
+    char *retval = NULL;
+
+    pw = getpwuid(uid);
+    if ((pw != NULL) && (pw->pw_name != NULL))
+    {
+        retval = malloc(strlen(pw->pw_name) + 1);
+        if (retval != NULL)
+            strcpy(retval, pw->pw_name);
+    } /* if */
+    
+    return(retval);
+} /* getUserNameByUID */
+
+
+static char *getUserDirByUID(void)
+{
+    uid_t uid = getuid();
+    struct passwd *pw;
+    char *retval = NULL;
+
+    pw = getpwuid(uid);
+    if ((pw != NULL) && (pw->pw_dir != NULL))
+    {
+        retval = malloc(strlen(pw->pw_dir) + 1);
+        if (retval != NULL)
+            strcpy(retval, pw->pw_dir);
+    } /* if */
+    
+    return(retval);
+} /* getUserDirByUID */
+
+
 char *__PHYSFS_platformGetUserName(void)
 {
+    char *retval = getUserNameByUID();
+    if (retval == NULL)
+        retval = copyEnvironmentVariable("USER");
+    return(retval);
 } /* __PHYSFS_platformGetUserName */
 
 
 char *__PHYSFS_platformGetUserDir(void)
 {
+    char *retval = copyEnvironmentVariable("HOME");
+    if (retval == NULL)
+        retval = getUserDirByUID();
+    return(retval);
 } /* __PHYSFS_platformGetUserDir */
 
 
@@ -43,21 +139,149 @@
 } /* __PHYSFS_platformGetThreadID */
 
 
-int __PHYSFS_platformStricmp(const char *str1, const char *str2)
+/* -ansi and -pedantic flags prevent use of strcasecmp() on Linux. */
+int __PHYSFS_platformStricmp(const char *x, const char *y)
 {
-    return(strcasecmp(str1, str2));
+    int ux, uy;
+
+    do
+    {
+        ux = toupper((int) *x);
+        uy = toupper((int) *y);
+        if (ux > uy)
+            return(1);
+        else if (ux < uy)
+            return(-1);
+        x++;
+        y++;
+    } while ((ux) && (uy));
+
+    return(0);
 } /* __PHYSFS_platformStricmp */
 
 
-int __PHYSFS_platformIsSymlink(const char *fname)
+int __PHYSFS_platformExists(const char *fname)
+{
+    struct stat statbuf;
+    return(stat(fname, &statbuf) == 0);
+} /* __PHYSFS_platformExists */
+
+
+int __PHYSFS_platformIsSymLink(const char *fname)
 {
+#if (defined __PHYSFS_NO_SYMLINKS__)
+    return(0);
+#else
+
+    struct stat statbuf;
+    int retval = 0;
+
+    if (lstat(fname, &statbuf) == 0)
+    {
+        if (S_ISLNK(statbuf.st_mode))
+            retval = 1;
+    } /* if */
+    
+    return(retval);
+
+#endif
 } /* __PHYSFS_platformIsSymlink */
 
 
 int __PHYSFS_platformIsDirectory(const char *fname)
 {
+    struct stat statbuf;
+    int retval = 0;
+
+    if (stat(fname, &statbuf) == 0)
+    {
+        if (S_ISDIR(statbuf.st_mode))
+            retval = 1;
+    } /* if */
+    
+    return(retval);
 } /* __PHYSFS_platformIsDirectory */
 
 
+char *__PHYSFS_platformCvtToDependent(const char *prepend,
+                                      const char *dirName,
+                                      const char *append)
+{
+    int len = ((prepend) ? strlen(prepend) : 0) +
+              ((append) ? strlen(append) : 0) +
+              strlen(dirName) + 1;
+    char *retval = malloc(len);
+
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    /* platform-independent notation is Unix-style already.  :)  */
+
+    if (prepend)
+        strcpy(retval, prepend);
+    else
+        retval[0] = '\0';
+
+    strcat(retval, dirName);
+
+    if (append)
+        strcat(retval, append);
+
+    return(retval);
+} /* __PHYSFS_platformCvtToDependent */
+
+
+/* Much like my college days, try to sleep for 10 milliseconds at a time... */
+void __PHYSFS_platformTimeslice(void)
+{
+    struct timespec napTime;
+    napTime.tv_sec = 0;
+    napTime.tv_nsec = 10 * 1000 * 1000;  /* specified in nanoseconds. */
+    nanosleep(&napTime, NULL);           /* don't care if it fails. */
+} /* __PHYSFS_platformTimeslice */
+
+
+LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname)
+{
+    LinkedStringList *retval = NULL;
+    LinkedStringList *l = NULL;
+    LinkedStringList *prev = NULL;
+    DIR *dir;
+    struct dirent *ent;
+
+    errno = 0;
+    dir = opendir(dirname);
+    BAIL_IF_MACRO(dir == NULL, strerror(errno), NULL);
+
+    while (1)
+    {
+        ent = readdir(dir);
+        if (ent == NULL)   /* we're done. */
+            break;
+
+        l = (LinkedStringList *) malloc(sizeof (LinkedStringList));
+        if (l != NULL)
+            break;
+
+        l->str = (char *) malloc(strlen(ent->d_name) + 1);
+        if (l->str == NULL)
+        {
+            free(l);
+            break;
+        } /* if */
+
+        if (retval == NULL)
+            retval = l;
+        else
+            prev->next = l;
+
+        prev = l;
+        l->next = NULL;
+    } /* while */
+
+    closedir(dir);
+    return(retval);
+} /* __PHYSFS_platformEnumerateFiles */
+
+
 /* end of unix.c ... */