Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / miscellany / less-177 / filename.c
1 /*
2  * Routines to mess around with filenames (and files).
3  * Much of this is very OS dependent.
4  */
5
6 #include <stdio.h>
7 #include "less.h"
8
9 extern char *getenv();
10
11 extern int force_open;
12 extern IFILE curr_ifile;
13 extern IFILE old_ifile;
14
15 /*
16  * Return the full pathname of the given file in the "home directory".
17  */
18         public char *
19 homefile(filename)
20         char *filename;
21 {
22         register char *pathname;
23         register char *homedir;
24
25         homedir = getenv("HOME");
26 #if __MSDOS__
27         /*
28          * Most MSDOS users do not have $HOME defined,
29          * so if no $HOME then look for "_less" anywhere 
30          * on search path (always begins at current directory).
31          */
32         if (homedir == NULL)
33         {
34                 extern char *searchpath();
35                 pathname = searchpath(filename);
36                 if (pathname == NULL)
37                         return (NULL);
38                 pathname = save(pathname);
39         } else
40         {
41                 pathname = (char *) calloc(strlen(homedir)+strlen(filename)+2, 
42                                         sizeof(char));
43                 if (pathname == NULL)
44                         return (NULL);
45                 sprintf(pathname, "%s\\%s", homedir, filename);
46         }
47 #else
48         if (homedir == NULL)
49                 return (NULL);
50         pathname = (char *) calloc(strlen(homedir)+strlen(filename)+2,
51                                 sizeof(char));
52         if (pathname == NULL)
53                 return (NULL);
54         sprintf(pathname, "%s/%s", homedir, filename);
55 #endif
56         return (pathname);
57 }
58
59 /*
60  * Find out where the help file is.
61  */
62         public char *
63 find_helpfile()
64 {
65         register char *helpfile;
66 #if __MSDOS__
67         extern char *searchpath();
68
69         /*
70          * Look in current directory.
71          */
72         if (access(HELPFILE,0) == 0)
73                 return (HELPFILE);
74         /*
75          * Find the basename of HELPFILE,
76          * and look for it in each directory in the search path.
77          */
78         if ((helpfile = strrchr(HELPFILE, '\\')) == NULL)
79                 helpfile = HELPFILE;
80         else
81                 helpfile++;
82         return (save(searchpath(helpfile)));
83 #else
84         if ((helpfile = getenv("LESSHELP")) != NULL)
85                 return (save(helpfile));
86         return (save(HELPFILE));
87 #endif
88 }
89
90 /*
91  * Expand a string, substituting any "%" with the current filename,
92  * and any "#" with the previous filename.
93  */
94         public char *
95 fexpand(s)
96         char *s;
97 {
98         register char *fr, *to;
99         register int n;
100         register char *e;
101
102         /*
103          * Make one pass to see how big a buffer we 
104          * need to allocate for the expanded string.
105          */
106         n = 0;
107         for (fr = s;  *fr != '\0';  fr++)
108         {
109                 switch (*fr)
110                 {
111                 case '%':
112                         n += strlen(get_filename(curr_ifile));
113                         break;
114                 case '#':
115                         if (old_ifile == NULL_IFILE)
116                         {
117                                 error("No previous file", NULL_PARG);
118                                 return (NULL);
119                         }
120                         n += strlen(get_filename(old_ifile));
121                         break;
122                 default:
123                         n++;
124                         break;
125                 }
126         }
127
128         e = (char *) ecalloc(n+1, sizeof(char));
129
130         /*
131          * Now copy the string, expanding any "%" or "#".
132          */
133         to = e;
134         for (fr = s;  *fr != '\0';  fr++)
135         {
136                 switch (*fr)
137                 {
138                 case '%':
139                         strcpy(to, get_filename(curr_ifile));
140                         to += strlen(to);
141                         break;
142                 case '#':
143                         strcpy(to, get_filename(old_ifile));
144                         to += strlen(to);
145                         break;
146                 default:
147                         *to++ = *fr;
148                         break;
149                 }
150         }
151         *to = '\0';
152         return (e);
153 }
154
155 /*
156  * Try to determine if a file is "binary".
157  * This is just a guess, and we need not try too hard to make it accurate.
158  */
159         int
160 bin_file(f)
161         int f;
162 {
163         int i;
164         int n;
165         char data[64];
166
167         n = read(f, data, sizeof(data));
168         for (i = 0;  i < n;  i++)
169                 if (binary_char(data[i]))
170                         return (1);
171         return (0);
172 }
173
174 /*
175  * Try to determine the size of a file by seeking to the end.
176  */
177         static POSITION
178 seek_filesize(f)
179         int f;
180 {
181         offset_t spos;
182
183         spos = lseek(f, (offset_t)0, 2);
184         if (spos == BAD_LSEEK)
185                 return (NULL_POSITION);
186         return ((POSITION) spos);
187 }
188
189 /*
190  * Expand a filename, substituting any environment variables, etc.
191  */
192 #if GLOB
193
194 FILE *popen();
195
196         public char *
197 glob(filename)
198         char *filename;
199 {
200         FILE *f;
201         char *p;
202         int ch;
203         int len;
204         char *cmd;
205         char *gfilename;
206
207         filename = fexpand(filename);
208         if (filename == NULL)
209                 return (NULL);
210
211         /*
212          * We get the shell to expand the filename for us by passing
213          * an "echo" command to the shell and reading its output.
214          */
215         p = getenv("SHELL");
216         if (p == NULL || *p == '\0')
217         {
218                 /*
219                  * Read the output of <echo filename>.
220                  */
221                 cmd = (char *) ecalloc(strlen(filename)+6, sizeof(char));
222                 sprintf(cmd, "echo %s", filename);
223         } else
224         {
225                 /*
226                  * Read the output of <$SHELL -c "echo filename">.
227                  */
228                 cmd = (char *) ecalloc(strlen(p)+strlen(filename)+12, sizeof(char));
229                 sprintf(cmd, "%s -c \"echo %s\"", p, filename);
230         }
231
232         f = popen(cmd, "r");
233         free(cmd);
234         if (f == NULL)
235                 return (filename);
236         free(filename);
237
238         len = 100;
239         gfilename = (char *) ecalloc(len, sizeof(char));
240         for (p = gfilename;  ;  p++)
241         {
242                 if ((ch = getc(f)) == '\n' || ch == EOF)
243                         break;
244                 if (p - gfilename >= len-1)
245                 {
246                         len *= 2;
247                         *p = '\0';
248                         p = (char *) ecalloc(len, sizeof(char));
249                         strcpy(p, gfilename);
250                         free(gfilename);
251                         gfilename = p;
252                         p = gfilename + strlen(gfilename);
253                 }
254                 *p = ch;
255         }
256         *p = '\0';
257         pclose(f);
258         if (*gfilename == '\0')
259                 return (NULL);
260         return (gfilename);
261 }
262
263 #else
264
265         public char *
266 glob(filename)
267         char *filename;
268 {
269         return (fexpand(filename));
270 }
271
272 #endif
273
274
275 #if STAT
276
277 #include <sys/types.h>
278 #include <sys/stat.h>
279
280 /*
281  * Returns NULL if the file can be opened and
282  * is an ordinary file, otherwise an error message
283  * (if it cannot be opened or is a directory, etc.)
284  */
285         public char *
286 bad_file(filename)
287         char *filename;
288 {
289         register char *m;
290         struct stat statbuf;
291
292         if (stat(filename, &statbuf) < 0)
293                 return (errno_message(filename));
294
295         if (force_open)
296                 return (NULL);
297
298         if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
299         {
300                 static char is_dir[] = " is a directory";
301                 m = (char *) ecalloc(strlen(filename) + sizeof(is_dir), 
302                         sizeof(char));
303                 strcpy(m, filename);
304                 strcat(m, is_dir);
305                 return (m);
306         }
307         if ((statbuf.st_mode & S_IFMT) != S_IFREG)
308         {
309                 static char not_reg[] = " is not a regular file";
310                 m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), 
311                         sizeof(char));
312                 strcpy(m, filename);
313                 strcat(m, not_reg);
314                 return (m);
315         }
316
317         return (NULL);
318 }
319
320 /*
321  * Return the size of a file, as cheaply as possible.
322  * In Unix, we can stat the file.
323  */
324         public POSITION
325 filesize(f)
326         int f;
327 {
328         struct stat statbuf;
329
330         if (fstat(f, &statbuf) < 0)
331                 /*
332                  * Can't stat; try seeking to the end.
333                  */
334                 return (seek_filesize(f));
335
336         return ((POSITION) statbuf.st_size);
337 }
338
339 #else
340
341 /*
342  * If we have no way to find out, just say the file is good.
343  */
344         public char *
345 bad_file(filename)
346         char *filename;
347 {
348         return (NULL);
349 }
350
351 /*
352  * We can find the file size by seeking.
353  */
354         public POSITION
355 filesize(f)
356         int f;
357 {
358         return (seek_filesize(f));
359 }
360
361 #endif