1 /* tw.help.c: actually look up and print documentation on a file. 2 * Look down the path for an appropriate file, then print it. 3 * Note that the printing is NOT PAGED. This is because the 4 * function is NOT meant to look at manual pages, it only does so 5 * if there is no .help file to look in. 6 */ 7 /*- 8 * Copyright (c) 1980, 1991 The Regents of the University of California. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 #include "sh.h" 36 #include "tw.h" 37 #include "tc.h" 38 39 40 static int f = -1; 41 static void cleanf (int); 42 static Char *skipslist (Char *); 43 static void nextslist (const Char *, Char *); 44 45 static const char *const h_ext[] = { 46 ".help", ".1", ".8", ".6", "", NULL 47 }; 48 49 void 50 do_help(const Char *command) 51 { 52 Char *name, *cmd_p; 53 54 /* trim off the whitespace at the beginning */ 55 while (*command == ' ' || *command == '\t') 56 command++; 57 58 /* copy the string to a safe place */ 59 name = Strsave(command); 60 cleanup_push(name, xfree); 61 62 /* trim off the whitespace that may be at the end */ 63 for (cmd_p = name; 64 *cmd_p != ' ' && *cmd_p != '\t' && *cmd_p != '\0'; cmd_p++) 65 continue; 66 *cmd_p = '\0'; 67 68 /* if nothing left, return */ 69 if (*name == '\0') { 70 cleanup_until(name); 71 return; 72 } 73 74 if (adrof1(STRhelpcommand, &aliases)) { /* if we have an alias */ 75 jmp_buf_t osetexit; 76 size_t omark; 77 78 getexit(osetexit); /* make sure to come back here */ 79 omark = cleanup_push_mark(); 80 if (setexit() == 0) 81 aliasrun(2, STRhelpcommand, name); /* then use it. */ 82 cleanup_pop_mark(omark); 83 resexit(osetexit); /* and finish up */ 84 } 85 else { /* else cat something to them */ 86 Char *thpath, *hpath; /* The environment parameter */ 87 Char *curdir; /* Current directory being looked at */ 88 struct Strbuf full = Strbuf_INIT; 89 90 /* got is, now "cat" the file based on the path $HPATH */ 91 92 hpath = str2short(getenv(SEARCHLIST)); 93 if (hpath == NULL) 94 hpath = str2short(DEFAULTLIST); 95 thpath = hpath = Strsave(hpath); 96 cleanup_push(thpath, xfree); 97 curdir = xmalloc((Strlen(thpath) + 1) * sizeof (*curdir)); 98 cleanup_push(curdir, xfree); 99 cleanup_push(&full, Strbuf_cleanup); 100 101 for (;;) { 102 const char *const *sp; 103 size_t ep; 104 105 if (!*hpath) { 106 xprintf(CGETS(29, 1, "No help file for %S\n"), name); 107 break; 108 } 109 nextslist(hpath, curdir); 110 hpath = skipslist(hpath); 111 112 /* 113 * now make the full path name - try first /bar/foo.help, then 114 * /bar/foo.1, /bar/foo.8, then finally /bar/foo.6. This is so 115 * that you don't spit a binary at the tty when $HPATH == $PATH. 116 */ 117 full.len = 0; 118 Strbuf_append(&full, curdir); 119 Strbuf_append(&full, STRslash); 120 Strbuf_append(&full, name); 121 ep = full.len; 122 for (sp = h_ext; *sp; sp++) { 123 full.len = ep; 124 Strbuf_append(&full, str2short(*sp)); 125 Strbuf_terminate(&full); 126 if ((f = xopen(short2str(full.s), O_RDONLY|O_LARGEFILE)) != -1) 127 break; 128 } 129 if (f != -1) { 130 unsigned char buf[512]; 131 sigset_t oset, set; 132 struct sigaction osa, sa; 133 ssize_t len; 134 135 /* so cat it to the terminal */ 136 cleanup_push(&f, open_cleanup); 137 sa.sa_handler = cleanf; 138 sigemptyset(&sa.sa_mask); 139 sa.sa_flags = 0; 140 (void)sigaction(SIGINT, &sa, &osa); 141 cleanup_push(&osa, sigint_cleanup); 142 (void)sigprocmask(SIG_UNBLOCK, &set, &oset); 143 cleanup_push(&oset, sigprocmask_cleanup); 144 while ((len = xread(f, buf, sizeof(buf))) > 0) 145 (void) xwrite(SHOUT, buf, len); 146 cleanup_until(&f); 147 #ifdef convex 148 /* print error in case file is migrated */ 149 if (len == -1) 150 stderror(ERR_SYSTEM, progname, strerror(errno)); 151 #endif /* convex */ 152 break; 153 } 154 } 155 } 156 cleanup_until(name); 157 } 158 159 static void 160 /*ARGSUSED*/ 161 cleanf(int snum) 162 { 163 USE(snum); 164 if (f != -1) 165 xclose(f); 166 f = -1; 167 } 168 169 /* these next two are stolen from CMU's man(1) command for looking down 170 * paths. they are prety straight forward. */ 171 172 /* 173 * nextslist takes a search list and copies the next path in it 174 * to np. A null search list entry is expanded to ".". 175 * If there are no entries in the search list, then np will point 176 * to a null string. 177 */ 178 179 static void 180 nextslist(const Char *sl, Char *np) 181 { 182 if (!*sl) 183 *np = '\000'; 184 else if (*sl == ':') { 185 *np++ = '.'; 186 *np = '\000'; 187 } 188 else { 189 while (*sl && *sl != ':') 190 *np++ = *sl++; 191 *np = '\000'; 192 } 193 } 194 195 /* 196 * skipslist returns the pointer to the next entry in the search list. 197 */ 198 199 static Char * 200 skipslist(Char *sl) 201 { 202 while (*sl && *sl++ != ':') 203 continue; 204 return (sl); 205 } 206