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