tw.help.c revision 167465
1123579Sgibbs/* $Header: /p/tcsh/cvsroot/tcsh/tw.help.c,v 3.27 2006/08/24 20:56:31 christos Exp $ */ 2123579Sgibbs/* tw.help.c: actually look up and print documentation on a file. 3123579Sgibbs * Look down the path for an appropriate file, then print it. 4123579Sgibbs * Note that the printing is NOT PAGED. This is because the 5123579Sgibbs * function is NOT meant to look at manual pages, it only does so 6123579Sgibbs * if there is no .help file to look in. 7123579Sgibbs */ 8123579Sgibbs/*- 9123579Sgibbs * Copyright (c) 1980, 1991 The Regents of the University of California. 10123579Sgibbs * All rights reserved. 11123579Sgibbs * 12123579Sgibbs * Redistribution and use in source and binary forms, with or without 13123579Sgibbs * modification, are permitted provided that the following conditions 14123579Sgibbs * are met: 15123579Sgibbs * 1. Redistributions of source code must retain the above copyright 16123579Sgibbs * notice, this list of conditions and the following disclaimer. 17123579Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 18123579Sgibbs * notice, this list of conditions and the following disclaimer in the 19123579Sgibbs * documentation and/or other materials provided with the distribution. 20123579Sgibbs * 3. Neither the name of the University nor the names of its contributors 21123579Sgibbs * may be used to endorse or promote products derived from this software 22123579Sgibbs * without specific prior written permission. 23123579Sgibbs * 24123579Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25123579Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26123579Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27123579Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28123579Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29123579Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30123579Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31123579Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32123679Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33123579Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34123579Sgibbs * SUCH DAMAGE. 35123579Sgibbs */ 36123579Sgibbs#include "sh.h" 37123579Sgibbs 38123579SgibbsRCSID("$tcsh: tw.help.c,v 3.27 2006/08/24 20:56:31 christos Exp $") 39123579Sgibbs 40123579Sgibbs#include "tw.h" 41123579Sgibbs#include "tc.h" 42123579Sgibbs 43123579Sgibbs 44123579Sgibbsstatic int f = -1; 45123579Sgibbsstatic void cleanf (int); 46123579Sgibbsstatic Char *skipslist (Char *); 47123579Sgibbsstatic void nextslist (const Char *, Char *); 48123579Sgibbs 49133911Sgibbsstatic const char *const h_ext[] = { 50123579Sgibbs ".help", ".1", ".8", ".6", "", NULL 51123579Sgibbs}; 52123579Sgibbs 53123579Sgibbsvoid 54123579Sgibbsdo_help(const Char *command) 55123579Sgibbs{ 56123579Sgibbs Char *name, *cmd_p; 57123579Sgibbs 58123579Sgibbs /* trim off the whitespace at the beginning */ 59123579Sgibbs while (*command == ' ' || *command == '\t') 60123579Sgibbs command++; 61123579Sgibbs 62123579Sgibbs /* copy the string to a safe place */ 63123579Sgibbs name = Strsave(command); 64123579Sgibbs cleanup_push(name, xfree); 65123579Sgibbs 66123579Sgibbs /* trim off the whitespace that may be at the end */ 67123579Sgibbs for (cmd_p = name; 68123579Sgibbs *cmd_p != ' ' && *cmd_p != '\t' && *cmd_p != '\0'; cmd_p++) 69123579Sgibbs continue; 70123579Sgibbs *cmd_p = '\0'; 71123579Sgibbs 72123579Sgibbs /* if nothing left, return */ 73123579Sgibbs if (*name == '\0') { 74123579Sgibbs cleanup_until(name); 75123579Sgibbs return; 76123579Sgibbs } 77123579Sgibbs 78123579Sgibbs if (adrof1(STRhelpcommand, &aliases)) { /* if we have an alias */ 79123579Sgibbs jmp_buf_t osetexit; 80123579Sgibbs size_t omark; 81123579Sgibbs 82123579Sgibbs getexit(osetexit); /* make sure to come back here */ 83123579Sgibbs omark = cleanup_push_mark(); 84123579Sgibbs if (setexit() == 0) 85123579Sgibbs aliasrun(2, STRhelpcommand, name); /* then use it. */ 86123579Sgibbs cleanup_pop_mark(omark); 87123579Sgibbs resexit(osetexit); /* and finish up */ 88123579Sgibbs } 89123579Sgibbs else { /* else cat something to them */ 90123579Sgibbs Char *thpath, *hpath; /* The environment parameter */ 91123579Sgibbs Char *curdir; /* Current directory being looked at */ 92123579Sgibbs struct Strbuf full = Strbuf_INIT; 93123579Sgibbs 94123579Sgibbs /* got is, now "cat" the file based on the path $HPATH */ 95123579Sgibbs 96123579Sgibbs hpath = str2short(getenv(SEARCHLIST)); 97123579Sgibbs if (hpath == NULL) 98123579Sgibbs hpath = str2short(DEFAULTLIST); 99123579Sgibbs thpath = hpath = Strsave(hpath); 100123579Sgibbs cleanup_push(thpath, xfree); 101123579Sgibbs curdir = xmalloc((Strlen(thpath) + 1) * sizeof (*curdir)); 102123579Sgibbs cleanup_push(curdir, xfree); 103123579Sgibbs cleanup_push(&full, Strbuf_cleanup); 104123579Sgibbs 105123579Sgibbs for (;;) { 106123579Sgibbs const char *const *sp; 107123579Sgibbs size_t ep; 108123579Sgibbs 109123579Sgibbs if (!*hpath) { 110123579Sgibbs xprintf(CGETS(29, 1, "No help file for %S\n"), name); 111123579Sgibbs break; 112123579Sgibbs } 113123579Sgibbs nextslist(hpath, curdir); 114123579Sgibbs hpath = skipslist(hpath); 115123579Sgibbs 116123579Sgibbs /* 117123579Sgibbs * now make the full path name - try first /bar/foo.help, then 118123579Sgibbs * /bar/foo.1, /bar/foo.8, then finally /bar/foo.6. This is so 119123579Sgibbs * that you don't spit a binary at the tty when $HPATH == $PATH. 120123579Sgibbs */ 121123579Sgibbs full.len = 0; 122123579Sgibbs Strbuf_append(&full, curdir); 123123579Sgibbs Strbuf_append(&full, STRslash); 124123679Sgibbs Strbuf_append(&full, name); 125123579Sgibbs ep = full.len; 126123679Sgibbs for (sp = h_ext; *sp; sp++) { 127123679Sgibbs full.len = ep; 128123579Sgibbs Strbuf_append(&full, str2short(*sp)); 129123679Sgibbs Strbuf_terminate(&full); 130123679Sgibbs if ((f = xopen(short2str(full.s), O_RDONLY|O_LARGEFILE)) != -1) 131123679Sgibbs break; 132123679Sgibbs } 133123579Sgibbs if (f != -1) { 134123579Sgibbs unsigned char buf[512]; 135123579Sgibbs sigset_t oset, set; 136123579Sgibbs struct sigaction osa, sa; 137123679Sgibbs ssize_t len; 138123579Sgibbs 139123579Sgibbs /* so cat it to the terminal */ 140123579Sgibbs cleanup_push(&f, open_cleanup); 141123579Sgibbs sa.sa_handler = cleanf; 142123579Sgibbs sigemptyset(&sa.sa_mask); 143123579Sgibbs sa.sa_flags = 0; 144123579Sgibbs (void)sigaction(SIGINT, &sa, &osa); 145123679Sgibbs cleanup_push(&osa, sigint_cleanup); 146123679Sgibbs (void)sigprocmask(SIG_UNBLOCK, &set, &oset); 147123679Sgibbs cleanup_push(&oset, sigprocmask_cleanup); 148123679Sgibbs while ((len = xread(f, buf, sizeof(buf))) > 0) 149123679Sgibbs (void) xwrite(SHOUT, buf, len); 150123679Sgibbs cleanup_until(&f); 151123679Sgibbs#ifdef convex 152123679Sgibbs /* print error in case file is migrated */ 153123679Sgibbs if (len == -1) 154123679Sgibbs stderror(ERR_SYSTEM, progname, strerror(errno)); 155123679Sgibbs#endif /* convex */ 156123679Sgibbs break; 157123679Sgibbs } 158123679Sgibbs } 159123679Sgibbs } 160123679Sgibbs cleanup_until(name); 161123679Sgibbs} 162123679Sgibbs 163123679Sgibbsstatic void 164123679Sgibbs/*ARGSUSED*/ 165123679Sgibbscleanf(int snum) 166123679Sgibbs{ 167123679Sgibbs USE(snum); 168123679Sgibbs 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 183static void 184nextslist(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 203static Char * 204skipslist(Char *sl) 205{ 206 while (*sl && *sl++ != ':') 207 continue; 208 return (sl); 209} 210