xref: /freebsd/contrib/tcsh/tw.help.c (revision 1e66f787c838b5af7de716e266caf4e5d190d54b)
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