/***************************************************************** * SQUID - a library of functions for biological sequence analysis * Copyright (C) 1992-2002 Washington University School of Medicine * * This source code is freely distributed under the terms of the * GNU General Public License. See the files COPYRIGHT and LICENSE * for details. *****************************************************************/ /* file.c * SRE, Wed Jun 19 11:19:22 1996 * * File operation utilities, dealing with pathnames, directories, * and environment variables. * * The goal is to have these be platform-independent but they * currently are UNIX-specific: i.e. this file is currently POSIX compliant * but it is NOT ANSI C compliant. (The sole offender is getenv().) * * RCS $Id: file.c 217 2011-03-19 10:27:10Z andreas $ (Original squid RCS Id: file.c,v 1.8 2002/03/07 03:18:02 eddy Exp) */ #include #include #include #include "squid.h" #include "sqfuncs.h" /* * VMS: #define DIRSLASH ']' * MacOS: #define DIRSLASH ':' * DOS: #define DIRSLASH '\\' * * The code assumes that '.' is used for file name extensions, * such as "foo.bar". */ #define DIRSLASH '/' /* UNIX directory paths have /foo/bar */ /* Function: FileDirname() * * Purpose: Returns the path from a filename: * "/foo/bar/baz" -> "/foo/bar" * "foo/bar" -> "foo" * "foo" -> "." * "/" -> "/" * i.e. the string will be non-NULL; it will * contain the string up to but not including the * last '/' character; returns "." if * there are no '/' characters, and returns "/" * if the last slash is the first character. * Modeled on Tcl's "file dirname" command. * * Args: file - name of file "/foo/bar/baz". * * Return: ptr to malloc'ed string "/foo/bar". */ char * FileDirname(char *file) { char *dirname; char *lastslash; int len; lastslash = strrchr(file, DIRSLASH); len = (lastslash == NULL) ? 0 : (int) (lastslash - file); dirname = (char *) MallocOrDie (sizeof(char) * (len+2)); if (len > 0) strncpy(dirname, file, len); else if (*file != DIRSLASH) { *dirname = '.'; len = 1; } else { *dirname = DIRSLASH; len = 1; } dirname[len] = '\0'; return dirname; } /* Function: FileTail() * * Purpose: Return everything after the DIRSLASH: * "/foo/bar/baz.1" -> "baz.1" * "foo/bar" -> "bar" * "foo" -> "foo" * "/" -> "" * If noextension is TRUE, removes a trailing ".foo" extension * too. * * Args: file - name of file "/foo/bar/baz.1" * noextension - TRUE to also remove extensions * * Return: ptr to malloc'ed string "baz.1" */ char * FileTail(char *file, int noextension) { char *tail; char *lastslash; char *lastdot; /* remove directory prefix */ lastslash = strrchr(file, DIRSLASH); tail = (char *) MallocOrDie (sizeof(char) * (strlen(file)+1)); if (lastslash == NULL) strcpy(tail, file); else strcpy(tail, lastslash+1); /* remove trailing suffix */ if (noextension) { if ((lastdot = strrchr(tail, '.')) != NULL) *lastdot = '\0'; } return tail; } /* Function: FileSameDirectory() * Date: SRE, Wed Mar 6 20:03:23 2002 [St. Louis] * * Purpose: Given a path to one file, and the * name of another file in the same directory, * concat the path from file1 onto file2, and * return the result. Caller must free the ptr * that's returned. * * Written for SSI - SSI indices contain filenames * without paths, and we will need to convert that * to a full path. * * Args: file1 - a path to a file, e.g. "/foo/bar/baz.1" * file2 - a simple filename, e.g. "quux.2" * * Returns: path to file2: e.g. "/foo/bar/quux.2" * Returns NULL if file2 already has a path, and the result * would be a different place. */ char * FileSameDirectory(char *file1, char *file2) { char *path; char *tail; char *result; int seems_ok = 1; path = FileDirname(file1); tail = FileTail(file2, FALSE); if (strcmp(file2, tail) != 0) seems_ok = 0; /* ut-oh, file2 *had* a path */ result = FileConcat(path, tail); if (! seems_ok && strcmp(result, file2) != 0) { free(result); result = NULL; } free(path); free(tail); return result; } /* Function: FileConcat() * * Purpose: Concatenate a directory path and a file name, * returning a pointer to a malloc'ed string with the * full filename. This isn't just a string concat, * because we're careful about the dir slash. */ char * FileConcat(char *dir, char *file) { char *full; full = (char *) MallocOrDie (sizeof(char) * (strlen(dir)+strlen(file)+2)); if (*file == DIRSLASH) strcpy(full, file); /* file = "/foo", ignore directory. */ else sprintf(full, "%s%c%s", dir, DIRSLASH, file); return full; } /* Function: FileAddSuffix() * Date: SRE, Wed Aug 1 11:19:33 2001 [Pasadena] * * Purpose: Add a suffix to a filename, return a malloc'ed * string containing the new filename.sfx name. * Example: * FileAddSuffix("genbank", "ssi") * returns "genbank.ssi". */ char * FileAddSuffix(char *filename, char *sfx) { char *new; new = MallocOrDie(strlen(filename) + strlen(sfx) + 2); sprintf(new, "%s.%s", filename, sfx); return new; } /* Function: EnvFileOpen() * Date: Sun Feb 12 10:55:29 1995 * * Purpose: Open a file, given a file name and an environment * variable that contains a directory path. Files * are opened read-only. Does not look at current directory * unless "." is explicitly in the path specified by env. * * For instance: * fp = EnvFileOpen("BLOSUM45", "BLASTMAT", NULL); * or: * fp = EnvFileOpen("swiss", "BLASTDB", NULL); * * Environment variables may contain a colon-delimited * list of more than one path; e.g. * setenv BLASTDB /nfs/databases/foo:/nfs/databases/bar * * Sometimes a group of files may be found in * one directory; for instance, an index file with a * database. The caller can EnvFileOpen() the main * file, and ask to get the name of the * directory back in ret_dir, so it can construct * the other auxiliary file names and fopen() them. (If it called * EnvFileOpen(), it might get confused by * file name clashes and open files in different * directories. * * Args: fname - name of file to open * env - name of environment variable containing path * ret_dir - if non-NULL, RETURN: name of dir that was used. * * Return: FILE * to open file, or NULL on failure -- same as fopen() * Caller must free ret_dir if it passed a non-NULL address. */ FILE * EnvFileOpen(char *fname, char *env, char **ret_dir) { FILE *fp; char *path; char *s; /* ptr to indiv element in env list */ char full[1024]; /* constructed file name */ if (env == NULL) return NULL; if ((path = Strdup(getenv(env))) == NULL) return NULL; fp = NULL; s = strtok(path, ":"); while (s != NULL) { if (((int) strlen(fname) + (int) strlen(s) + 2) > 1024) { free(path); return NULL; } sprintf(full, "%s%c%s", s, DIRSLASH, fname); if ((fp = fopen(full, "r")) != NULL) break; s = strtok(NULL, ":"); } /* Return the path we used, if caller wants it */ if (ret_dir != NULL) *ret_dir = Strdup(s); free(path); return fp; } /* Function: FileExists() * * Purpose: Return TRUE if filename exists. * Testing fopen() is the only possible platform-independent test * I'm aware of. */ int FileExists(char *filename) { FILE *fp; if ((fp = fopen(filename, "r"))) { fclose(fp); return TRUE; } return FALSE; }