1*115427c0Sopcode /*
2*115427c0Sopcode * @(#)path.c 1.1 10/21/84
3*115427c0Sopcode *
4*115427c0Sopcode * These routines implement a path mechanism for the SUN Gremlin
5*115427c0Sopcode * picture editor. It provides facilities whereby several directories
6*115427c0Sopcode * may be searched for files and a defaulting mechanism for file name
7*115427c0Sopcode * extensions.
8*115427c0Sopcode *
9*115427c0Sopcode * Mark Opperman (opcode@monet.BERKELEY)
10*115427c0Sopcode *
11*115427c0Sopcode */
12*115427c0Sopcode
13*115427c0Sopcode #include "gremlin.h"
14*115427c0Sopcode #include <pwd.h>
15*115427c0Sopcode #include <ctype.h>
16*115427c0Sopcode
17*115427c0Sopcode /* imports from main.c */
18*115427c0Sopcode
19*115427c0Sopcode extern char GLibrary[];
20*115427c0Sopcode
21*115427c0Sopcode /* imports from C */
22*115427c0Sopcode
23*115427c0Sopcode extern char *strcpy();
24*115427c0Sopcode extern char *strncpy();
25*115427c0Sopcode extern char *index();
26*115427c0Sopcode extern char *sprintf();
27*115427c0Sopcode extern char *malloc();
28*115427c0Sopcode
29*115427c0Sopcode /*
30*115427c0Sopcode * The following string holds the current path, consisting of a bunch
31*115427c0Sopcode * of directory names separated by spaces.
32*115427c0Sopcode */
33*115427c0Sopcode
34*115427c0Sopcode #define PATHSIZE 400
35*115427c0Sopcode
36*115427c0Sopcode static char path[PATHSIZE] = ".";
37*115427c0Sopcode
38*115427c0Sopcode /*
39*115427c0Sopcode * The following string pointers constitute a cache of recently
40*115427c0Sopcode * referenced tilde names.
41*115427c0Sopcode */
42*115427c0Sopcode
43*115427c0Sopcode #define NTILDE 10
44*115427c0Sopcode
45*115427c0Sopcode static char *tildename[NTILDE] = { NULL, NULL, NULL, NULL, NULL,
46*115427c0Sopcode NULL, NULL, NULL, NULL, NULL };
47*115427c0Sopcode static char *realname[NTILDE] = { NULL, NULL, NULL, NULL, NULL,
48*115427c0Sopcode NULL, NULL, NULL, NULL, NULL };
49*115427c0Sopcode static int discard = 0;
50*115427c0Sopcode
51*115427c0Sopcode
52*115427c0Sopcode /*
53*115427c0Sopcode * This routine converts tilde notation into standard directory names.
54*115427c0Sopcode *
55*115427c0Sopcode * If the conversion was done successfully, then TRUE is returned.
56*115427c0Sopcode * If a user name couldn't be found in the password file, then
57*115427c0Sopcode * FALSE is returned.
58*115427c0Sopcode *
59*115427c0Sopcode * If the first character of the string indicated by psource is a
60*115427c0Sopcode * tilde ("~") then the subsequent user name is converted to a login
61*115427c0Sopcode * directory name and stored in the string indicated by pdest. Then
62*115427c0Sopcode * remaining characters in the file name at psource are copied to
63*115427c0Sopcode * pdest and both pointers are updated. Upon return, psource points
64*115427c0Sopcode * to the terminating character in the source file name and pdest
65*115427c0Sopcode * points to the next character after the last character in the file
66*115427c0Sopcode * name at that location. If a tilde cannot be converted because the
67*115427c0Sopcode * user name cannot be found, psource is still advanced past the current
68*115427c0Sopcode * entry, but pdest is unaffected. At most size characters will be
69*115427c0Sopcode * stored at pdest, and the size is decremented by the number of
70*115427c0Sopcode * characters we actually stored.
71*115427c0Sopcode *
72*115427c0Sopcode * mro 7/28/84
73*115427c0Sopcode * fixed NULL pointer bugs
74*115427c0Sopcode */
PConvertTilde(psource,pdest,size)75*115427c0Sopcode PConvertTilde(psource, pdest, size)
76*115427c0Sopcode char **psource; /* Pointer to a pointer to the source string */
77*115427c0Sopcode char **pdest; /* Pointer to a pointer to the dest. string */
78*115427c0Sopcode int *size; /* Pointer to no. bytes available at pdest */
79*115427c0Sopcode {
80*115427c0Sopcode register char *ps, *pd;
81*115427c0Sopcode struct passwd *passwd, *getpwnam();
82*115427c0Sopcode char username[17], *string;
83*115427c0Sopcode int i, length;
84*115427c0Sopcode
85*115427c0Sopcode ps = *psource;
86*115427c0Sopcode string = NULL;
87*115427c0Sopcode
88*115427c0Sopcode if (*ps == '~') {
89*115427c0Sopcode /* Copy the user name into a string (at most 16 characters). If we
90*115427c0Sopcode don't have a cached entry for this name, then read the password
91*115427c0Sopcode file entry for the user and grab out the login directory. */
92*115427c0Sopcode
93*115427c0Sopcode pd = username;
94*115427c0Sopcode for (i=0; ; i++) {
95*115427c0Sopcode *pd = *++ps;
96*115427c0Sopcode if (isspace(*pd) || (*pd == '\0') || (*pd == '/') || (*pd == ':'))
97*115427c0Sopcode break;
98*115427c0Sopcode if (i < 16)
99*115427c0Sopcode pd++;
100*115427c0Sopcode }
101*115427c0Sopcode
102*115427c0Sopcode *pd = '\0';
103*115427c0Sopcode for (i=0; i<NTILDE; i++) {
104*115427c0Sopcode if (tildename[i] != NULL) {
105*115427c0Sopcode if (strcmp(tildename[i], username) == 0) {
106*115427c0Sopcode string = realname[i];
107*115427c0Sopcode break;
108*115427c0Sopcode }
109*115427c0Sopcode }
110*115427c0Sopcode }
111*115427c0Sopcode
112*115427c0Sopcode if (string == NULL) { /* didn't find cached entry */
113*115427c0Sopcode passwd = getpwnam(username); /* check password file */
114*115427c0Sopcode if (passwd != NULL) { /* got it! */
115*115427c0Sopcode string = passwd->pw_dir;
116*115427c0Sopcode if (++discard >= NTILDE)
117*115427c0Sopcode discard = 0;
118*115427c0Sopcode if (tildename[discard] != NULL) {
119*115427c0Sopcode free(tildename[discard]);
120*115427c0Sopcode free(realname[discard]);
121*115427c0Sopcode }
122*115427c0Sopcode tildename[discard] = malloc((unsigned) strlen(username)+1);
123*115427c0Sopcode strcpy(tildename[discard], username);
124*115427c0Sopcode realname[discard] = malloc((unsigned) strlen(string)+1);
125*115427c0Sopcode strcpy(realname[discard], string);
126*115427c0Sopcode }
127*115427c0Sopcode else { /* illegal user name */
128*115427c0Sopcode /* skip the source entry and return */
129*115427c0Sopcode while ((*ps != '\0') && !isspace(*ps) && (*ps != ':'))
130*115427c0Sopcode ps++;
131*115427c0Sopcode *psource = ps;
132*115427c0Sopcode return(FALSE);
133*115427c0Sopcode }
134*115427c0Sopcode }
135*115427c0Sopcode
136*115427c0Sopcode length = strlen(string);
137*115427c0Sopcode if (length > *size)
138*115427c0Sopcode length = *size;
139*115427c0Sopcode strncpy(*pdest, string, length);
140*115427c0Sopcode *size -= length;
141*115427c0Sopcode pd = *pdest+length;
142*115427c0Sopcode }
143*115427c0Sopcode else
144*115427c0Sopcode pd = *pdest;
145*115427c0Sopcode
146*115427c0Sopcode /* Copy the rest of the directory name from the source to the dest. */
147*115427c0Sopcode
148*115427c0Sopcode while ((*ps != '\0') && !isspace(*ps) && (*ps != ':'))
149*115427c0Sopcode if (*size > 0) {
150*115427c0Sopcode *pd++ = *ps++;
151*115427c0Sopcode (*size)--;
152*115427c0Sopcode }
153*115427c0Sopcode else
154*115427c0Sopcode ps++;
155*115427c0Sopcode *psource = ps;
156*115427c0Sopcode *pdest = pd;
157*115427c0Sopcode return(TRUE);
158*115427c0Sopcode }
159*115427c0Sopcode
160*115427c0Sopcode
161*115427c0Sopcode /*
162*115427c0Sopcode * PSetPath sets up the current search path.
163*115427c0Sopcode *
164*115427c0Sopcode * (-1) is returned if one or more of the paths contained a tilde
165*115427c0Sopcode * notation that couldn't be converted. (-2) is returned if the
166*115427c0Sopcode * path space was exhausted. Otherwise, a value >= 0 is returned.
167*115427c0Sopcode *
168*115427c0Sopcode * The string is stored as the current path, and all entries with
169*115427c0Sopcode * tilde notation are converted to non-tilde notation. Tilde entries
170*115427c0Sopcode * that cannot be converted are ignored. Note: only PATHSIZE total
171*115427c0Sopcode * bytes of path are stored, after tilde conversion. Excess bytes
172*115427c0Sopcode * are truncated.
173*115427c0Sopcode */
PSetPath(string)174*115427c0Sopcode PSetPath(string)
175*115427c0Sopcode char *string; /* Pointer to a string that is to become the new file
176*115427c0Sopcode search path. Must consist of one or more directory
177*115427c0Sopcode names separated by white space or colons. Two adjacent
178*115427c0Sopcode colons are the same as ":.:". Tilde notation is ok. */
179*115427c0Sopcode {
180*115427c0Sopcode int result, spaceleft;
181*115427c0Sopcode char *p;
182*115427c0Sopcode
183*115427c0Sopcode result = 0;
184*115427c0Sopcode spaceleft = PATHSIZE-1;
185*115427c0Sopcode p = path;
186*115427c0Sopcode
187*115427c0Sopcode if (*string == '\0') {
188*115427c0Sopcode strcpy(path, ".");
189*115427c0Sopcode return(0);
190*115427c0Sopcode }
191*115427c0Sopcode
192*115427c0Sopcode while (*string != '\0') {
193*115427c0Sopcode if (*string == ':')
194*115427c0Sopcode if ((*++string == ':') && (spaceleft >= 2)) {
195*115427c0Sopcode *p++ = '.';
196*115427c0Sopcode *p++ = ' ';
197*115427c0Sopcode spaceleft -= 2;
198*115427c0Sopcode }
199*115427c0Sopcode if (spaceleft <= 0)
200*115427c0Sopcode break;
201*115427c0Sopcode while ((*string == ':') || isspace(*string))
202*115427c0Sopcode string++;
203*115427c0Sopcode if (!PConvertTilde(&string, &p, &spaceleft))
204*115427c0Sopcode result = -1;
205*115427c0Sopcode else if (spaceleft-- > 0)
206*115427c0Sopcode *p++ = ' ';
207*115427c0Sopcode }
208*115427c0Sopcode *p = '\0';
209*115427c0Sopcode
210*115427c0Sopcode if (spaceleft < 2)
211*115427c0Sopcode return(-2);
212*115427c0Sopcode
213*115427c0Sopcode return(result);
214*115427c0Sopcode }
215*115427c0Sopcode
216*115427c0Sopcode
217*115427c0Sopcode /*
218*115427c0Sopcode * This routine merely returns a poiner to the current path.
219*115427c0Sopcode */
220*115427c0Sopcode char *
PGetPath()221*115427c0Sopcode PGetPath()
222*115427c0Sopcode {
223*115427c0Sopcode return(path);
224*115427c0Sopcode }
225*115427c0Sopcode
226*115427c0Sopcode
227*115427c0Sopcode /*
228*115427c0Sopcode * This routine does a file lookup using the current path and
229*115427c0Sopcode * supplying a default extension.
230*115427c0Sopcode *
231*115427c0Sopcode * Returns a pointer to a FILE, or NULL if the file couldn't be found.
232*115427c0Sopcode *
233*115427c0Sopcode * If the first character of the
234*115427c0Sopcode * file name is "~" or "/" or if search is FALSE, then we try
235*115427c0Sopcode * to look up the file with the original name, doing tilde
236*115427c0Sopcode * expansion of course and returning that result. If none of
237*115427c0Sopcode * these conditions is met, we go through the current path
238*115427c0Sopcode * trying to look up the file once for each path
239*115427c0Sopcode * entry by prepending the path entry to the original file name.
240*115427c0Sopcode * This concatenated name is stored in a static string and made
241*115427c0Sopcode * available to the caller through prealname if the open succeeds.
242*115427c0Sopcode * Note: the static string will be trashed on the next call to this
243*115427c0Sopcode * routine. Also, note that no individual file name is allowed to
244*115427c0Sopcode * be more than NAMESIZE characters long. Excess characters are lost.
245*115427c0Sopcode */
246*115427c0Sopcode FILE *
POpen(file,prealname,search)247*115427c0Sopcode POpen(file, prealname, search)
248*115427c0Sopcode char *file; /* Name of the file to be opened. */
249*115427c0Sopcode char **prealname; /* Pointer to a location that will be filled
250*115427c0Sopcode in with the address of the real name of
251*115427c0Sopcode the file that was successfully opened.
252*115427c0Sopcode If NULL, then nothing is stored. */
253*115427c0Sopcode int search; /* If FALSE, then the search path business
254*115427c0Sopcode doesn't happen. A default extension
255*115427c0Sopcode will still be added. */
256*115427c0Sopcode {
257*115427c0Sopcode #define NAMESIZE 128
258*115427c0Sopcode static char realname[NAMESIZE];
259*115427c0Sopcode char extendedname[NAMESIZE], *p, *p2;
260*115427c0Sopcode int length, spaceleft, size;
261*115427c0Sopcode FILE *f;
262*115427c0Sopcode
263*115427c0Sopcode if ((file == NULL) || (file[0] == '\0'))
264*115427c0Sopcode return((FILE *) NULL);
265*115427c0Sopcode
266*115427c0Sopcode if (prealname != NULL)
267*115427c0Sopcode *prealname = realname;
268*115427c0Sopcode
269*115427c0Sopcode /* Now try the original name. If it starts with a ~ or / look
270*115427c0Sopcode it up directly. */
271*115427c0Sopcode
272*115427c0Sopcode if (file[0] == '~') {
273*115427c0Sopcode p = realname;
274*115427c0Sopcode length = NAMESIZE-1;
275*115427c0Sopcode if (!PConvertTilde(&file, &p, &length))
276*115427c0Sopcode return(NULL);
277*115427c0Sopcode *p = '\0';
278*115427c0Sopcode return(fopen(realname, "r"));
279*115427c0Sopcode }
280*115427c0Sopcode
281*115427c0Sopcode if ((file[0] == '/') || (search == FALSE)) {
282*115427c0Sopcode strncpy(realname, file, NAMESIZE-1);
283*115427c0Sopcode realname[NAMESIZE-1] = '\0';
284*115427c0Sopcode return(fopen(realname, "r"));
285*115427c0Sopcode }
286*115427c0Sopcode
287*115427c0Sopcode /* Now try going through the path. */
288*115427c0Sopcode
289*115427c0Sopcode p = path;
290*115427c0Sopcode while (*p != '\0') {
291*115427c0Sopcode spaceleft = NAMESIZE-1;
292*115427c0Sopcode p2 = realname;
293*115427c0Sopcode while (isspace(*p))
294*115427c0Sopcode p++;
295*115427c0Sopcode while ((*p != '\0') && !isspace(*p)) {
296*115427c0Sopcode if (spaceleft-- > 0)
297*115427c0Sopcode *p2++ = *p++;
298*115427c0Sopcode else
299*115427c0Sopcode p++;
300*115427c0Sopcode }
301*115427c0Sopcode if (spaceleft-- > 0)
302*115427c0Sopcode *p2++ = '/';
303*115427c0Sopcode if (spaceleft > 0)
304*115427c0Sopcode strncpy(p2, file, spaceleft);
305*115427c0Sopcode realname[NAMESIZE-1] = '\0';
306*115427c0Sopcode f = fopen(realname, "r");
307*115427c0Sopcode if (f != NULL) {
308*115427c0Sopcode /* if file in current directory fix up prealname */
309*115427c0Sopcode if ((strncmp(realname, "./", 2) == 0) && (prealname != NULL))
310*115427c0Sopcode (*prealname) += 2;
311*115427c0Sopcode return(f);
312*115427c0Sopcode }
313*115427c0Sopcode }
314*115427c0Sopcode
315*115427c0Sopcode /* We've tried the path and that didn't work. As a last shot,
316*115427c0Sopcode try the library area. Only use the library for reads. */
317*115427c0Sopcode
318*115427c0Sopcode p = GLibrary;
319*115427c0Sopcode p2 = realname;
320*115427c0Sopcode size = NAMESIZE;
321*115427c0Sopcode if (!PConvertTilde(&p, &p2, &size))
322*115427c0Sopcode return(FALSE);
323*115427c0Sopcode (void) strncpy(p2, file, size);
324*115427c0Sopcode realname[NAMESIZE-1] = '\0';
325*115427c0Sopcode return(fopen(realname, "r"));
326*115427c0Sopcode }
327