1*11983Sslatteng /* @(#)path.c 1.2 04/18/83
211958Sslatteng *
311958Sslatteng * Copyright -C- 1982 Barry S. Roitblat
411958Sslatteng *
511958Sslatteng *
611958Sslatteng * This file contains routines that a) implement a path mechanism, whereby
711958Sslatteng * several places may be searched for files, and b) provide a defaulting
811958Sslatteng * mechanism for file name extensions.
911958Sslatteng *
1011958Sslatteng * (modified from code originally written by John Ousterhout for the caesar
1111958Sslatteng * design system)
1211958Sslatteng */
1311958Sslatteng
1411958Sslatteng #include "gremlin.h"
1511958Sslatteng #include <pwd.h>
1611958Sslatteng #include <ctype.h>
1711958Sslatteng
1811958Sslatteng /* Imports from config.c: */
1911958Sslatteng
2011958Sslatteng extern char GLibrary[];
2111958Sslatteng
2211958Sslatteng /* Library routines: */
2311958Sslatteng
2411958Sslatteng extern char *strcpy(), *strcpyn(), *index(), *sprintf(), *malloc();
2511958Sslatteng
2611958Sslatteng /* The following string holds the current path,which consists of a bunch
2711958Sslatteng * of directory names separated by spaces.
2811958Sslatteng */
2911958Sslatteng
3011958Sslatteng #define PATHSIZE 400
3111958Sslatteng static char path[PATHSIZE] = ".";
3211958Sslatteng
3311958Sslatteng /* The following string pointers constitute a cache of recently
3411958Sslatteng * referenced tilde names.
3511958Sslatteng */
3611958Sslatteng
3711958Sslatteng #define NTILDE 10
3811958Sslatteng static char *tildename[NTILDE] = {NULL, NULL, NULL, NULL, NULL,
3911958Sslatteng NULL, NULL, NULL, NULL, NULL};
4011958Sslatteng static char *realname[NTILDE] = {NULL, NULL, NULL, NULL, NULL,
4111958Sslatteng NULL, NULL, NULL, NULL, NULL};
4211958Sslatteng static int discard = 0;
4311958Sslatteng
44*11983Sslatteng
4511958Sslatteng int
PConvertTilde(psource,pdest,size)4611958Sslatteng PConvertTilde(psource, pdest, size)
4711958Sslatteng char **psource; /* Pointer to a pointer to the source string */
4811958Sslatteng char **pdest; /* Pointer to a pointer to the dest. string */
4911958Sslatteng int *size; /* Pointer to no. bytes available at pdest */
5011958Sslatteng
5111958Sslatteng /*---------------------------------------------------------
5211958Sslatteng * This routine converts tilde notation into standard directory names.
5311958Sslatteng *
5411958Sslatteng * Results:
5511958Sslatteng * If the conversion was done successfully, then TRUE is returned.
5611958Sslatteng * If a user name couldn't be found in the password file, then
5711958Sslatteng * FALSE is returned.
5811958Sslatteng *
5911958Sslatteng * Side Effects:
6011958Sslatteng * If the first character of the string indicated by psource is a
6111958Sslatteng * tilde ("~") then the subsequent user name is converted to a login
6211958Sslatteng * directory name and stored in the string indicated by pdest. Then
6311958Sslatteng * remaining characters in the file name at psource are copied to
6411958Sslatteng * pdest and both pointers are updated. Upon return, psource points
6511958Sslatteng * to the terminating character in the source file name and pdest
6611958Sslatteng * points to the next character after the last character in the file
6711958Sslatteng * name at that location. If a tilde cannot be converted because the
6811958Sslatteng * user name cannot be found, psource is still advanced past the current
6911958Sslatteng * entry, but pdest is unaffected. At most size characters will be
7011958Sslatteng * stored at pdest, and the size is decremented by the number of
7111958Sslatteng * characters we actually stored.
7211958Sslatteng *---------------------------------------------------------
7311958Sslatteng */
7411958Sslatteng
7511958Sslatteng {
7611958Sslatteng register char *ps, *pd;
7711958Sslatteng struct passwd *passwd, *getpwnam();
7811958Sslatteng char username[17], *string;
7911958Sslatteng int i, length;
8011958Sslatteng
8111958Sslatteng ps = *psource;
8211958Sslatteng if (*ps == '~')
8311958Sslatteng {
8411958Sslatteng /* Copy the user name into a string (at most 16 characters).
8511958Sslatteng * If we don't have a cached entry for this name, then
8611958Sslatteng * read the password file entry for the user and grab out
8711958Sslatteng * the login directory.
8811958Sslatteng */
8911958Sslatteng
9011958Sslatteng pd = username;
9111958Sslatteng for (i=0; ; i++)
9211958Sslatteng {
9311958Sslatteng *pd = *++ps;
9411958Sslatteng if (isspace(*pd) || (*pd=='\0') || (*pd=='/') || (*pd==':'))
9511958Sslatteng break;
9611958Sslatteng if (i < 16) pd++;
9711958Sslatteng }
9811958Sslatteng *pd = '\0';
9911958Sslatteng for (i=0; i<NTILDE; i++)
10011958Sslatteng {
10111958Sslatteng if (strcmp(tildename[i], username) == 0)
10211958Sslatteng {
10311958Sslatteng string = realname[i];
10411958Sslatteng goto gotname;
10511958Sslatteng }
10611958Sslatteng }
10711958Sslatteng
10811958Sslatteng /* Since we don't have a cached entry, read the password file
10911958Sslatteng * and make a new cache entry for this one. Note that this
11011958Sslatteng * means discarding an old entry.
11111958Sslatteng */
11211958Sslatteng
11311958Sslatteng passwd = getpwnam(username);
11411958Sslatteng string = passwd->pw_dir;
11511958Sslatteng if (passwd != NULL)
11611958Sslatteng {
11711958Sslatteng discard++;
11811958Sslatteng if (discard >= NTILDE) discard = 0;
11911958Sslatteng if (tildename[discard] != NULL)
12011958Sslatteng {
12111958Sslatteng free(tildename[discard]);
12211958Sslatteng free(realname[discard]);
12311958Sslatteng }
12411958Sslatteng tildename[discard] = malloc((unsigned) strlen(username)+1);
12511958Sslatteng strcpy(tildename[discard], username);
12611958Sslatteng realname[discard] = malloc((unsigned) strlen(string)+1);
12711958Sslatteng strcpy(realname[discard], string);
12811958Sslatteng }
12911958Sslatteng else
13011958Sslatteng
13111958Sslatteng /* The entry can't be found, so skip the source entry and return */
13211958Sslatteng
13311958Sslatteng {
13411958Sslatteng while ((*ps != '\0') && !isspace(*ps) && (*ps != ':')) ps++;
13511958Sslatteng *psource = ps;
13611958Sslatteng return FALSE;
13711958Sslatteng }
13811958Sslatteng gotname: length = strlen(string);
13911958Sslatteng if (length > *size) length = *size;
14011958Sslatteng strcpyn(*pdest, string, length);
14111958Sslatteng *size -= length;
14211958Sslatteng pd = *pdest+length;
14311958Sslatteng }
14411958Sslatteng else pd = *pdest;
14511958Sslatteng
14611958Sslatteng /* Copy the rest of the directory name from the source to the dest. */
14711958Sslatteng
14811958Sslatteng while ((*ps != '\0') && !isspace(*ps) && (*ps != ':'))
14911958Sslatteng if (*size > 0)
15011958Sslatteng {
15111958Sslatteng *pd++ = *ps++;
15211958Sslatteng (*size)--;
15311958Sslatteng }
15411958Sslatteng else ps++;
15511958Sslatteng *psource = ps;
15611958Sslatteng *pdest = pd;
15711958Sslatteng return TRUE;
15811958Sslatteng }
15911958Sslatteng
160*11983Sslatteng
16111958Sslatteng int
PSetPath(string)16211958Sslatteng PSetPath(string)
16311958Sslatteng char *string; /* Pointer to a string that is to become
16411958Sslatteng * the new fle search path. Must consist
16511958Sslatteng * of one or more directory names separated
16611958Sslatteng * by white space or colons. Two adjacent
16711958Sslatteng * colons are the same as ":.:". Tilde
16811958Sslatteng * notation is ok.
16911958Sslatteng */
17011958Sslatteng
17111958Sslatteng /*---------------------------------------------------------
17211958Sslatteng * PSetPath sets up the current search path.
17311958Sslatteng *
17411958Sslatteng * Results:
17511958Sslatteng * -1 is returned if one or more of the paths contained a tilde
17611958Sslatteng * notation that couldn't be converted. -2 is returned if the
17711958Sslatteng * path space was exhausted. Otherwise a value >= 0 is returned.
17811958Sslatteng *
17911958Sslatteng * Side Effects:
18011958Sslatteng * The string is stored as the current path, and all entries with
18111958Sslatteng * tilde notation are converted to non-tilde notation. Tilde entries
18211958Sslatteng * that cannot be converted are ignored. Note: only PATHSIZE total
18311958Sslatteng * bytes of path are stored, after tilde conversion. Excess bytes
18411958Sslatteng * are truncated.
18511958Sslatteng *---------------------------------------------------------
18611958Sslatteng */
18711958Sslatteng
18811958Sslatteng {
18911958Sslatteng int result, spaceleft;
19011958Sslatteng char *p;
19111958Sslatteng
19211958Sslatteng result = 0;
19311958Sslatteng spaceleft = PATHSIZE-1;
19411958Sslatteng p = path;
19511958Sslatteng
19611958Sslatteng if (*string == '\0')
19711958Sslatteng {
19811958Sslatteng path[0] = '.';
19911958Sslatteng path[1] = '\0';
20011958Sslatteng return 0;
20111958Sslatteng }
20211958Sslatteng
20311958Sslatteng while (*string != '\0')
20411958Sslatteng {
20511958Sslatteng if (*string == ':')
20611958Sslatteng if ((*++string == ':') && (spaceleft >= 2))
20711958Sslatteng {
20811958Sslatteng *p++ = '.';
20911958Sslatteng *p++ = ' ';
21011958Sslatteng spaceleft -= 2;
21111958Sslatteng }
21211958Sslatteng if (spaceleft <= 0) break;
21311958Sslatteng while ((*string == ':') || isspace(*string)) string++;
21411958Sslatteng if (!PConvertTilde(&string, &p, &spaceleft)) result = -1;
21511958Sslatteng else if (spaceleft-- > 0) *p++ = ' ';
21611958Sslatteng }
21711958Sslatteng *p = '\0';
21811958Sslatteng if (spaceleft < 2) return -2;
21911958Sslatteng return result;
22011958Sslatteng }
22111958Sslatteng
222*11983Sslatteng
22311958Sslatteng char *
PGetPath()22411958Sslatteng PGetPath()
22511958Sslatteng
22611958Sslatteng /*---------------------------------------------------------
22711958Sslatteng * This routine merely returns a poiner to the current path.
22811958Sslatteng *
22911958Sslatteng * Results:
23011958Sslatteng * The address of the current path (with all tildes expanded).
23111958Sslatteng *
23211958Sslatteng * Side Effects: None.
23311958Sslatteng *---------------------------------------------------------
23411958Sslatteng */
23511958Sslatteng
23611958Sslatteng {
23711958Sslatteng return path;
23811958Sslatteng }
23911958Sslatteng
240*11983Sslatteng
24111958Sslatteng FILE *
POpen(file,prealname,search)24211958Sslatteng POpen(file, prealname, search)
24311958Sslatteng char *file; /* Name of the file to be opened. */
24411958Sslatteng char **prealname; /* Pointer to a location that will be filled
24511958Sslatteng * in with the address of the real name of
24611958Sslatteng * the file that was successfully opened.
24711958Sslatteng * If NULL, then nothing is stored.
24811958Sslatteng */
24911958Sslatteng int search; /* If FALSE, then the search path business
25011958Sslatteng * doesn't happen. A default extension
25111958Sslatteng * will still be added.
25211958Sslatteng */
25311958Sslatteng
25411958Sslatteng /*---------------------------------------------------------
25511958Sslatteng * This routine does a file lookup using the current path and
25611958Sslatteng * supplying a default extension.
25711958Sslatteng *
25811958Sslatteng * Results:
25911958Sslatteng * A pointer to a FILE, or NULL if the file couldn't be found.
26011958Sslatteng *
26111958Sslatteng * Side Effects:
26211958Sslatteng * If the first character of the
26311958Sslatteng * file name is "~" or "/" or if search is FALSE, then we try
26411958Sslatteng * to look up the file with the original name, doing tilde
26511958Sslatteng * expansion of course and returning that result. If none of
26611958Sslatteng * these conditions is met, we go through the current path
26711958Sslatteng * trying to look up the file once for each path
26811958Sslatteng * entry by prepending the path entry to the original file name.
26911958Sslatteng * This concatenated name is stored in a static string and made
27011958Sslatteng * available to the caller through prealname if the open succeeds.
27111958Sslatteng * Note: the static string will be trashed on the next call to this
27211958Sslatteng * routine. Also, note that no individual file name is allowed to
27311958Sslatteng * be more than NAMESIZE characters long. Excess characters are lost.
27411958Sslatteng *---------------------------------------------------------
27511958Sslatteng */
27611958Sslatteng
27711958Sslatteng {
27811958Sslatteng #define NAMESIZE 50
27911958Sslatteng static char realname[NAMESIZE];
28011958Sslatteng char extendedname[NAMESIZE], *p, *p2;
28111958Sslatteng int length, spaceleft, size;
28211958Sslatteng FILE *f;
28311958Sslatteng
28411958Sslatteng if (file == NULL) return (FILE *) NULL;
28511958Sslatteng if (file[0] == '\0') return (FILE *) NULL;
28611958Sslatteng
28711958Sslatteng if (prealname != NULL) *prealname = realname;
28811958Sslatteng
28911958Sslatteng /* Now try the original name. If it starts with a ~ or / look
29011958Sslatteng * it up directly.
29111958Sslatteng */
29211958Sslatteng
29311958Sslatteng if (file[0] == '~')
29411958Sslatteng {
29511958Sslatteng p = realname;
29611958Sslatteng length = NAMESIZE-1;
29711958Sslatteng if (!PConvertTilde(&file, &p, &length)) return NULL;
29811958Sslatteng *p = '\0';
29911958Sslatteng return fopen(realname, "r");
30011958Sslatteng }
30111958Sslatteng
30211958Sslatteng if ((file[0] == '/') || (search == FALSE))
30311958Sslatteng {
30411958Sslatteng strcpyn(realname, file, NAMESIZE-1);
30511958Sslatteng realname[NAMESIZE-1] = '\0';
30611958Sslatteng return fopen(realname, "r");
30711958Sslatteng }
30811958Sslatteng
30911958Sslatteng /* Now try going through the path. */
31011958Sslatteng
31111958Sslatteng p = path;
31211958Sslatteng while (*p != '\0')
31311958Sslatteng {
31411958Sslatteng spaceleft = NAMESIZE-1;
31511958Sslatteng p2 = realname;
31611958Sslatteng while (isspace(*p)) p++;
31711958Sslatteng while ((*p != '\0') && !isspace(*p))
31811958Sslatteng if (spaceleft-- > 0) *p2++ = *p++;
31911958Sslatteng else p++;
32011958Sslatteng if (spaceleft-- > 0) *p2++ = '/';
32111958Sslatteng if (spaceleft > 0) strcpyn(p2, file, spaceleft);
32211958Sslatteng realname[NAMESIZE-1] = '\0';
32311958Sslatteng f = fopen(realname, "r");
32411958Sslatteng if (f != NULL) return f;
32511958Sslatteng }
32611958Sslatteng
32711958Sslatteng /* We've tried the path and that didn't work. As a last shot,
32811958Sslatteng * try the library area. Only use the library for reads.
32911958Sslatteng */
33011958Sslatteng
33111958Sslatteng p = GLibrary;
33211958Sslatteng p2 = realname;
33311958Sslatteng size = NAMESIZE;
33411958Sslatteng if (!PConvertTilde(&p, &p2, &size)) return FALSE;
33511958Sslatteng (void) strcpyn(p2, file, size);
33611958Sslatteng realname[NAMESIZE-1] = '\0';
33711958Sslatteng return fopen(realname, "r");
33811958Sslatteng }
339