1167465Smp/* $Header: /p/tcsh/cvsroot/tcsh/tw.help.c,v 3.27 2006/08/24 20:56:31 christos Exp $ */ 259243Sobrien/* tw.help.c: actually look up and print documentation on a file. 359243Sobrien * Look down the path for an appropriate file, then print it. 459243Sobrien * Note that the printing is NOT PAGED. This is because the 559243Sobrien * function is NOT meant to look at manual pages, it only does so 659243Sobrien * if there is no .help file to look in. 759243Sobrien */ 859243Sobrien/*- 959243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 1059243Sobrien * All rights reserved. 1159243Sobrien * 1259243Sobrien * Redistribution and use in source and binary forms, with or without 1359243Sobrien * modification, are permitted provided that the following conditions 1459243Sobrien * are met: 1559243Sobrien * 1. Redistributions of source code must retain the above copyright 1659243Sobrien * notice, this list of conditions and the following disclaimer. 1759243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1859243Sobrien * notice, this list of conditions and the following disclaimer in the 1959243Sobrien * documentation and/or other materials provided with the distribution. 20100616Smp * 3. Neither the name of the University nor the names of its contributors 2159243Sobrien * may be used to endorse or promote products derived from this software 2259243Sobrien * without specific prior written permission. 2359243Sobrien * 2459243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2559243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2659243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2759243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2859243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2959243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3059243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3159243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3259243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3359243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3459243Sobrien * SUCH DAMAGE. 3559243Sobrien */ 3659243Sobrien#include "sh.h" 3759243Sobrien 38167465SmpRCSID("$tcsh: tw.help.c,v 3.27 2006/08/24 20:56:31 christos Exp $") 3959243Sobrien 4059243Sobrien#include "tw.h" 4159243Sobrien#include "tc.h" 4259243Sobrien 4359243Sobrien 4459243Sobrienstatic int f = -1; 45167465Smpstatic void cleanf (int); 46167465Smpstatic Char *skipslist (Char *); 47167465Smpstatic void nextslist (const Char *, Char *); 4859243Sobrien 49167465Smpstatic const char *const h_ext[] = { 5059243Sobrien ".help", ".1", ".8", ".6", "", NULL 5159243Sobrien}; 5259243Sobrien 5359243Sobrienvoid 54167465Smpdo_help(const Char *command) 5559243Sobrien{ 56167465Smp Char *name, *cmd_p; 5759243Sobrien 58167465Smp /* trim off the whitespace at the beginning */ 59167465Smp while (*command == ' ' || *command == '\t') 60167465Smp command++; 6159243Sobrien 6259243Sobrien /* copy the string to a safe place */ 63167465Smp name = Strsave(command); 64167465Smp cleanup_push(name, xfree); 6559243Sobrien 6659243Sobrien /* trim off the whitespace that may be at the end */ 67167465Smp for (cmd_p = name; 6859243Sobrien *cmd_p != ' ' && *cmd_p != '\t' && *cmd_p != '\0'; cmd_p++) 6959243Sobrien continue; 7059243Sobrien *cmd_p = '\0'; 7159243Sobrien 7259243Sobrien /* if nothing left, return */ 73167465Smp if (*name == '\0') { 74167465Smp cleanup_until(name); 7559243Sobrien return; 76167465Smp } 7759243Sobrien 7859243Sobrien if (adrof1(STRhelpcommand, &aliases)) { /* if we have an alias */ 7959243Sobrien jmp_buf_t osetexit; 80167465Smp size_t omark; 8159243Sobrien 8259243Sobrien getexit(osetexit); /* make sure to come back here */ 83167465Smp omark = cleanup_push_mark(); 8459243Sobrien if (setexit() == 0) 8559243Sobrien aliasrun(2, STRhelpcommand, name); /* then use it. */ 86167465Smp cleanup_pop_mark(omark); 8759243Sobrien resexit(osetexit); /* and finish up */ 8859243Sobrien } 8959243Sobrien else { /* else cat something to them */ 90167465Smp Char *thpath, *hpath; /* The environment parameter */ 91167465Smp Char *curdir; /* Current directory being looked at */ 92167465Smp struct Strbuf full = Strbuf_INIT; 93167465Smp 9459243Sobrien /* got is, now "cat" the file based on the path $HPATH */ 9559243Sobrien 9659243Sobrien hpath = str2short(getenv(SEARCHLIST)); 9759243Sobrien if (hpath == NULL) 9859243Sobrien hpath = str2short(DEFAULTLIST); 9959243Sobrien thpath = hpath = Strsave(hpath); 100167465Smp cleanup_push(thpath, xfree); 101167465Smp curdir = xmalloc((Strlen(thpath) + 1) * sizeof (*curdir)); 102167465Smp cleanup_push(curdir, xfree); 103167465Smp cleanup_push(&full, Strbuf_cleanup); 10459243Sobrien 10559243Sobrien for (;;) { 106167465Smp const char *const *sp; 107167465Smp size_t ep; 108167465Smp 10959243Sobrien if (!*hpath) { 11059243Sobrien xprintf(CGETS(29, 1, "No help file for %S\n"), name); 11159243Sobrien break; 11259243Sobrien } 11359243Sobrien nextslist(hpath, curdir); 11459243Sobrien hpath = skipslist(hpath); 11559243Sobrien 11659243Sobrien /* 11759243Sobrien * now make the full path name - try first /bar/foo.help, then 11859243Sobrien * /bar/foo.1, /bar/foo.8, then finally /bar/foo.6. This is so 11959243Sobrien * that you don't spit a binary at the tty when $HPATH == $PATH. 12059243Sobrien */ 121167465Smp full.len = 0; 122167465Smp Strbuf_append(&full, curdir); 123167465Smp Strbuf_append(&full, STRslash); 124167465Smp Strbuf_append(&full, name); 125167465Smp ep = full.len; 12659243Sobrien for (sp = h_ext; *sp; sp++) { 127167465Smp full.len = ep; 128167465Smp Strbuf_append(&full, str2short(*sp)); 129167465Smp Strbuf_terminate(&full); 130167465Smp if ((f = xopen(short2str(full.s), O_RDONLY|O_LARGEFILE)) != -1) 13159243Sobrien break; 13259243Sobrien } 13359243Sobrien if (f != -1) { 134167465Smp unsigned char buf[512]; 135167465Smp sigset_t oset, set; 136167465Smp struct sigaction osa, sa; 137167465Smp ssize_t len; 138167465Smp 13959243Sobrien /* so cat it to the terminal */ 140167465Smp cleanup_push(&f, open_cleanup); 141167465Smp sa.sa_handler = cleanf; 142167465Smp sigemptyset(&sa.sa_mask); 143167465Smp sa.sa_flags = 0; 144167465Smp (void)sigaction(SIGINT, &sa, &osa); 145167465Smp cleanup_push(&osa, sigint_cleanup); 146167465Smp (void)sigprocmask(SIG_UNBLOCK, &set, &oset); 147167465Smp cleanup_push(&oset, sigprocmask_cleanup); 148167465Smp while ((len = xread(f, buf, sizeof(buf))) > 0) 149167465Smp (void) xwrite(SHOUT, buf, len); 150167465Smp cleanup_until(&f); 15159243Sobrien#ifdef convex 15259243Sobrien /* print error in case file is migrated */ 15359243Sobrien if (len == -1) 15459243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 15559243Sobrien#endif /* convex */ 15659243Sobrien break; 15759243Sobrien } 15859243Sobrien } 15959243Sobrien } 160167465Smp cleanup_until(name); 16159243Sobrien} 16259243Sobrien 163167465Smpstatic void 16459243Sobrien/*ARGSUSED*/ 165167465Smpcleanf(int snum) 16659243Sobrien{ 16759415Sobrien USE(snum); 16859243Sobrien if (f != -1) 169167465Smp xclose(f); 17059243Sobrien f = -1; 17159243Sobrien} 17259243Sobrien 17359243Sobrien/* these next two are stolen from CMU's man(1) command for looking down 17459243Sobrien * paths. they are prety straight forward. */ 17559243Sobrien 17659243Sobrien/* 17759243Sobrien * nextslist takes a search list and copies the next path in it 17859243Sobrien * to np. A null search list entry is expanded to ".". 17959243Sobrien * If there are no entries in the search list, then np will point 18059243Sobrien * to a null string. 18159243Sobrien */ 18259243Sobrien 18359243Sobrienstatic void 184167465Smpnextslist(const Char *sl, Char *np) 18559243Sobrien{ 18659243Sobrien if (!*sl) 18759243Sobrien *np = '\000'; 18859243Sobrien else if (*sl == ':') { 18959243Sobrien *np++ = '.'; 19059243Sobrien *np = '\000'; 19159243Sobrien } 19259243Sobrien else { 19359243Sobrien while (*sl && *sl != ':') 19459243Sobrien *np++ = *sl++; 19559243Sobrien *np = '\000'; 19659243Sobrien } 19759243Sobrien} 19859243Sobrien 19959243Sobrien/* 20059243Sobrien * skipslist returns the pointer to the next entry in the search list. 20159243Sobrien */ 20259243Sobrien 20359243Sobrienstatic Char * 204167465Smpskipslist(Char *sl) 20559243Sobrien{ 20659243Sobrien while (*sl && *sl++ != ':') 20759243Sobrien continue; 20859243Sobrien return (sl); 20959243Sobrien} 210