~ubuntu-branches/ubuntu/quantal/less/quantal

« back to all changes in this revision

Viewing changes to filename.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Schoepf
  • Date: 2002-04-04 16:43:52 UTC
  • Revision ID: james.westby@ubuntu.com-20020404164352-qldq048yoc7x5sd5
Tags: upstream-374
ImportĀ upstreamĀ versionĀ 374

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1984-2000  Mark Nudelman
 
3
 *
 
4
 * You may distribute under the terms of either the GNU General Public
 
5
 * License or the Less License, as specified in the README file.
 
6
 *
 
7
 * For more information about less, or for information on how to 
 
8
 * contact the author, see the README file.
 
9
 */
 
10
 
 
11
 
 
12
/*
 
13
 * Routines to mess around with filenames (and files).
 
14
 * Much of this is very OS dependent.
 
15
 */
 
16
 
 
17
#include "less.h"
 
18
#include "lglob.h"
 
19
#if MSDOS_COMPILER
 
20
#include <dos.h>
 
21
#if MSDOS_COMPILER==WIN32C && !defined(_MSC_VER)
 
22
#include <dir.h>
 
23
#endif
 
24
#if MSDOS_COMPILER==DJGPPC
 
25
#include <glob.h>
 
26
#include <dir.h>
 
27
#define _MAX_PATH       PATH_MAX
 
28
#endif
 
29
#endif
 
30
#ifdef _OSK
 
31
#include <rbf.h>
 
32
#ifndef _OSK_MWC32
 
33
#include <modes.h>
 
34
#endif
 
35
#endif
 
36
#if OS2
 
37
#include <signal.h>
 
38
#endif
 
39
 
 
40
#if HAVE_STAT
 
41
#include <sys/stat.h>
 
42
#ifndef S_ISDIR
 
43
#define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
 
44
#endif
 
45
#ifndef S_ISREG
 
46
#define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
 
47
#endif
 
48
#endif
 
49
 
 
50
 
 
51
extern int force_open;
 
52
extern int secure;
 
53
extern IFILE curr_ifile;
 
54
extern IFILE old_ifile;
 
55
#if SPACES_IN_FILENAMES
 
56
extern char openquote;
 
57
extern char closequote;
 
58
#endif
 
59
 
 
60
/*
 
61
 * Remove quotes around a filename.
 
62
 */
 
63
        public char *
 
64
shell_unquote(str)
 
65
        char *str;
 
66
{
 
67
        char *name;
 
68
        char *p;
 
69
 
 
70
        name = p = (char *) ecalloc(strlen(str)+1, sizeof(char));
 
71
        if (*str == openquote)
 
72
        {
 
73
                str++;
 
74
                while (*str != '\0')
 
75
                {
 
76
                        if (*str == closequote)
 
77
                        {
 
78
                                if (str[1] != closequote)
 
79
                                        break;
 
80
                                str++;
 
81
                        }
 
82
                        *p++ = *str++;
 
83
                }
 
84
        } else
 
85
        {
 
86
                char *esc = get_meta_escape();
 
87
                int esclen = strlen(esc);
 
88
                while (*str != '\0')
 
89
                {
 
90
                        if (esclen > 0 && strncmp(str, esc, esclen) == 0)
 
91
                                str += esclen;
 
92
                        *p++ = *str++;
 
93
                }
 
94
        }
 
95
        *p = '\0';
 
96
        return (name);
 
97
}
 
98
 
 
99
/*
 
100
 * Get the shell's escape character.
 
101
 */
 
102
        public char *
 
103
get_meta_escape()
 
104
{
 
105
        char *s;
 
106
 
 
107
        s = lgetenv("LESSMETAESCAPE");
 
108
        if (s == NULL)
 
109
                s = DEF_METAESCAPE;
 
110
        return (s);
 
111
}
 
112
 
 
113
/*
 
114
 * Get the characters which the shell considers to be "metacharacters".
 
115
 */
 
116
        static char *
 
117
metachars()
 
118
{
 
119
        static char *mchars = NULL;
 
120
 
 
121
        if (mchars == NULL)
 
122
        {
 
123
                mchars = lgetenv("LESSMETACHARS");
 
124
                if (mchars == NULL)
 
125
                        mchars = DEF_METACHARS;
 
126
        }
 
127
        return (mchars);
 
128
}
 
129
 
 
130
/*
 
131
 * Is this a shell metacharacter?
 
132
 */
 
133
        static int
 
134
metachar(c)
 
135
        char c;
 
136
{
 
137
        return (strchr(metachars(), c) != NULL);
 
138
}
 
139
 
 
140
/*
 
141
 * Insert a backslash before each metacharacter in a string.
 
142
 */
 
143
        public char *
 
144
shell_quote(s)
 
145
        char *s;
 
146
{
 
147
        char *p;
 
148
        char *newstr;
 
149
        int len;
 
150
        char *esc = get_meta_escape();
 
151
        int esclen = strlen(esc);
 
152
        int use_quotes = 0;
 
153
        int have_quotes = 0;
 
154
 
 
155
        /*
 
156
         * Determine how big a string we need to allocate.
 
157
         */
 
158
        len = 1; /* Trailing null byte */
 
159
        for (p = s;  *p != '\0';  p++)
 
160
        {
 
161
                len++;
 
162
                if (*p == openquote || *p == closequote)
 
163
                        have_quotes = 1;
 
164
                if (metachar(*p))
 
165
                {
 
166
                        if (esclen == 0)
 
167
                        {
 
168
                                /*
 
169
                                 * We've got a metachar, but this shell 
 
170
                                 * doesn't support escape chars.  Use quotes.
 
171
                                 */
 
172
                                use_quotes = 1;
 
173
                        } else
 
174
                        {
 
175
                                /*
 
176
                                 * Allow space for the escape char.
 
177
                                 */
 
178
                                len += esclen;
 
179
                        }
 
180
                }
 
181
        }
 
182
        if (use_quotes)
 
183
        {
 
184
                if (have_quotes)
 
185
                        /*
 
186
                         * We can't quote a string that contains quotes.
 
187
                         */
 
188
                        return (NULL);
 
189
                len = strlen(s) + 3;
 
190
        }
 
191
        /*
 
192
         * Allocate and construct the new string.
 
193
         */
 
194
        newstr = p = (char *) ecalloc(len, sizeof(char));
 
195
        if (use_quotes)
 
196
        {
 
197
                sprintf(newstr, "%c%s%c", openquote, s, closequote);
 
198
        } else
 
199
        {
 
200
                while (*s != '\0')
 
201
                {
 
202
                        if (metachar(*s))
 
203
                        {
 
204
                                /*
 
205
                                 * Add the escape char.
 
206
                                 */
 
207
                                strcpy(p, esc);
 
208
                                p += esclen;
 
209
                        }
 
210
                        *p++ = *s++;
 
211
                }
 
212
                *p = '\0';
 
213
        }
 
214
        return (newstr);
 
215
}
 
216
 
 
217
/*
 
218
 * Return a pathname that points to a specified file in a specified directory.
 
219
 * Return NULL if the file does not exist in the directory.
 
220
 */
 
221
        static char *
 
222
dirfile(dirname, filename)
 
223
        char *dirname;
 
224
        char *filename;
 
225
{
 
226
        char *pathname;
 
227
        char *qpathname;
 
228
        int f;
 
229
 
 
230
        if (dirname == NULL || *dirname == '\0')
 
231
                return (NULL);
 
232
        /*
 
233
         * Construct the full pathname.
 
234
         */
 
235
        pathname = (char *) calloc(strlen(dirname) + strlen(filename) + 2, 
 
236
                                        sizeof(char));
 
237
        if (pathname == NULL)
 
238
                return (NULL);
 
239
        sprintf(pathname, "%s%s%s", dirname, PATHNAME_SEP, filename);
 
240
        /*
 
241
         * Make sure the file exists.
 
242
         */
 
243
        qpathname = shell_unquote(pathname);
 
244
        f = open(qpathname, OPEN_READ);
 
245
        if (f < 0)
 
246
        {
 
247
                free(pathname);
 
248
                pathname = NULL;
 
249
        } else
 
250
        {
 
251
                close(f);
 
252
        }
 
253
        free(qpathname);
 
254
        return (pathname);
 
255
}
 
256
 
 
257
/*
 
258
 * Return the full pathname of the given file in the "home directory".
 
259
 */
 
260
        public char *
 
261
homefile(filename)
 
262
        char *filename;
 
263
{
 
264
        register char *pathname;
 
265
 
 
266
        /*
 
267
         * Try $HOME/filename.
 
268
         */
 
269
        pathname = dirfile(lgetenv("HOME"), filename);
 
270
        if (pathname != NULL)
 
271
                return (pathname);
 
272
#if OS2
 
273
        /*
 
274
         * Try $INIT/filename.
 
275
         */
 
276
        pathname = dirfile(lgetenv("INIT"), filename);
 
277
        if (pathname != NULL)
 
278
                return (pathname);
 
279
#endif
 
280
#if MSDOS_COMPILER || OS2
 
281
        /*
 
282
         * Look for the file anywhere on search path.
 
283
         */
 
284
        pathname = (char *) calloc(_MAX_PATH, sizeof(char));
 
285
#if MSDOS_COMPILER==DJGPPC
 
286
        {
 
287
                char *res = searchpath(filename);
 
288
                if (res == 0)
 
289
                        *pathname = '\0';
 
290
                else
 
291
                        strcpy(pathname, res);
 
292
        }
 
293
#else
 
294
        _searchenv(filename, "PATH", pathname);
 
295
#endif
 
296
        if (*pathname != '\0')
 
297
                return (pathname);
 
298
        free(pathname);
 
299
#endif
 
300
        return (NULL);
 
301
}
 
302
 
 
303
/*
 
304
 * Expand a string, substituting any "%" with the current filename,
 
305
 * and any "#" with the previous filename.
 
306
 * But a string of N "%"s is just replaced with N-1 "%"s.
 
307
 * Likewise for a string of N "#"s.
 
308
 * {{ This is a lot of work just to support % and #. }}
 
309
 */
 
310
        public char *
 
311
fexpand(s)
 
312
        char *s;
 
313
{
 
314
        register char *fr, *to;
 
315
        register int n;
 
316
        register char *e;
 
317
        IFILE ifile;
 
318
 
 
319
#define fchar_ifile(c) \
 
320
        ((c) == '%' ? curr_ifile : \
 
321
         (c) == '#' ? old_ifile : NULL_IFILE)
 
322
 
 
323
        /*
 
324
         * Make one pass to see how big a buffer we 
 
325
         * need to allocate for the expanded string.
 
326
         */
 
327
        n = 0;
 
328
        for (fr = s;  *fr != '\0';  fr++)
 
329
        {
 
330
                switch (*fr)
 
331
                {
 
332
                case '%':
 
333
                case '#':
 
334
                        if (fr > s && fr[-1] == *fr)
 
335
                        {
 
336
                                /*
 
337
                                 * Second (or later) char in a string
 
338
                                 * of identical chars.  Treat as normal.
 
339
                                 */
 
340
                                n++;
 
341
                        } else if (fr[1] != *fr)
 
342
                        {
 
343
                                /*
 
344
                                 * Single char (not repeated).  Treat specially.
 
345
                                 */
 
346
                                ifile = fchar_ifile(*fr);
 
347
                                if (ifile == NULL_IFILE)
 
348
                                        n++;
 
349
                                else
 
350
                                        n += strlen(get_filename(ifile));
 
351
                        }
 
352
                        /*
 
353
                         * Else it is the first char in a string of
 
354
                         * identical chars.  Just discard it.
 
355
                         */
 
356
                        break;
 
357
                default:
 
358
                        n++;
 
359
                        break;
 
360
                }
 
361
        }
 
362
 
 
363
        e = (char *) ecalloc(n+1, sizeof(char));
 
364
 
 
365
        /*
 
366
         * Now copy the string, expanding any "%" or "#".
 
367
         */
 
368
        to = e;
 
369
        for (fr = s;  *fr != '\0';  fr++)
 
370
        {
 
371
                switch (*fr)
 
372
                {
 
373
                case '%':
 
374
                case '#':
 
375
                        if (fr > s && fr[-1] == *fr)
 
376
                        {
 
377
                                *to++ = *fr;
 
378
                        } else if (fr[1] != *fr)
 
379
                        {
 
380
                                ifile = fchar_ifile(*fr);
 
381
                                if (ifile == NULL_IFILE)
 
382
                                        *to++ = *fr;
 
383
                                else
 
384
                                {
 
385
                                        strcpy(to, get_filename(ifile));
 
386
                                        to += strlen(to);
 
387
                                }
 
388
                        }
 
389
                        break;
 
390
                default:
 
391
                        *to++ = *fr;
 
392
                        break;
 
393
                }
 
394
        }
 
395
        *to = '\0';
 
396
        return (e);
 
397
}
 
398
 
 
399
#if TAB_COMPLETE_FILENAME
 
400
 
 
401
/*
 
402
 * Return a blank-separated list of filenames which "complete"
 
403
 * the given string.
 
404
 */
 
405
        public char *
 
406
fcomplete(s)
 
407
        char *s;
 
408
{
 
409
        char *fpat;
 
410
        char *qs;
 
411
 
 
412
        if (secure)
 
413
                return (NULL);
 
414
        /*
 
415
         * Complete the filename "s" by globbing "s*".
 
416
         */
 
417
#if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC)
 
418
        /*
 
419
         * But in DOS, we have to glob "s*.*".
 
420
         * But if the final component of the filename already has
 
421
         * a dot in it, just do "s*".  
 
422
         * (Thus, "FILE" is globbed as "FILE*.*", 
 
423
         *  but "FILE.A" is globbed as "FILE.A*").
 
424
         */
 
425
        {
 
426
                char *slash;
 
427
                for (slash = s+strlen(s)-1;  slash > s;  slash--)
 
428
                        if (*slash == *PATHNAME_SEP || *slash == '/')
 
429
                                break;
 
430
                fpat = (char *) ecalloc(strlen(s)+4, sizeof(char));
 
431
                if (strchr(slash, '.') == NULL)
 
432
                        sprintf(fpat, "%s*.*", s);
 
433
                else
 
434
                        sprintf(fpat, "%s*", s);
 
435
        }
 
436
#else
 
437
        fpat = (char *) ecalloc(strlen(s)+2, sizeof(char));
 
438
        sprintf(fpat, "%s*", s);
 
439
#endif
 
440
        qs = lglob(fpat);
 
441
        s = shell_unquote(qs);
 
442
        if (strcmp(s,fpat) == 0)
 
443
        {
 
444
                /*
 
445
                 * The filename didn't expand.
 
446
                 */
 
447
                free(qs);
 
448
                qs = NULL;
 
449
        }
 
450
        free(s);
 
451
        free(fpat);
 
452
        return (qs);
 
453
}
 
454
#endif
 
455
 
 
456
/*
 
457
 * Try to determine if a file is "binary".
 
458
 * This is just a guess, and we need not try too hard to make it accurate.
 
459
 */
 
460
        public int
 
461
bin_file(f)
 
462
        int f;
 
463
{
 
464
        int i;
 
465
        int n;
 
466
        unsigned char data[64];
 
467
 
 
468
        if (!seekable(f))
 
469
                return (0);
 
470
        if (lseek(f, (off_t)0, 0) == BAD_LSEEK)
 
471
                return (0);
 
472
        n = read(f, data, sizeof(data));
 
473
        for (i = 0;  i < n;  i++)
 
474
                if (binary_char(data[i]))
 
475
                        return (1);
 
476
        return (0);
 
477
}
 
478
 
 
479
/*
 
480
 * Try to determine the size of a file by seeking to the end.
 
481
 */
 
482
        static POSITION
 
483
seek_filesize(f)
 
484
        int f;
 
485
{
 
486
        off_t spos;
 
487
 
 
488
        spos = lseek(f, (off_t)0, 2);
 
489
        if (spos == BAD_LSEEK)
 
490
                return (NULL_POSITION);
 
491
        return ((POSITION) spos);
 
492
}
 
493
 
 
494
/*
 
495
 * Read a string from a file.
 
496
 * Return a pointer to the string in memory.
 
497
 */
 
498
        static char *
 
499
readfd(fd)
 
500
        FILE *fd;
 
501
{
 
502
        int len;
 
503
        int ch;
 
504
        char *buf;
 
505
        char *p;
 
506
        
 
507
        /* 
 
508
         * Make a guess about how many chars in the string
 
509
         * and allocate a buffer to hold it.
 
510
         */
 
511
        len = 100;
 
512
        buf = (char *) ecalloc(len, sizeof(char));
 
513
        for (p = buf;  ;  p++)
 
514
        {
 
515
                if ((ch = getc(fd)) == '\n' || ch == EOF)
 
516
                        break;
 
517
                if (p - buf >= len-1)
 
518
                {
 
519
                        /*
 
520
                         * The string is too big to fit in the buffer we have.
 
521
                         * Allocate a new buffer, twice as big.
 
522
                         */
 
523
                        len *= 2;
 
524
                        *p = '\0';
 
525
                        p = (char *) ecalloc(len, sizeof(char));
 
526
                        strcpy(p, buf);
 
527
                        free(buf);
 
528
                        buf = p;
 
529
                        p = buf + strlen(buf);
 
530
                }
 
531
                *p = ch;
 
532
        }
 
533
        *p = '\0';
 
534
        return (buf);
 
535
}
 
536
 
 
537
 
 
538
 
 
539
#if HAVE_POPEN
 
540
 
 
541
FILE *popen();
 
542
 
 
543
/*
 
544
 * Execute a shell command.
 
545
 * Return a pointer to a pipe connected to the shell command's standard output.
 
546
 */
 
547
        static FILE *
 
548
shellcmd(cmd)
 
549
        char *cmd;
 
550
{
 
551
        FILE *fd;
 
552
 
 
553
#if HAVE_SHELL
 
554
        char *shell;
 
555
 
 
556
        shell = lgetenv("SHELL");
 
557
        if (shell != NULL && *shell != '\0')
 
558
        {
 
559
                char *scmd;
 
560
                char *esccmd;
 
561
 
 
562
                /*
 
563
                 * Read the output of <$SHELL -c cmd>.  
 
564
                 * Escape any metacharacters in the command.
 
565
                 */
 
566
                esccmd = shell_quote(cmd);
 
567
                if (esccmd == NULL)
 
568
                {
 
569
                        fd = popen(cmd, "r");
 
570
                } else
 
571
                {
 
572
                        scmd = (char *) ecalloc(strlen(shell) + strlen(esccmd) + 5,
 
573
                                                sizeof(char));
 
574
                        sprintf(scmd, "%s %s %s", shell, shell_coption(), esccmd);
 
575
                        free(esccmd);
 
576
                        fd = popen(scmd, "r");
 
577
                        free(scmd);
 
578
                }
 
579
        } else
 
580
#endif
 
581
        {
 
582
                fd = popen(cmd, "r");
 
583
        }
 
584
        /*
 
585
         * Redirection in `popen' might have messed with the
 
586
         * standard devices.  Restore binary input mode.
 
587
         */
 
588
        SET_BINARY(0);
 
589
        return (fd);
 
590
}
 
591
 
 
592
#endif /* HAVE_POPEN */
 
593
 
 
594
 
 
595
/*
 
596
 * Expand a filename, doing any system-specific metacharacter substitutions.
 
597
 */
 
598
        public char *
 
599
lglob(filename)
 
600
        char *filename;
 
601
{
 
602
        char *gfilename;
 
603
        char *ofilename;
 
604
 
 
605
        ofilename = fexpand(filename);
 
606
        if (secure)
 
607
                return (ofilename);
 
608
        filename = shell_unquote(ofilename);
 
609
 
 
610
#ifdef DECL_GLOB_LIST
 
611
{
 
612
        /*
 
613
         * The globbing function returns a list of names.
 
614
         */
 
615
        int length;
 
616
        char *p;
 
617
        char *qfilename;
 
618
        DECL_GLOB_LIST(list)
 
619
 
 
620
        GLOB_LIST(filename, list);
 
621
        if (GLOB_LIST_FAILED(list))
 
622
        {
 
623
                free(filename);
 
624
                return (ofilename);
 
625
        }
 
626
        length = 1; /* Room for trailing null byte */
 
627
        for (SCAN_GLOB_LIST(list, p))
 
628
        {
 
629
                INIT_GLOB_LIST(list, p);
 
630
                qfilename = shell_quote(p);
 
631
                if (qfilename != NULL)
 
632
                {
 
633
                        length += strlen(qfilename) + 1;
 
634
                        free(qfilename);
 
635
                }
 
636
        }
 
637
        gfilename = (char *) ecalloc(length, sizeof(char));
 
638
        for (SCAN_GLOB_LIST(list, p))
 
639
        {
 
640
                INIT_GLOB_LIST(list, p);
 
641
                qfilename = shell_quote(p);
 
642
                if (qfilename != NULL)
 
643
                {
 
644
                        sprintf(gfilename + strlen(gfilename), "%s ", qfilename);
 
645
                        free(qfilename);
 
646
                }
 
647
        }
 
648
        /*
 
649
         * Overwrite the final trailing space with a null terminator.
 
650
         */
 
651
        *--p = '\0';
 
652
        GLOB_LIST_DONE(list);
 
653
}
 
654
#else
 
655
#ifdef DECL_GLOB_NAME
 
656
{
 
657
        /*
 
658
         * The globbing function returns a single name, and
 
659
         * is called multiple times to walk thru all names.
 
660
         */
 
661
        register char *p;
 
662
        register int len;
 
663
        register int n;
 
664
        char *pathname;
 
665
        char *qpathname;
 
666
        DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle)
 
667
        
 
668
        GLOB_FIRST_NAME(filename, &fnd, handle);
 
669
        if (GLOB_FIRST_FAILED(handle))
 
670
        {
 
671
                free(filename);
 
672
                return (ofilename);
 
673
        }
 
674
 
 
675
        _splitpath(filename, drive, dir, fname, ext);
 
676
        len = 100;
 
677
        gfilename = (char *) ecalloc(len, sizeof(char));
 
678
        p = gfilename;
 
679
        do {
 
680
                n = strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1;
 
681
                pathname = (char *) ecalloc(n, sizeof(char));
 
682
                sprintf(pathname, "%s%s%s", drive, dir, fnd.GLOB_NAME);
 
683
                qpathname = shell_quote(pathname);
 
684
                free(pathname);
 
685
                if (qpathname != NULL)
 
686
                {
 
687
                        n = strlen(qpathname);
 
688
                        while (p - gfilename + n + 2 >= len)
 
689
                        {
 
690
                                /*
 
691
                                 * No room in current buffer.
 
692
                                 * Allocate a bigger one.
 
693
                                 */
 
694
                                len *= 2;
 
695
                                *p = '\0';
 
696
                                p = (char *) ecalloc(len, sizeof(char));
 
697
                                strcpy(p, gfilename);
 
698
                                free(gfilename);
 
699
                                gfilename = p;
 
700
                                p = gfilename + strlen(gfilename);
 
701
                        }
 
702
                        strcpy(p, qpathname);
 
703
                        free(qpathname);
 
704
                        p += n;
 
705
                        *p++ = ' ';
 
706
                }
 
707
        } while (GLOB_NEXT_NAME(handle, &fnd) == 0);
 
708
 
 
709
        /*
 
710
         * Overwrite the final trailing space with a null terminator.
 
711
         */
 
712
        *--p = '\0';
 
713
        GLOB_NAME_DONE(handle);
 
714
}
 
715
#else
 
716
#if HAVE_POPEN
 
717
{
 
718
        /*
 
719
         * We get the shell to glob the filename for us by passing
 
720
         * an "echo" command to the shell and reading its output.
 
721
         */
 
722
        FILE *fd;
 
723
        char *s;
 
724
        char *lessecho;
 
725
        char *cmd;
 
726
        char *esc;
 
727
 
 
728
        esc = get_meta_escape();
 
729
        if (strlen(esc) == 0)
 
730
                esc = "-";
 
731
        esc = shell_quote(esc);
 
732
        if (esc == NULL)
 
733
        {
 
734
                free(filename);
 
735
                return (ofilename);
 
736
        }
 
737
        lessecho = lgetenv("LESSECHO");
 
738
        if (lessecho == NULL || *lessecho == '\0')
 
739
                lessecho = "lessecho";
 
740
        /*
 
741
         * Invoke lessecho, and read its output (a globbed list of filenames).
 
742
         */
 
743
        cmd = (char *) ecalloc(strlen(lessecho) + strlen(ofilename) + (7*strlen(metachars())) + 24, sizeof(char));
 
744
        sprintf(cmd, "%s -p0x%x -d0x%x -e%s ", lessecho, openquote, closequote, esc);
 
745
        free(esc);
 
746
        for (s = metachars();  *s != '\0';  s++)
 
747
                sprintf(cmd + strlen(cmd), "-n0x%x ", *s);
 
748
        sprintf(cmd + strlen(cmd), "-- %s", ofilename);
 
749
        fd = shellcmd(cmd);
 
750
        free(cmd);
 
751
        if (fd == NULL)
 
752
        {
 
753
                /*
 
754
                 * Cannot create the pipe.
 
755
                 * Just return the original (fexpanded) filename.
 
756
                 */
 
757
                free(filename);
 
758
                return (ofilename);
 
759
        }
 
760
        gfilename = readfd(fd);
 
761
        pclose(fd);
 
762
        if (*gfilename == '\0')
 
763
        {
 
764
                free(gfilename);
 
765
                free(filename);
 
766
                return (ofilename);
 
767
        }
 
768
}
 
769
#else
 
770
        /*
 
771
         * No globbing functions at all.  Just use the fexpanded filename.
 
772
         */
 
773
        gfilename = save(filename);
 
774
#endif
 
775
#endif
 
776
#endif
 
777
        free(filename);
 
778
        free(ofilename);
 
779
        return (gfilename);
 
780
}
 
781
 
 
782
/*
 
783
 * See if we should open a "replacement file" 
 
784
 * instead of the file we're about to open.
 
785
 */
 
786
        public char *
 
787
open_altfile(filename, pf, pfd)
 
788
        char *filename;
 
789
        int *pf;
 
790
        void **pfd;
 
791
{
 
792
#if !HAVE_POPEN
 
793
        return (NULL);
 
794
#else
 
795
        char *lessopen;
 
796
        char *cmd;
 
797
        FILE *fd;
 
798
#if HAVE_FILENO
 
799
        int returnfd = 0;
 
800
#endif
 
801
        
 
802
        if (secure)
 
803
                return (NULL);
 
804
        ch_ungetchar(-1);
 
805
        if ((lessopen = lgetenv("LESSOPEN")) == NULL)
 
806
                return (NULL);
 
807
        if (strcmp(filename, "-") == 0)
 
808
                return (NULL);
 
809
        if (*lessopen == '|')
 
810
        {
 
811
                /*
 
812
                 * If LESSOPEN starts with a |, it indicates 
 
813
                 * a "pipe preprocessor".
 
814
                 */
 
815
#if HAVE_FILENO
 
816
                lessopen++;
 
817
                returnfd = 1;
 
818
#else
 
819
                error("LESSOPEN pipe is not supported", NULL_PARG);
 
820
                return (NULL);
 
821
#endif
 
822
        }
 
823
 
 
824
        cmd = (char *) ecalloc(strlen(lessopen) + strlen(filename) + 2, 
 
825
                        sizeof(char));
 
826
        sprintf(cmd, lessopen, filename);
 
827
        fd = shellcmd(cmd);
 
828
        free(cmd);
 
829
        if (fd == NULL)
 
830
        {
 
831
                /*
 
832
                 * Cannot create the pipe.
 
833
                 */
 
834
                return (NULL);
 
835
        }
 
836
#if HAVE_FILENO
 
837
        if (returnfd)
 
838
        {
 
839
                int f;
 
840
                char c;
 
841
 
 
842
                /*
 
843
                 * Read one char to see if the pipe will produce any data.
 
844
                 * If it does, push the char back on the pipe.
 
845
                 */
 
846
                f = fileno(fd);
 
847
                SET_BINARY(f);
 
848
                if (read(f, &c, 1) != 1)
 
849
                {
 
850
                        /*
 
851
                         * Pipe is empty.  This means there is no alt file.
 
852
                         */
 
853
                        pclose(fd);
 
854
                        return (NULL);
 
855
                }
 
856
                ch_ungetchar(c);
 
857
                *pfd = (void *) fd;
 
858
                *pf = f;
 
859
                return (save("-"));
 
860
        }
 
861
#endif
 
862
        cmd = readfd(fd);
 
863
        pclose(fd);
 
864
        if (*cmd == '\0')
 
865
                /*
 
866
                 * Pipe is empty.  This means there is no alt file.
 
867
                 */
 
868
                return (NULL);
 
869
        return (cmd);
 
870
#endif /* HAVE_POPEN */
 
871
}
 
872
 
 
873
/*
 
874
 * Close a replacement file.
 
875
 */
 
876
        public void
 
877
close_altfile(altfilename, filename, pipefd)
 
878
        char *altfilename;
 
879
        char *filename;
 
880
        void *pipefd;
 
881
{
 
882
#if HAVE_POPEN
 
883
        char *lessclose;
 
884
        FILE *fd;
 
885
        char *cmd;
 
886
        
 
887
        if (secure)
 
888
                return;
 
889
        if (pipefd != NULL)
 
890
        {
 
891
#if OS2
 
892
                /*
 
893
                 * The pclose function of OS/2 emx sometimes fails.
 
894
                 * Send SIGINT to the piped process before closing it.
 
895
                 */
 
896
                kill(((FILE*)pipefd)->_pid, SIGINT);
 
897
#endif
 
898
                pclose((FILE*) pipefd);
 
899
        }
 
900
        if ((lessclose = lgetenv("LESSCLOSE")) == NULL)
 
901
                return;
 
902
        cmd = (char *) ecalloc(strlen(lessclose) + strlen(filename) + 
 
903
                        strlen(altfilename) + 2, sizeof(char));
 
904
        sprintf(cmd, lessclose, filename, altfilename);
 
905
        fd = shellcmd(cmd);
 
906
        free(cmd);
 
907
        if (fd != NULL)
 
908
                pclose(fd);
 
909
#endif
 
910
}
 
911
                
 
912
/*
 
913
 * Is the specified file a directory?
 
914
 */
 
915
        public int
 
916
is_dir(filename)
 
917
        char *filename;
 
918
{
 
919
        int isdir = 0;
 
920
 
 
921
        filename = shell_unquote(filename);
 
922
#if HAVE_STAT
 
923
{
 
924
        int r;
 
925
        struct stat statbuf;
 
926
 
 
927
        r = stat(filename, &statbuf);
 
928
        isdir = (r >= 0 && S_ISDIR(statbuf.st_mode));
 
929
}
 
930
#else
 
931
#ifdef _OSK
 
932
{
 
933
        register int f;
 
934
 
 
935
        f = open(filename, S_IREAD | S_IFDIR);
 
936
        if (f >= 0)
 
937
                close(f);
 
938
        isdir = (f >= 0);
 
939
}
 
940
#endif
 
941
#endif
 
942
        free(filename);
 
943
        return (isdir);
 
944
}
 
945
 
 
946
/*
 
947
 * Returns NULL if the file can be opened and
 
948
 * is an ordinary file, otherwise an error message
 
949
 * (if it cannot be opened or is a directory, etc.)
 
950
 */
 
951
        public char *
 
952
bad_file(filename)
 
953
        char *filename;
 
954
{
 
955
        register char *m = NULL;
 
956
 
 
957
        filename = shell_unquote(filename);
 
958
        if (is_dir(filename))
 
959
        {
 
960
                static char is_dir[] = " is a directory";
 
961
 
 
962
                m = (char *) ecalloc(strlen(filename) + sizeof(is_dir), 
 
963
                        sizeof(char));
 
964
                strcpy(m, filename);
 
965
                strcat(m, is_dir);
 
966
        } else
 
967
        {
 
968
#if HAVE_STAT
 
969
                int r;
 
970
                struct stat statbuf;
 
971
 
 
972
                r = stat(filename, &statbuf);
 
973
                if (r < 0)
 
974
                {
 
975
                        m = errno_message(filename);
 
976
                } else if (force_open)
 
977
                {
 
978
                        m = NULL;
 
979
                } else if (!S_ISREG(statbuf.st_mode))
 
980
                {
 
981
                        static char not_reg[] = " is not a regular file (use -f to see it)";
 
982
                        m = (char *) ecalloc(strlen(filename) + sizeof(not_reg),
 
983
                                sizeof(char));
 
984
                        strcpy(m, filename);
 
985
                        strcat(m, not_reg);
 
986
                }
 
987
#endif
 
988
        }
 
989
        free(filename);
 
990
        return (m);
 
991
}
 
992
 
 
993
/*
 
994
 * Return the size of a file, as cheaply as possible.
 
995
 * In Unix, we can stat the file.
 
996
 */
 
997
        public POSITION
 
998
filesize(f)
 
999
        int f;
 
1000
{
 
1001
#if HAVE_STAT
 
1002
        struct stat statbuf;
 
1003
 
 
1004
        if (fstat(f, &statbuf) >= 0)
 
1005
                return ((POSITION) statbuf.st_size);
 
1006
#else
 
1007
#ifdef _OSK
 
1008
        long size;
 
1009
 
 
1010
        if ((size = (long) _gs_size(f)) >= 0)
 
1011
                return ((POSITION) size);
 
1012
#endif
 
1013
#endif
 
1014
        return (seek_filesize(f));
 
1015
}
 
1016
 
 
1017
/*
 
1018
 * 
 
1019
 */
 
1020
        public char *
 
1021
shell_coption()
 
1022
{
 
1023
        return ("-c");
 
1024
}