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