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