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