xref: /freebsd/contrib/tcsh/tw.help.c (revision a3e8fd0b7f663db7eafff527d5c3ca3bcfa8a537)
1 /* $Header: /src/pub/tcsh/tw.help.c,v 3.18 2002/03/08 17:36:47 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("$Id: tw.help.c,v 3.18 2002/03/08 17:36:47 christos Exp $")
39 
40 #include "tw.h"
41 #include "tc.h"
42 
43 
44 static int f = -1;
45 static	sigret_t	 cleanf		__P((int));
46 static	Char    	*skipslist	__P((Char *));
47 static	void		 nextslist 	__P((Char *, Char *));
48 
49 static char *h_ext[] = {
50     ".help", ".1", ".8", ".6", "", NULL
51 };
52 
53 void
54 do_help(command)
55     Char   *command;
56 {
57     Char    name[FILSIZ + 1];
58     Char   *cmd_p, *ep;
59     char  **sp;
60 
61     signalfun_t orig_intr;
62     Char    curdir[MAXPATHLEN];	/* Current directory being looked at */
63     register 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)) != -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 
146 static  sigret_t
147 /*ARGSUSED*/
148 cleanf(snum)
149 int 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 #ifndef SIGVOID
160     return (snum);
161 #endif
162 }
163 
164 /* these next two are stolen from CMU's man(1) command for looking down
165  * paths.  they are prety straight forward. */
166 
167 /*
168  * nextslist takes a search list and copies the next path in it
169  * to np.  A null search list entry is expanded to ".".
170  * If there are no entries in the search list, then np will point
171  * to a null string.
172  */
173 
174 static void
175 nextslist(sl, np)
176     register Char *sl;
177     register Char *np;
178 {
179     if (!*sl)
180 	*np = '\000';
181     else if (*sl == ':') {
182 	*np++ = '.';
183 	*np = '\000';
184     }
185     else {
186 	while (*sl && *sl != ':')
187 	    *np++ = *sl++;
188 	*np = '\000';
189     }
190 }
191 
192 /*
193  * skipslist returns the pointer to the next entry in the search list.
194  */
195 
196 static Char *
197 skipslist(sl)
198     register Char *sl;
199 {
200     while (*sl && *sl++ != ':')
201 	continue;
202     return (sl);
203 }
204