Annotation of hatari/src/paths.c, revision 1.1.1.14

1.1       root        1: /*
                      2:   Hatari - paths.c
                      3: 
1.1.1.9   root        4:   This file is distributed under the GNU General Public License, version 2
                      5:   or at your option any later version. Read the file gpl.txt for details.
1.1       root        6: 
                      7:   Set up the various path strings.
                      8: */
1.1.1.4   root        9: const char Paths_fileid[] = "Hatari paths.c : " __DATE__ " " __TIME__;
1.1       root       10: 
                     11: #include <unistd.h>
                     12: #include <sys/stat.h>
                     13: #include <sys/types.h>
                     14: 
                     15: #include "main.h"
                     16: #include "file.h"
                     17: #include "paths.h"
1.1.1.11  root       18: #include "str.h"
1.1       root       19: 
1.1.1.5   root       20: #if defined(WIN32) && !defined(mkdir)
1.1.1.2   root       21: #define mkdir(name,mode) mkdir(name)
                     22: #endif  /* WIN32 */
                     23: 
1.1.1.10  root       24: #if defined(__MACOSX__)
                     25:        #define HATARI_HOME_DIR "Library/Application Support/Hatari"
1.1.1.12  root       26: #elif defined(WIN32)
                     27:        #define HATARI_HOME_DIR "AppData\\Local\\Hatari"
1.1.1.10  root       28: #else
1.1.1.12  root       29:        #define HATARI_HOME_DIR ".config/hatari"
1.1.1.10  root       30: #endif
                     31: 
1.1.1.14! root       32: static char *sWorkingDir;     /* Working directory */
        !            33: static char *sDataDir;        /* Directory where data files of Hatari can be found */
        !            34: static char *sUserHomeDir;    /* User's home directory ($HOME) */
        !            35: static char *sHatariHomeDir;  /* Hatari's home directory ($HOME/.hatari/) */
        !            36: static char *sScreenShotDir;  /* Directory to use for screenshots */
1.1       root       37: 
                     38: /**
                     39:  * Return pointer to current working directory string
                     40:  */
                     41: const char *Paths_GetWorkingDir(void)
                     42: {
                     43:        return sWorkingDir;
                     44: }
                     45: 
                     46: /**
                     47:  * Return pointer to data directory string
                     48:  */
                     49: const char *Paths_GetDataDir(void)
                     50: {
                     51:        return sDataDir;
                     52: }
                     53: 
                     54: /**
                     55:  * Return pointer to user's home directory string
                     56:  */
                     57: const char *Paths_GetUserHome(void)
                     58: {
                     59:        return sUserHomeDir;
                     60: }
                     61: 
                     62: /**
                     63:  * Return pointer to Hatari's home directory string
                     64:  */
                     65: const char *Paths_GetHatariHome(void)
                     66: {
                     67:        return sHatariHomeDir;
                     68: }
                     69: 
1.1.1.14! root       70: /**
        !            71:  * Return pointer to screenshot directory string
        !            72:  */
        !            73: const char *Paths_GetScreenShotDir(void)
        !            74: {
        !            75:        return sScreenShotDir;
        !            76: }
        !            77: 
1.1       root       78: 
                     79: /**
                     80:  * Explore the PATH environment variable to see where our executable is
                     81:  * installed.
                     82:  */
1.1.1.3   root       83: static void Paths_GetExecDirFromPATH(const char *argv0, char *pExecDir, int nMaxLen)
1.1       root       84: {
                     85:        char *pPathEnv;
                     86:        char *pAct;
                     87:        char *pTmpName;
                     88:        const char *pToken;
                     89: 
                     90:        /* Get the PATH environment string */
                     91:        pPathEnv = getenv("PATH");
                     92:        if (!pPathEnv)
                     93:                return;
                     94:        /* Duplicate the string because strtok destroys it later */
                     95:        pPathEnv = strdup(pPathEnv);
                     96:        if (!pPathEnv)
                     97:                return;
                     98: 
                     99:        pTmpName = malloc(FILENAME_MAX);
                    100:        if (!pTmpName)
1.1.1.10  root      101:        {
                    102:                perror("Paths_GetExecDirFromPATH");
                    103:                free(pPathEnv);
1.1       root      104:                return;
1.1.1.10  root      105:        }
1.1       root      106: 
                    107:        /* If there is a semicolon in the PATH, we assume it is the PATH
                    108:         * separator token (like on Windows), otherwise we use a colon. */
                    109:        if (strchr((pPathEnv), ';'))
                    110:                pToken = ";";
                    111:        else
                    112:                pToken = ":";
                    113: 
                    114:        pAct = strtok (pPathEnv, pToken);
                    115:        while (pAct)
                    116:        {
                    117:                snprintf(pTmpName, FILENAME_MAX, "%s%c%s",
                    118:                         pAct, PATHSEP, argv0);
                    119:                if (File_Exists(pTmpName))
                    120:                {
                    121:                        /* Found the executable - so use the corresponding path: */
1.1.1.11  root      122:                        strlcpy(pExecDir, pAct, nMaxLen);
1.1       root      123:                        break;
                    124:                }
1.1.1.12  root      125:                pAct = strtok (NULL, pToken);
1.1       root      126:        }
                    127: 
                    128:        free(pPathEnv);
                    129:        free(pTmpName);
                    130: }
                    131: 
                    132: 
                    133: /**
                    134:  * Locate the directory where the hatari executable resides
                    135:  */
1.1.1.3   root      136: static char *Paths_InitExecDir(const char *argv0)
1.1       root      137: {
                    138:        char *psExecDir;  /* Path string where the hatari executable can be found */
                    139: 
                    140:        /* Allocate memory for storing the path string of the executable */
                    141:        psExecDir = malloc(FILENAME_MAX);
                    142:        if (!psExecDir)
                    143:        {
                    144:                fprintf(stderr, "Out of memory (Paths_Init)\n");
                    145:                exit(-1);
                    146:        }
                    147: 
                    148:        /* Determine the bindir...
                    149:         * Start with empty string, then try to use OS specific functions,
                    150:         * and finally analyze the PATH variable if it has not been found yet. */
                    151:        psExecDir[0] = '\0';
                    152: 
                    153: #if defined(__linux__)
                    154:        {
                    155:                int i;
                    156:                /* On Linux, we can analyze the symlink /proc/self/exe */
1.1.1.11  root      157:                i = readlink("/proc/self/exe", psExecDir, FILENAME_MAX-1);
1.1       root      158:                if (i > 0)
                    159:                {
                    160:                        char *p;
                    161:                        psExecDir[i] = '\0';
                    162:                        p = strrchr(psExecDir, '/');    /* Search last slash */
                    163:                        if (p)
                    164:                                *p = 0;                     /* Strip file name from path */
                    165:                }
                    166:        }
                    167: //#elif defined(WIN32) || defined(__CEGCC__)
                    168: //     /* On Windows we can use GetModuleFileName for getting the exe path */
                    169: //     GetModuleFileName(NULL, psExecDir, FILENAME_MAX);
                    170: #endif
                    171: 
                    172:        /* If we do not have the execdir yet, analyze argv[0] and the PATH: */
                    173:        if (psExecDir[0] == 0)
                    174:        {
1.1.1.12  root      175:                if (strchr(argv0, PATHSEP) == NULL)
1.1       root      176:                {
                    177:                        /* No separator in argv[0], we have to explore PATH... */
                    178:                        Paths_GetExecDirFromPATH(argv0, psExecDir, FILENAME_MAX);
                    179:                }
                    180:                else
                    181:                {
                    182:                        /* There was a path separator in argv[0], so let's assume a
                    183:                         * relative or absolute path to the current directory in argv[0] */
                    184:                        char *p;
1.1.1.11  root      185:                        strlcpy(psExecDir, argv0, FILENAME_MAX);
1.1       root      186:                        p = strrchr(psExecDir, PATHSEP);  /* Search last slash */
                    187:                        if (p)
                    188:                                *p = 0;                       /* Strip file name from path */
                    189:                }
                    190:        }
                    191: 
                    192:        return psExecDir;
                    193: }
                    194: 
                    195: 
                    196: /**
                    197:  * Initialize the users home directory string
                    198:  * and Hatari's home directory (~/.hatari)
                    199:  */
                    200: static void Paths_InitHomeDirs(void)
                    201: {
                    202:        char *psHome;
                    203: 
                    204:        psHome = getenv("HOME");
1.1.1.8   root      205:        if (psHome)
1.1.1.14! root      206:        {
        !           207:                sUserHomeDir = Str_Dup(psHome);
        !           208:        }
1.1.1.8   root      209: #if defined(WIN32)
                    210:        else
1.1       root      211:        {
1.1.1.8   root      212:                char *psDrive;
                    213:                int len = 0;
1.1.1.6   root      214:                /* Windows home path? */
1.1.1.8   root      215:                psDrive = getenv("HOMEDRIVE");
                    216:                if (psDrive)
                    217:                        len = strlen(psDrive);
1.1.1.14! root      218:                psHome = getenv("HOMEPATH");
1.1.1.8   root      219:                if (psHome)
1.1.1.14! root      220:                        len += strlen(psHome);
        !           221:                if (len > 0)
        !           222:                {
        !           223:                        sUserHomeDir = Str_Alloc(len);
        !           224:                        if (psDrive)
        !           225:                                strcpy(sUserHomeDir, psDrive);
        !           226:                        if (psHome)
        !           227:                                strcat(sUserHomeDir, psHome);
        !           228:                }
1.1.1.6   root      229:        }
1.1.1.8   root      230: #endif
1.1.1.14! root      231:        if (!sUserHomeDir)
1.1.1.6   root      232:        {
1.1       root      233:                /* $HOME not set, so let's use current working dir as home */
1.1.1.14! root      234:                sUserHomeDir = Str_Dup(sWorkingDir);
        !           235:                sHatariHomeDir = Str_Dup(sWorkingDir);
1.1.1.12  root      236:                return;
1.1       root      237:        }
1.1.1.12  root      238: 
1.1.1.14! root      239:        sHatariHomeDir = Str_Alloc(strlen(sUserHomeDir) + 1 + strlen(HATARI_HOME_DIR));
1.1.1.12  root      240: 
                    241:        /* Try to use a private hatari directory in the users home directory */
1.1.1.14! root      242:        sprintf(sHatariHomeDir, "%s%c%s", sUserHomeDir, PATHSEP, HATARI_HOME_DIR);
1.1.1.12  root      243:        if (File_DirExists(sHatariHomeDir))
1.1       root      244:        {
1.1.1.12  root      245:                return;
                    246:        }
                    247:        /* Try legacy location ~/.hatari */
1.1.1.14! root      248:        sprintf(sHatariHomeDir, "%s%c.hatari", sUserHomeDir, PATHSEP);
1.1.1.12  root      249:        if (File_DirExists(sHatariHomeDir))
                    250:        {
                    251:                return;
                    252:        }
1.1       root      253: 
1.1.1.12  root      254:        /* Hatari home directory does not exists yet...
                    255:         * ... so let's try to create it: */
                    256: #if !defined(__MACOSX__) && !defined(WIN32)
1.1.1.14! root      257:        sprintf(sHatariHomeDir, "%s%c.config", sUserHomeDir, PATHSEP);
1.1.1.12  root      258:        if (!File_DirExists(sHatariHomeDir))
                    259:        {
                    260:                /* ~/.config does not exist yet, create it first */
1.1.1.13  root      261:                if (mkdir(sHatariHomeDir, 0700) != 0)
                    262:                {
                    263:                        perror("Failed to create ~/.config directory");
                    264:                }
1.1.1.12  root      265:        }
                    266: #endif
1.1.1.14! root      267:        sprintf(sHatariHomeDir, "%s%c%s", sUserHomeDir, PATHSEP, HATARI_HOME_DIR);
1.1.1.12  root      268:        if (mkdir(sHatariHomeDir, 0750) != 0)
                    269:        {
                    270:                /* Failed to create, so use user's home dir instead */
                    271:                strcpy(sHatariHomeDir, sUserHomeDir);
1.1       root      272:        }
                    273: }
                    274: 
                    275: 
                    276: /**
                    277:  * Initialize directory names
                    278:  *
                    279:  * The datadir will be initialized relative to the bindir (where the executable
                    280:  * has been installed to). This means a lot of additional effort since we first
                    281:  * have to find out where the executable is. But thanks to this effort, we get
                    282:  * a relocatable package (we don't have any absolute path names in the program)!
                    283:  */
1.1.1.3   root      284: void Paths_Init(const char *argv0)
1.1       root      285: {
                    286:        char *psExecDir;  /* Path string where the hatari executable can be found */
                    287: 
                    288:        /* Init working directory string */
1.1.1.14! root      289:        sWorkingDir = malloc(FILENAME_MAX);
        !           290:        if (!sWorkingDir || getcwd(sWorkingDir, FILENAME_MAX) == NULL)
1.1.1.5   root      291:        {
                    292:                /* This should never happen... just in case... */
1.1.1.14! root      293:                sWorkingDir = Str_Dup(".");
1.1.1.5   root      294:        }
1.1       root      295: 
                    296:        /* Init the user's home directory string */
                    297:        Paths_InitHomeDirs();
                    298: 
1.1.1.14! root      299:        /* Init screenshot directory string */
        !           300: #if !defined(__MACOSX__)
        !           301:        sScreenShotDir = Str_Dup(sWorkingDir);
        !           302: #else
        !           303:        sScreenShotDir = Paths_GetMacScreenShotDir();
        !           304:        if (!sScreenShotDir)
        !           305:        {
        !           306:                /* Failsafe, but should not be able to happen */
        !           307:                sScreenShotDir = Str_Dup(sWorkingDir);
        !           308:        }
        !           309: #endif
        !           310: 
1.1       root      311:        /* Get the directory where the executable resides */
                    312:        psExecDir = Paths_InitExecDir(argv0);
                    313: 
                    314:        /* Now create the datadir path name from the bindir path name: */
1.1.1.14! root      315:        sDataDir = Str_Alloc(FILENAME_MAX);
1.1       root      316:        if (psExecDir && strlen(psExecDir) > 0)
                    317:        {
1.1.1.14! root      318:                sprintf(sDataDir, "%s%c%s", psExecDir, PATHSEP, BIN2DATADIR);
1.1       root      319:        }
                    320:        else
                    321:        {
                    322:                /* bindir could not be determined, let's assume datadir is relative
                    323:                 * to current working directory... */
                    324:                strcpy(sDataDir, BIN2DATADIR);
                    325:        }
                    326: 
                    327:        /* And finally make a proper absolute path out of datadir: */
                    328:        File_MakeAbsoluteName(sDataDir);
                    329: 
                    330:        free(psExecDir);
                    331: 
1.1.1.14! root      332:        /* fprintf(stderr, " WorkingDir = %s\n DataDir = %s\n UserHomeDir = %s\n HatariHomeDir = %s\n ScrenShotDir = %s\n",
        !           333:                sWorkingDir, sDataDir, sUserHomeDir, sHatariHomeDir, sScreenShotDir); */
        !           334: }
        !           335: 
        !           336: void Paths_UnInit(void)
        !           337: {
        !           338:        Str_Free(sWorkingDir);
        !           339:        Str_Free(sDataDir);
        !           340:        Str_Free(sUserHomeDir);
        !           341:        Str_Free(sHatariHomeDir);
        !           342:        Str_Free(sScreenShotDir);
1.1       root      343: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.