tw.help.c revision 145479
1/* $Header: /src/pub/tcsh/tw.help.c,v 3.21 2005/01/18 20:24:51 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
38RCSID("$Id: tw.help.c,v 3.21 2005/01/18 20:24:51 christos Exp $")
39
40#include "tw.h"
41#include "tc.h"
42
43
44static int f = -1;
45static	RETSIGTYPE	 cleanf		__P((int));
46static	Char    	*skipslist	__P((Char *));
47static	void		 nextslist 	__P((Char *, Char *));
48
49static const char *h_ext[] = {
50    ".help", ".1", ".8", ".6", "", NULL
51};
52
53void
54do_help(command)
55    Char   *command;
56{
57    Char    name[FILSIZ + 1];
58    Char   *cmd_p, *ep;
59    const char  **sp;
60
61    signalfun_t orig_intr;
62    Char    curdir[MAXPATHLEN];	/* Current directory being looked at */
63    Char *hpath;	/* The environment parameter */
64    Char    full[MAXPATHLEN];
65    char    buf[512];		/* full path name and buffer for read */
66    int     len;		/* length of read buffer */
67    Char   *thpath;
68
69
70    /* trim off the whitespace at the beginning */
71    for (cmd_p = command; *cmd_p == ' ' || *cmd_p == '\t'; cmd_p++)
72	continue;
73
74    /* copy the string to a safe place */
75    copyn(name, cmd_p, FILSIZ + 1);
76
77    /* trim off the whitespace that may be at the end */
78    for (cmd_p = name;
79	 *cmd_p != ' ' && *cmd_p != '\t' && *cmd_p != '\0'; cmd_p++)
80	continue;
81    *cmd_p = '\0';
82
83    /* if nothing left, return */
84    if (*name == '\0')
85	return;
86
87    if (adrof1(STRhelpcommand, &aliases)) {	/* if we have an alias */
88	jmp_buf_t osetexit;
89
90	getexit(osetexit);	/* make sure to come back here */
91	if (setexit() == 0)
92	    aliasrun(2, STRhelpcommand, name);	/* then use it. */
93	resexit(osetexit);	/* and finish up */
94    }
95    else {			/* else cat something to them */
96	/* got is, now "cat" the file based on the path $HPATH */
97
98	hpath = str2short(getenv(SEARCHLIST));
99	if (hpath == NULL)
100	    hpath = str2short(DEFAULTLIST);
101	thpath = hpath = Strsave(hpath);
102
103	for (;;) {
104	    if (!*hpath) {
105		xprintf(CGETS(29, 1, "No help file for %S\n"), name);
106		break;
107	    }
108	    nextslist(hpath, curdir);
109	    hpath = skipslist(hpath);
110
111	    /*
112	     * now make the full path name - try first /bar/foo.help, then
113	     * /bar/foo.1, /bar/foo.8, then finally /bar/foo.6.  This is so
114	     * that you don't spit a binary at the tty when $HPATH == $PATH.
115	     */
116	    copyn(full, curdir, (int) (sizeof(full) / sizeof(Char)));
117	    catn(full, STRslash, (int) (sizeof(full) / sizeof(Char)));
118	    catn(full, name, (int) (sizeof(full) / sizeof(Char)));
119	    ep = &full[Strlen(full)];
120	    for (sp = h_ext; *sp; sp++) {
121		*ep = '\0';
122		catn(full, str2short(*sp), (int) (sizeof(full) / sizeof(Char)));
123		if ((f = open(short2str(full), O_RDONLY|O_LARGEFILE)) != -1)
124		    break;
125	    }
126	    if (f != -1) {
127		/* so cat it to the terminal */
128		orig_intr = (signalfun_t) sigset(SIGINT, cleanf);
129		while (f != -1 && (len = read(f, (char *) buf, 512)) > 0)
130		    (void) write(SHOUT, (char *) buf, (size_t) len);
131#ifdef convex
132		/* print error in case file is migrated */
133		if (len == -1)
134		    stderror(ERR_SYSTEM, progname, strerror(errno));
135#endif /* convex */
136		(void) sigset(SIGINT, orig_intr);
137		if (f != -1)
138		    (void) close(f);
139		break;
140	    }
141	}
142	xfree((ptr_t) thpath);
143    }
144}
145
146static RETSIGTYPE
147/*ARGSUSED*/
148cleanf(snum)
149int snum;
150{
151    USE(snum);
152#ifdef UNRELSIGS
153    if (snum)
154	(void) sigset(SIGINT, cleanf);
155#endif /* UNRELSIGS */
156    if (f != -1)
157	(void) close(f);
158    f = -1;
159}
160
161/* these next two are stolen from CMU's man(1) command for looking down
162 * paths.  they are prety straight forward. */
163
164/*
165 * nextslist takes a search list and copies the next path in it
166 * to np.  A null search list entry is expanded to ".".
167 * If there are no entries in the search list, then np will point
168 * to a null string.
169 */
170
171static void
172nextslist(sl, np)
173    Char *sl;
174    Char *np;
175{
176    if (!*sl)
177	*np = '\000';
178    else if (*sl == ':') {
179	*np++ = '.';
180	*np = '\000';
181    }
182    else {
183	while (*sl && *sl != ':')
184	    *np++ = *sl++;
185	*np = '\000';
186    }
187}
188
189/*
190 * skipslist returns the pointer to the next entry in the search list.
191 */
192
193static Char *
194skipslist(sl)
195    Char *sl;
196{
197    while (*sl && *sl++ != ':')
198	continue;
199    return (sl);
200}
201