1167465Smp/* $Header: /p/tcsh/cvsroot/tcsh/tw.help.c,v 3.27 2006/08/24 20:56:31 christos Exp $ */
259243Sobrien/* tw.help.c: actually look up and print documentation on a file.
359243Sobrien *	      Look down the path for an appropriate file, then print it.
459243Sobrien *	      Note that the printing is NOT PAGED.  This is because the
559243Sobrien *	      function is NOT meant to look at manual pages, it only does so
659243Sobrien *	      if there is no .help file to look in.
759243Sobrien */
859243Sobrien/*-
959243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
1059243Sobrien * All rights reserved.
1159243Sobrien *
1259243Sobrien * Redistribution and use in source and binary forms, with or without
1359243Sobrien * modification, are permitted provided that the following conditions
1459243Sobrien * are met:
1559243Sobrien * 1. Redistributions of source code must retain the above copyright
1659243Sobrien *    notice, this list of conditions and the following disclaimer.
1759243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1859243Sobrien *    notice, this list of conditions and the following disclaimer in the
1959243Sobrien *    documentation and/or other materials provided with the distribution.
20100616Smp * 3. Neither the name of the University nor the names of its contributors
2159243Sobrien *    may be used to endorse or promote products derived from this software
2259243Sobrien *    without specific prior written permission.
2359243Sobrien *
2459243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2559243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2659243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2759243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2859243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2959243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3059243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3159243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3259243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3359243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3459243Sobrien * SUCH DAMAGE.
3559243Sobrien */
3659243Sobrien#include "sh.h"
3759243Sobrien
38167465SmpRCSID("$tcsh: tw.help.c,v 3.27 2006/08/24 20:56:31 christos Exp $")
3959243Sobrien
4059243Sobrien#include "tw.h"
4159243Sobrien#include "tc.h"
4259243Sobrien
4359243Sobrien
4459243Sobrienstatic int f = -1;
45167465Smpstatic	void		 cleanf		(int);
46167465Smpstatic	Char    	*skipslist	(Char *);
47167465Smpstatic	void		 nextslist 	(const Char *, Char *);
4859243Sobrien
49167465Smpstatic const char *const h_ext[] = {
5059243Sobrien    ".help", ".1", ".8", ".6", "", NULL
5159243Sobrien};
5259243Sobrien
5359243Sobrienvoid
54167465Smpdo_help(const Char *command)
5559243Sobrien{
56167465Smp    Char   *name, *cmd_p;
5759243Sobrien
58167465Smp    /* trim off the whitespace at the beginning */
59167465Smp    while (*command == ' ' || *command == '\t')
60167465Smp        command++;
6159243Sobrien
6259243Sobrien    /* copy the string to a safe place */
63167465Smp    name = Strsave(command);
64167465Smp    cleanup_push(name, xfree);
6559243Sobrien
6659243Sobrien    /* trim off the whitespace that may be at the end */
67167465Smp    for (cmd_p = name;
6859243Sobrien	 *cmd_p != ' ' && *cmd_p != '\t' && *cmd_p != '\0'; cmd_p++)
6959243Sobrien	continue;
7059243Sobrien    *cmd_p = '\0';
7159243Sobrien
7259243Sobrien    /* if nothing left, return */
73167465Smp    if (*name == '\0') {
74167465Smp	cleanup_until(name);
7559243Sobrien	return;
76167465Smp    }
7759243Sobrien
7859243Sobrien    if (adrof1(STRhelpcommand, &aliases)) {	/* if we have an alias */
7959243Sobrien	jmp_buf_t osetexit;
80167465Smp	size_t omark;
8159243Sobrien
8259243Sobrien	getexit(osetexit);	/* make sure to come back here */
83167465Smp	omark = cleanup_push_mark();
8459243Sobrien	if (setexit() == 0)
8559243Sobrien	    aliasrun(2, STRhelpcommand, name);	/* then use it. */
86167465Smp	cleanup_pop_mark(omark);
8759243Sobrien	resexit(osetexit);	/* and finish up */
8859243Sobrien    }
8959243Sobrien    else {			/* else cat something to them */
90167465Smp	Char *thpath, *hpath;	/* The environment parameter */
91167465Smp	Char *curdir;	        /* Current directory being looked at */
92167465Smp	struct Strbuf full = Strbuf_INIT;
93167465Smp
9459243Sobrien	/* got is, now "cat" the file based on the path $HPATH */
9559243Sobrien
9659243Sobrien	hpath = str2short(getenv(SEARCHLIST));
9759243Sobrien	if (hpath == NULL)
9859243Sobrien	    hpath = str2short(DEFAULTLIST);
9959243Sobrien	thpath = hpath = Strsave(hpath);
100167465Smp	cleanup_push(thpath, xfree);
101167465Smp	curdir = xmalloc((Strlen(thpath) + 1) * sizeof (*curdir));
102167465Smp	cleanup_push(curdir, xfree);
103167465Smp	cleanup_push(&full, Strbuf_cleanup);
10459243Sobrien
10559243Sobrien	for (;;) {
106167465Smp	    const char *const *sp;
107167465Smp	    size_t ep;
108167465Smp
10959243Sobrien	    if (!*hpath) {
11059243Sobrien		xprintf(CGETS(29, 1, "No help file for %S\n"), name);
11159243Sobrien		break;
11259243Sobrien	    }
11359243Sobrien	    nextslist(hpath, curdir);
11459243Sobrien	    hpath = skipslist(hpath);
11559243Sobrien
11659243Sobrien	    /*
11759243Sobrien	     * now make the full path name - try first /bar/foo.help, then
11859243Sobrien	     * /bar/foo.1, /bar/foo.8, then finally /bar/foo.6.  This is so
11959243Sobrien	     * that you don't spit a binary at the tty when $HPATH == $PATH.
12059243Sobrien	     */
121167465Smp	    full.len = 0;
122167465Smp	    Strbuf_append(&full, curdir);
123167465Smp	    Strbuf_append(&full, STRslash);
124167465Smp	    Strbuf_append(&full, name);
125167465Smp	    ep = full.len;
12659243Sobrien	    for (sp = h_ext; *sp; sp++) {
127167465Smp		full.len = ep;
128167465Smp		Strbuf_append(&full, str2short(*sp));
129167465Smp		Strbuf_terminate(&full);
130167465Smp		if ((f = xopen(short2str(full.s), O_RDONLY|O_LARGEFILE)) != -1)
13159243Sobrien		    break;
13259243Sobrien	    }
13359243Sobrien	    if (f != -1) {
134167465Smp	        unsigned char buf[512];
135167465Smp		sigset_t oset, set;
136167465Smp		struct sigaction osa, sa;
137167465Smp		ssize_t len;
138167465Smp
13959243Sobrien		/* so cat it to the terminal */
140167465Smp		cleanup_push(&f, open_cleanup);
141167465Smp		sa.sa_handler = cleanf;
142167465Smp		sigemptyset(&sa.sa_mask);
143167465Smp		sa.sa_flags = 0;
144167465Smp		(void)sigaction(SIGINT, &sa, &osa);
145167465Smp		cleanup_push(&osa, sigint_cleanup);
146167465Smp		(void)sigprocmask(SIG_UNBLOCK, &set, &oset);
147167465Smp		cleanup_push(&oset, sigprocmask_cleanup);
148167465Smp		while ((len = xread(f, buf, sizeof(buf))) > 0)
149167465Smp		    (void) xwrite(SHOUT, buf, len);
150167465Smp		cleanup_until(&f);
15159243Sobrien#ifdef convex
15259243Sobrien		/* print error in case file is migrated */
15359243Sobrien		if (len == -1)
15459243Sobrien		    stderror(ERR_SYSTEM, progname, strerror(errno));
15559243Sobrien#endif /* convex */
15659243Sobrien		break;
15759243Sobrien	    }
15859243Sobrien	}
15959243Sobrien    }
160167465Smp    cleanup_until(name);
16159243Sobrien}
16259243Sobrien
163167465Smpstatic void
16459243Sobrien/*ARGSUSED*/
165167465Smpcleanf(int snum)
16659243Sobrien{
16759415Sobrien    USE(snum);
16859243Sobrien    if (f != -1)
169167465Smp	xclose(f);
17059243Sobrien    f = -1;
17159243Sobrien}
17259243Sobrien
17359243Sobrien/* these next two are stolen from CMU's man(1) command for looking down
17459243Sobrien * paths.  they are prety straight forward. */
17559243Sobrien
17659243Sobrien/*
17759243Sobrien * nextslist takes a search list and copies the next path in it
17859243Sobrien * to np.  A null search list entry is expanded to ".".
17959243Sobrien * If there are no entries in the search list, then np will point
18059243Sobrien * to a null string.
18159243Sobrien */
18259243Sobrien
18359243Sobrienstatic void
184167465Smpnextslist(const Char *sl, Char *np)
18559243Sobrien{
18659243Sobrien    if (!*sl)
18759243Sobrien	*np = '\000';
18859243Sobrien    else if (*sl == ':') {
18959243Sobrien	*np++ = '.';
19059243Sobrien	*np = '\000';
19159243Sobrien    }
19259243Sobrien    else {
19359243Sobrien	while (*sl && *sl != ':')
19459243Sobrien	    *np++ = *sl++;
19559243Sobrien	*np = '\000';
19659243Sobrien    }
19759243Sobrien}
19859243Sobrien
19959243Sobrien/*
20059243Sobrien * skipslist returns the pointer to the next entry in the search list.
20159243Sobrien */
20259243Sobrien
20359243Sobrienstatic Char *
204167465Smpskipslist(Char *sl)
20559243Sobrien{
20659243Sobrien    while (*sl && *sl++ != ':')
20759243Sobrien	continue;
20859243Sobrien    return (sl);
20959243Sobrien}
210