17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright 1998,2001-2003 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1985 Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
127c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #include <setjmp.h>
167c478bd9Sstevel@tonic-gate #include <euc.h>
177c478bd9Sstevel@tonic-gate #include <widec.h>
187c478bd9Sstevel@tonic-gate #include "restore.h"
197c478bd9Sstevel@tonic-gate #include <ctype.h>
207c478bd9Sstevel@tonic-gate #include <limits.h>
217c478bd9Sstevel@tonic-gate #include <sys/wait.h>
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate extern eucwidth_t wp;
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #define	round(a, b) ((((a) + (b) - 1) / (b)) * (b))
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Things to handle interruptions.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate static jmp_buf reset;
317c478bd9Sstevel@tonic-gate static int reset_OK;
327c478bd9Sstevel@tonic-gate static char *nextarg = NULL;
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate static int dontexpand;	/* co-routine state set in getnext, used in expandarg */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate static void getcmd(char *, char *, size_t, char *, size_t, struct arglist *);
377c478bd9Sstevel@tonic-gate static void expandarg(char *, struct arglist *);
387c478bd9Sstevel@tonic-gate static void printlist(char *, ino_t, char *, int);
397c478bd9Sstevel@tonic-gate static void formatf(struct arglist *);
407c478bd9Sstevel@tonic-gate static char *copynext(char *, char *, size_t);
417c478bd9Sstevel@tonic-gate static int fcmp(struct afile *, struct afile *);
427c478bd9Sstevel@tonic-gate static char *fmtentry(struct afile *);
437c478bd9Sstevel@tonic-gate static void setpagercmd(void);
447c478bd9Sstevel@tonic-gate static uint_t setpagerargs(char **);
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * Read and execute commands from the terminal.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate void
runcmdshell(void)507c478bd9Sstevel@tonic-gate runcmdshell(void)
517c478bd9Sstevel@tonic-gate {
527c478bd9Sstevel@tonic-gate 	struct entry *np;
537c478bd9Sstevel@tonic-gate 	ino_t ino;
547c478bd9Sstevel@tonic-gate 	static struct arglist alist = { 0, 0, 0, 0, 0 };
557c478bd9Sstevel@tonic-gate 	char curdir[MAXCOMPLEXLEN];
567c478bd9Sstevel@tonic-gate 	char name[MAXCOMPLEXLEN];
577c478bd9Sstevel@tonic-gate 	char cmd[BUFSIZ];
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #ifdef	lint
607c478bd9Sstevel@tonic-gate 	curdir[0] = '\0';
617c478bd9Sstevel@tonic-gate #endif	/* lint */
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	canon("/", curdir, sizeof (curdir));
647c478bd9Sstevel@tonic-gate loop:
657c478bd9Sstevel@tonic-gate 	if (setjmp(reset) != 0) {
667c478bd9Sstevel@tonic-gate 		for (; alist.head < alist.last; alist.head++)
677c478bd9Sstevel@tonic-gate 			freename(alist.head->fname);
687c478bd9Sstevel@tonic-gate 		nextarg = NULL;
697c478bd9Sstevel@tonic-gate 		volno = 0;
707c478bd9Sstevel@tonic-gate 		goto loop;	/* make sure jmpbuf is up-to-date */
717c478bd9Sstevel@tonic-gate 	}
727c478bd9Sstevel@tonic-gate 	reset_OK = 1;
737c478bd9Sstevel@tonic-gate 	getcmd(curdir, cmd, sizeof (cmd), name, sizeof (name), &alist);
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	/*
767c478bd9Sstevel@tonic-gate 	 * Using strncmp() to catch unique prefixes.
777c478bd9Sstevel@tonic-gate 	 */
787c478bd9Sstevel@tonic-gate 	switch (cmd[0]) {
797c478bd9Sstevel@tonic-gate 	/*
807c478bd9Sstevel@tonic-gate 	 * Add elements to the extraction list.
817c478bd9Sstevel@tonic-gate 	 */
827c478bd9Sstevel@tonic-gate 	case 'a':
837c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "add", strlen(cmd)) != 0)
847c478bd9Sstevel@tonic-gate 			goto bad;
857c478bd9Sstevel@tonic-gate 		if (name[0] == '\0')
867c478bd9Sstevel@tonic-gate 			break;
877c478bd9Sstevel@tonic-gate 		ino = dirlookup(name);
887c478bd9Sstevel@tonic-gate 		if (ino == 0)
897c478bd9Sstevel@tonic-gate 			break;
907c478bd9Sstevel@tonic-gate 		if (mflag)
917c478bd9Sstevel@tonic-gate 			pathcheck(name);
927c478bd9Sstevel@tonic-gate 		treescan(name, ino, addfile);
937c478bd9Sstevel@tonic-gate 		break;
947c478bd9Sstevel@tonic-gate 	/*
957c478bd9Sstevel@tonic-gate 	 * Change working directory.
967c478bd9Sstevel@tonic-gate 	 */
977c478bd9Sstevel@tonic-gate 	case 'c':
987c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "cd", strlen(cmd)) != 0)
997c478bd9Sstevel@tonic-gate 			goto bad;
1007c478bd9Sstevel@tonic-gate 		if (name[0] == '\0')
1017c478bd9Sstevel@tonic-gate 			break;
1027c478bd9Sstevel@tonic-gate 		ino = dirlookup(name);
1037c478bd9Sstevel@tonic-gate 		if (ino == 0)
1047c478bd9Sstevel@tonic-gate 			break;
1057c478bd9Sstevel@tonic-gate 		if (inodetype(ino) == LEAF) {
1067c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
107*d9529689SToomas Soome 			    gettext("%s: not a directory\n"), name);
1087c478bd9Sstevel@tonic-gate 			break;
1097c478bd9Sstevel@tonic-gate 		}
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 		/* No need to canon(name), getcmd() did it for us */
1127c478bd9Sstevel@tonic-gate 		(void) strncpy(curdir, name, sizeof (curdir));
1137c478bd9Sstevel@tonic-gate 		curdir[sizeof (curdir) - 1] = '\0';
1147c478bd9Sstevel@tonic-gate 		break;
1157c478bd9Sstevel@tonic-gate 	/*
1167c478bd9Sstevel@tonic-gate 	 * Delete elements from the extraction list.
1177c478bd9Sstevel@tonic-gate 	 */
1187c478bd9Sstevel@tonic-gate 	case 'd':
1197c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "delete", strlen(cmd)) != 0)
1207c478bd9Sstevel@tonic-gate 			goto bad;
1217c478bd9Sstevel@tonic-gate 		if (name[0] == '\0')
1227c478bd9Sstevel@tonic-gate 			break;
1237c478bd9Sstevel@tonic-gate 		np = lookupname(name);
1247c478bd9Sstevel@tonic-gate 		if (np == NIL || (np->e_flags & NEW) == 0) {
1257c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
126*d9529689SToomas Soome 			    gettext("%s: not on extraction list\n"), name);
1277c478bd9Sstevel@tonic-gate 			break;
1287c478bd9Sstevel@tonic-gate 		}
1297c478bd9Sstevel@tonic-gate 		treescan(name, np->e_ino, deletefile);
1307c478bd9Sstevel@tonic-gate 		break;
1317c478bd9Sstevel@tonic-gate 	/*
1327c478bd9Sstevel@tonic-gate 	 * Extract the requested list.
1337c478bd9Sstevel@tonic-gate 	 */
1347c478bd9Sstevel@tonic-gate 	case 'e':
1357c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "extract", strlen(cmd)) != 0)
1367c478bd9Sstevel@tonic-gate 			goto bad;
1377c478bd9Sstevel@tonic-gate 		attrscan(0, addfile);
1387c478bd9Sstevel@tonic-gate 		createfiles();
1397c478bd9Sstevel@tonic-gate 		createlinks();
1407c478bd9Sstevel@tonic-gate 		setdirmodes();
1417c478bd9Sstevel@tonic-gate 		if (dflag)
1427c478bd9Sstevel@tonic-gate 			checkrestore();
1437c478bd9Sstevel@tonic-gate 		volno = 0;
1447c478bd9Sstevel@tonic-gate 		break;
1457c478bd9Sstevel@tonic-gate 	/*
1467c478bd9Sstevel@tonic-gate 	 * List available commands.
1477c478bd9Sstevel@tonic-gate 	 */
1487c478bd9Sstevel@tonic-gate 	case 'h':
1497c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "help", strlen(cmd)) != 0)
1507c478bd9Sstevel@tonic-gate 			goto bad;
1517c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
1527c478bd9Sstevel@tonic-gate 	case '?':
1537c478bd9Sstevel@tonic-gate 		/* ANSI string catenation, to shut cstyle up */
1547c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s",
155*d9529689SToomas Soome 		    gettext("Available commands are:\n"
1567c478bd9Sstevel@tonic-gate "\tls [arg] - list directory\n"
1577c478bd9Sstevel@tonic-gate "\tmarked [arg] - list items marked for extraction from directory\n"
1587c478bd9Sstevel@tonic-gate "\tcd arg - change directory\n"
1597c478bd9Sstevel@tonic-gate "\tpwd - print current directory\n"
1607c478bd9Sstevel@tonic-gate "\tadd [arg] - add `arg' to list of files to be extracted\n"
1617c478bd9Sstevel@tonic-gate "\tdelete [arg] - delete `arg' from list of files to be extracted\n"
1627c478bd9Sstevel@tonic-gate "\textract - extract requested files\n"
1637c478bd9Sstevel@tonic-gate "\tsetmodes - set modes of requested directories\n"
1647c478bd9Sstevel@tonic-gate "\tquit - immediately exit program\n"
1657c478bd9Sstevel@tonic-gate "\twhat - list dump header information\n"
1667c478bd9Sstevel@tonic-gate "\tverbose - toggle verbose flag (useful with ``ls'')\n"
1677c478bd9Sstevel@tonic-gate "\tpaginate - toggle pagination flag (affects ``ls'' and ``marked'')\n"
1687c478bd9Sstevel@tonic-gate "\tsetpager - set pagination command and arguments\n"
1697c478bd9Sstevel@tonic-gate "\thelp or `?' - print this list\n"
1707c478bd9Sstevel@tonic-gate "If no `arg' is supplied, the current directory is used\n"));
1717c478bd9Sstevel@tonic-gate 		break;
1727c478bd9Sstevel@tonic-gate 	/*
1737c478bd9Sstevel@tonic-gate 	 * List a directory.
1747c478bd9Sstevel@tonic-gate 	 */
1757c478bd9Sstevel@tonic-gate 	case 'l':
1767c478bd9Sstevel@tonic-gate 	case 'm':
1777c478bd9Sstevel@tonic-gate 		if ((strncmp(cmd, "ls", strlen(cmd)) != 0) &&
1787c478bd9Sstevel@tonic-gate 		    (strncmp(cmd, "marked", strlen(cmd)) != 0))
1797c478bd9Sstevel@tonic-gate 			goto bad;
1807c478bd9Sstevel@tonic-gate 		if (name[0] == '\0')
1817c478bd9Sstevel@tonic-gate 			break;
1827c478bd9Sstevel@tonic-gate 		ino = dirlookup(name);
1837c478bd9Sstevel@tonic-gate 		if (ino == 0)
1847c478bd9Sstevel@tonic-gate 			break;
1857c478bd9Sstevel@tonic-gate 		printlist(name, ino, curdir, *cmd == 'm');
1867c478bd9Sstevel@tonic-gate 		break;
1877c478bd9Sstevel@tonic-gate 	/*
1887c478bd9Sstevel@tonic-gate 	 * Print current directory or enable pagination.
1897c478bd9Sstevel@tonic-gate 	 */
1907c478bd9Sstevel@tonic-gate 	case 'p':
1917c478bd9Sstevel@tonic-gate 		if (strlen(cmd) < 2)
1927c478bd9Sstevel@tonic-gate 			goto ambiguous;
1937c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "pwd", strlen(cmd)) == 0) {
1947c478bd9Sstevel@tonic-gate 			if (curdir[1] == '\0') {
1957c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "/\n");
1967c478bd9Sstevel@tonic-gate 			} else {
1977c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s\n", &curdir[1]);
1987c478bd9Sstevel@tonic-gate 			}
1997c478bd9Sstevel@tonic-gate 		} else if (strncmp(cmd, "paginate", strlen(cmd)) == 0) {
2007c478bd9Sstevel@tonic-gate 			if (paginating) {
2017c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
2027c478bd9Sstevel@tonic-gate 				    gettext("paging disabled\n"));
2037c478bd9Sstevel@tonic-gate 				paginating = 0;
2047c478bd9Sstevel@tonic-gate 				break;
2057c478bd9Sstevel@tonic-gate 			}
2067c478bd9Sstevel@tonic-gate 			if (vflag) {
2077c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
2087c478bd9Sstevel@tonic-gate 				    gettext("paging enabled (%s)\n"),
2097c478bd9Sstevel@tonic-gate 				    pager_catenated);
2107c478bd9Sstevel@tonic-gate 			} else {
2117c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
2127c478bd9Sstevel@tonic-gate 				    gettext("paging enabled\n"));
2137c478bd9Sstevel@tonic-gate 			}
2147c478bd9Sstevel@tonic-gate 			if (dflag) {
2157c478bd9Sstevel@tonic-gate 				int index = 0;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 				while (index < pager_len) {
2187c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
2197c478bd9Sstevel@tonic-gate 					    ">>>pager_vector[%d] = `%s'\n",
2207c478bd9Sstevel@tonic-gate 					    index,
2217c478bd9Sstevel@tonic-gate 					    pager_vector[index] ?
222*d9529689SToomas Soome 					    pager_vector[index] : "(null)");
2237c478bd9Sstevel@tonic-gate 					index += 1;
2247c478bd9Sstevel@tonic-gate 				}
2257c478bd9Sstevel@tonic-gate 			}
2267c478bd9Sstevel@tonic-gate 			paginating = 1;
2277c478bd9Sstevel@tonic-gate 		} else {
2287c478bd9Sstevel@tonic-gate 			goto bad;
2297c478bd9Sstevel@tonic-gate 		}
2307c478bd9Sstevel@tonic-gate 		break;
2317c478bd9Sstevel@tonic-gate 	/*
2327c478bd9Sstevel@tonic-gate 	 * Quit.
2337c478bd9Sstevel@tonic-gate 	 */
2347c478bd9Sstevel@tonic-gate 	case 'q':
2357c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "quit", strlen(cmd)) != 0)
2367c478bd9Sstevel@tonic-gate 			goto bad;
2377c478bd9Sstevel@tonic-gate 		reset_OK = 0;
2387c478bd9Sstevel@tonic-gate 		return;
2397c478bd9Sstevel@tonic-gate 	case 'x':
2407c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "xit", strlen(cmd)) != 0)
2417c478bd9Sstevel@tonic-gate 			goto bad;
2427c478bd9Sstevel@tonic-gate 		reset_OK = 0;
2437c478bd9Sstevel@tonic-gate 		return;
2447c478bd9Sstevel@tonic-gate 	/*
2457c478bd9Sstevel@tonic-gate 	 * Toggle verbose mode.
2467c478bd9Sstevel@tonic-gate 	 */
2477c478bd9Sstevel@tonic-gate 	case 'v':
2487c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "verbose", strlen(cmd)) != 0)
2497c478bd9Sstevel@tonic-gate 			goto bad;
2507c478bd9Sstevel@tonic-gate 		if (vflag) {
2517c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("verbose mode off\n"));
2527c478bd9Sstevel@tonic-gate 			vflag = 0;
2537c478bd9Sstevel@tonic-gate 			break;
2547c478bd9Sstevel@tonic-gate 		}
2557c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("verbose mode on\n"));
2567c478bd9Sstevel@tonic-gate 		vflag = 1;
2577c478bd9Sstevel@tonic-gate 		break;
2587c478bd9Sstevel@tonic-gate 	/*
2597c478bd9Sstevel@tonic-gate 	 * Just restore requested directory modes, or set pagination command.
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	case 's':
2627c478bd9Sstevel@tonic-gate 		if (strlen(cmd) < 4)
2637c478bd9Sstevel@tonic-gate 			goto ambiguous;
2647c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "setmodes", strlen(cmd)) == 0) {
2657c478bd9Sstevel@tonic-gate 			setdirmodes();
2667c478bd9Sstevel@tonic-gate 		} else if (strncmp(cmd, "setpager", strlen(cmd)) == 0) {
2677c478bd9Sstevel@tonic-gate 			setpagercmd();
2687c478bd9Sstevel@tonic-gate 		} else {
2697c478bd9Sstevel@tonic-gate 			goto bad;
2707c478bd9Sstevel@tonic-gate 		}
2717c478bd9Sstevel@tonic-gate 		break;
2727c478bd9Sstevel@tonic-gate 	/*
2737c478bd9Sstevel@tonic-gate 	 * Print out dump header information.
2747c478bd9Sstevel@tonic-gate 	 */
2757c478bd9Sstevel@tonic-gate 	case 'w':
2767c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "what", strlen(cmd)) != 0)
2777c478bd9Sstevel@tonic-gate 			goto bad;
2787c478bd9Sstevel@tonic-gate 		printdumpinfo();
2797c478bd9Sstevel@tonic-gate 		break;
2807c478bd9Sstevel@tonic-gate 	/*
2817c478bd9Sstevel@tonic-gate 	 * Turn on debugging.
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate 	case 'D':
2847c478bd9Sstevel@tonic-gate 		if (strncmp(cmd, "Debug", strlen(cmd)) != 0)
2857c478bd9Sstevel@tonic-gate 			goto bad;
2867c478bd9Sstevel@tonic-gate 		if (dflag) {
2877c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("debugging mode off\n"));
2887c478bd9Sstevel@tonic-gate 			dflag = 0;
2897c478bd9Sstevel@tonic-gate 			break;
2907c478bd9Sstevel@tonic-gate 		}
2917c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("debugging mode on\n"));
2927c478bd9Sstevel@tonic-gate 		dflag++;
2937c478bd9Sstevel@tonic-gate 		break;
2947c478bd9Sstevel@tonic-gate 	/*
2957c478bd9Sstevel@tonic-gate 	 * Unknown command.
2967c478bd9Sstevel@tonic-gate 	 */
2977c478bd9Sstevel@tonic-gate 	default:
2987c478bd9Sstevel@tonic-gate 	bad:
2997c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
300*d9529689SToomas Soome 		    gettext("%s: unknown command; type ? for help\n"), cmd);
3017c478bd9Sstevel@tonic-gate 		break;
3027c478bd9Sstevel@tonic-gate 	ambiguous:
3037c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
3047c478bd9Sstevel@tonic-gate 		    gettext("%s: ambiguous command; type ? for help\n"), cmd);
3057c478bd9Sstevel@tonic-gate 		break;
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 	goto loop;
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate static char input[MAXCOMPLEXLEN]; /* shared by getcmd() and setpagercmd() */
3117c478bd9Sstevel@tonic-gate #define	rawname input	/* save space by reusing input buffer */
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate /*
3147c478bd9Sstevel@tonic-gate  * Read and parse an interactive command.
3157c478bd9Sstevel@tonic-gate  * The first word on the line is assigned to "cmd". If
3167c478bd9Sstevel@tonic-gate  * there are no arguments on the command line, then "curdir"
3177c478bd9Sstevel@tonic-gate  * is returned as the argument. If there are arguments
3187c478bd9Sstevel@tonic-gate  * on the line they are returned one at a time on each
3197c478bd9Sstevel@tonic-gate  * successive call to getcmd. Each argument is first assigned
3207c478bd9Sstevel@tonic-gate  * to "name". If it does not start with "/" the pathname in
3217c478bd9Sstevel@tonic-gate  * "curdir" is prepended to it. Finally "canon" is called to
3227c478bd9Sstevel@tonic-gate  * eliminate any embedded ".." components.
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate /* ARGSUSED */
3257c478bd9Sstevel@tonic-gate static void
getcmd(char * curdir,char * cmd,size_t cmdsiz,char * name,size_t namesiz,struct arglist * ap)326*d9529689SToomas Soome getcmd(char *curdir, char *cmd, size_t cmdsiz, char *name, size_t namesiz,
327*d9529689SToomas Soome     struct arglist *ap)
3287c478bd9Sstevel@tonic-gate {
3297c478bd9Sstevel@tonic-gate 	char *cp;
3307c478bd9Sstevel@tonic-gate 	char output[MAXCOMPLEXLEN];
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	/*
3337c478bd9Sstevel@tonic-gate 	 * Check to see if still processing arguments.
3347c478bd9Sstevel@tonic-gate 	 */
3357c478bd9Sstevel@tonic-gate 	if (ap->head != ap->last) {
3367c478bd9Sstevel@tonic-gate 		(void) strncpy(name, ap->head->fname, namesiz);
3377c478bd9Sstevel@tonic-gate 		name[namesiz - 1] = '\0';
3387c478bd9Sstevel@tonic-gate 		/* double null terminate string */
3397c478bd9Sstevel@tonic-gate 		if ((strlen(name) + 2) > namesiz) {
3407c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext("name is too long, ignoring"));
3417c478bd9Sstevel@tonic-gate 			memset(name, 0, namesiz);
3427c478bd9Sstevel@tonic-gate 		} else {
3437c478bd9Sstevel@tonic-gate 			name[strlen(name) + 1] = '\0';
3447c478bd9Sstevel@tonic-gate 		}
3457c478bd9Sstevel@tonic-gate 		freename(ap->head->fname);
3467c478bd9Sstevel@tonic-gate 		ap->head++;
3477c478bd9Sstevel@tonic-gate 		return;
3487c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate 	if (nextarg != NULL)
3507c478bd9Sstevel@tonic-gate 		goto getnext;
3517c478bd9Sstevel@tonic-gate 	/*
3527c478bd9Sstevel@tonic-gate 	 * Read a command line and trim off trailing white space.
3537c478bd9Sstevel@tonic-gate 	 */
3547c478bd9Sstevel@tonic-gate readagain:
3557c478bd9Sstevel@tonic-gate 	do {
3567c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s > ", progname);
3577c478bd9Sstevel@tonic-gate 		(void) fflush(stderr);
3587c478bd9Sstevel@tonic-gate 		(void) fgets(input, sizeof (input), terminal);
3597c478bd9Sstevel@tonic-gate 	} while (!feof(terminal) && input[0] == '\n');
3607c478bd9Sstevel@tonic-gate 	if (feof(terminal)) {
3617c478bd9Sstevel@tonic-gate 		(void) strncpy(cmd, "quit", cmdsiz);
3627c478bd9Sstevel@tonic-gate 		return;
3637c478bd9Sstevel@tonic-gate 	}
3647c478bd9Sstevel@tonic-gate 	/* trim off trailing white space and newline */
3657c478bd9Sstevel@tonic-gate 	for (cp = &input[strlen(input) - 2];
3667c478bd9Sstevel@tonic-gate 	    cp >= &input[0] && isspace((uchar_t)*cp);
3677c478bd9Sstevel@tonic-gate 	    cp--) {
3687c478bd9Sstevel@tonic-gate 		continue;
3697c478bd9Sstevel@tonic-gate 		/*LINTED [empty loop body]*/
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 	*++cp = '\0';
3727c478bd9Sstevel@tonic-gate 	if ((strlen(input) + 2) > MAXCOMPLEXLEN) {
3737c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("command is too long\n"));
3747c478bd9Sstevel@tonic-gate 		goto readagain;
3757c478bd9Sstevel@tonic-gate 	} else {
3767c478bd9Sstevel@tonic-gate 		/* double null terminate string */
3777c478bd9Sstevel@tonic-gate 		*(cp + 1) = '\0';
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	if (cp == &input[0])
3817c478bd9Sstevel@tonic-gate 		goto readagain;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	/*
3847c478bd9Sstevel@tonic-gate 	 * Copy the command into "cmd".
3857c478bd9Sstevel@tonic-gate 	 */
3867c478bd9Sstevel@tonic-gate 	cp = copynext(input, cmd, cmdsiz);
3877c478bd9Sstevel@tonic-gate 	ap->cmd = cmd;
3887c478bd9Sstevel@tonic-gate 	/*
3897c478bd9Sstevel@tonic-gate 	 * If no argument, use curdir as the default.
3907c478bd9Sstevel@tonic-gate 	 */
3917c478bd9Sstevel@tonic-gate 	if (*cp == '\0') {
3927c478bd9Sstevel@tonic-gate 		(void) strncpy(name, curdir, namesiz);
3937c478bd9Sstevel@tonic-gate 		name[namesiz - 1] = '\0';
3947c478bd9Sstevel@tonic-gate 		/* double null terminate string */
3957c478bd9Sstevel@tonic-gate 		if ((strlen(name) + 2) > namesiz) {
3967c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext("name is too long, ignoring"));
3977c478bd9Sstevel@tonic-gate 			memset(name, 0, namesiz);
3987c478bd9Sstevel@tonic-gate 		} else {
3997c478bd9Sstevel@tonic-gate 			name[strlen(name) + 1] = '\0';
4007c478bd9Sstevel@tonic-gate 		}
4017c478bd9Sstevel@tonic-gate 		return;
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 	nextarg = cp;
4047c478bd9Sstevel@tonic-gate 	/*
4057c478bd9Sstevel@tonic-gate 	 * Find the next argument.
4067c478bd9Sstevel@tonic-gate 	 */
4077c478bd9Sstevel@tonic-gate getnext:
4087c478bd9Sstevel@tonic-gate 	cp = copynext(nextarg, rawname, sizeof (rawname));
4097c478bd9Sstevel@tonic-gate 	if (*cp == '\0')
4107c478bd9Sstevel@tonic-gate 		nextarg = NULL;
4117c478bd9Sstevel@tonic-gate 	else
4127c478bd9Sstevel@tonic-gate 		nextarg = cp;
4137c478bd9Sstevel@tonic-gate 	/*
4147c478bd9Sstevel@tonic-gate 	 * If it an absolute pathname, canonicalize it and return it.
4157c478bd9Sstevel@tonic-gate 	 */
4167c478bd9Sstevel@tonic-gate 	if (rawname[0] == '/') {
4177c478bd9Sstevel@tonic-gate 		canon(rawname, name, namesiz);
4187c478bd9Sstevel@tonic-gate 	} else {
4197c478bd9Sstevel@tonic-gate 		/*
4207c478bd9Sstevel@tonic-gate 		 * For relative pathnames, prepend the current directory to
4217c478bd9Sstevel@tonic-gate 		 * it then canonicalize and return it.
4227c478bd9Sstevel@tonic-gate 		 */
4237c478bd9Sstevel@tonic-gate 		(void) snprintf(output, sizeof (output), "%s/%s",
4247c478bd9Sstevel@tonic-gate 		    curdir, rawname);
4257c478bd9Sstevel@tonic-gate 		canon(output, name, namesiz);
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 	expandarg(name, ap);
4287c478bd9Sstevel@tonic-gate 	/*
4297c478bd9Sstevel@tonic-gate 	 * ap->head->fname guaranteed to be double null-terminated and
4307c478bd9Sstevel@tonic-gate 	 * no more than MAXCOMPLEXLEN characters long.
4317c478bd9Sstevel@tonic-gate 	 */
4327c478bd9Sstevel@tonic-gate 	assert(namesiz >= (MAXCOMPLEXLEN));
4337c478bd9Sstevel@tonic-gate 	(void) strcpy(name, ap->head->fname);
4347c478bd9Sstevel@tonic-gate 	/* double null terminate string */
4357c478bd9Sstevel@tonic-gate 	name[strlen(name) + 1] = '\0';
4367c478bd9Sstevel@tonic-gate 	freename(ap->head->fname);
4377c478bd9Sstevel@tonic-gate 	ap->head++;
4387c478bd9Sstevel@tonic-gate #undef	rawname
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate /*
4427c478bd9Sstevel@tonic-gate  * Strip off the next token of the input.
4437c478bd9Sstevel@tonic-gate  */
4447c478bd9Sstevel@tonic-gate static char *
copynext(char * input,char * output,size_t outsize)445*d9529689SToomas Soome copynext(char *input, char *output, size_t outsize)
4467c478bd9Sstevel@tonic-gate {
4477c478bd9Sstevel@tonic-gate 	char *cp, *bp, *limit;
4487c478bd9Sstevel@tonic-gate 	char quote;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	dontexpand = 0;
4517c478bd9Sstevel@tonic-gate 	/* skip to argument */
4527c478bd9Sstevel@tonic-gate 	for (cp = input; *cp != '\0' && isspace((uchar_t)*cp); cp++) {
4537c478bd9Sstevel@tonic-gate 		continue;
4547c478bd9Sstevel@tonic-gate 		/*LINTED [empty loop body]*/
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 	bp = output;
4577c478bd9Sstevel@tonic-gate 	limit = output + outsize - 1; /* -1 for the trailing \0 */
4587c478bd9Sstevel@tonic-gate 	while (!isspace((uchar_t)*cp) && *cp != '\0' && bp < limit) {
4597c478bd9Sstevel@tonic-gate 		/*
4607c478bd9Sstevel@tonic-gate 		 * Handle back slashes.
4617c478bd9Sstevel@tonic-gate 		 */
4627c478bd9Sstevel@tonic-gate 		if (*cp == '\\') {
4637c478bd9Sstevel@tonic-gate 			if (*++cp == '\0') {
4647c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
4657c478bd9Sstevel@tonic-gate 				    "command lines cannot be continued\n"));
4667c478bd9Sstevel@tonic-gate 				continue;
4677c478bd9Sstevel@tonic-gate 			}
4687c478bd9Sstevel@tonic-gate 			*bp++ = *cp++;
4697c478bd9Sstevel@tonic-gate 			continue;
4707c478bd9Sstevel@tonic-gate 		}
4717c478bd9Sstevel@tonic-gate 		/*
4727c478bd9Sstevel@tonic-gate 		 * The usual unquoted case.
4737c478bd9Sstevel@tonic-gate 		 */
4747c478bd9Sstevel@tonic-gate 		if (*cp != '\'' && *cp != '"') {
4757c478bd9Sstevel@tonic-gate 			*bp++ = *cp++;
4767c478bd9Sstevel@tonic-gate 			continue;
4777c478bd9Sstevel@tonic-gate 		}
4787c478bd9Sstevel@tonic-gate 		/*
4797c478bd9Sstevel@tonic-gate 		 * Handle single and double quotes.
4807c478bd9Sstevel@tonic-gate 		 */
4817c478bd9Sstevel@tonic-gate 		quote = *cp++;
4827c478bd9Sstevel@tonic-gate 		dontexpand = 1;
4837c478bd9Sstevel@tonic-gate 		while (*cp != quote && *cp != '\0' && bp < limit)
4847c478bd9Sstevel@tonic-gate 			*bp++ = *cp++;
4857c478bd9Sstevel@tonic-gate 		if (*cp++ == '\0') {
4867c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
4877c478bd9Sstevel@tonic-gate 			    gettext("missing %c\n"), (uchar_t)quote);
4887c478bd9Sstevel@tonic-gate 			cp--;
4897c478bd9Sstevel@tonic-gate 			continue;
4907c478bd9Sstevel@tonic-gate 		}
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 	*bp = '\0';
4937c478bd9Sstevel@tonic-gate 	if ((strlen(output) + 2) > outsize) {
4947c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(
4957c478bd9Sstevel@tonic-gate 		    "name is too long, ignoring"));
4967c478bd9Sstevel@tonic-gate 		memset(output, 0, outsize);
4977c478bd9Sstevel@tonic-gate 	} else {
4987c478bd9Sstevel@tonic-gate 		/* double null terminate string */
4997c478bd9Sstevel@tonic-gate 		*(bp + 1) = '\0';
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 	return (cp);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate /*
5057c478bd9Sstevel@tonic-gate  * Canonicalize file names to always start with ``./'' and
5067c478bd9Sstevel@tonic-gate  * remove any imbedded "." and ".." components.
5077c478bd9Sstevel@tonic-gate  *
5087c478bd9Sstevel@tonic-gate  * The pathname "canonname" is returned double null terminated.
5097c478bd9Sstevel@tonic-gate  */
5107c478bd9Sstevel@tonic-gate void
canon(char * rawname,char * canonname,size_t limit)511*d9529689SToomas Soome canon(char *rawname, char *canonname, size_t limit)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate 	char *cp, *np, *prefix;
5147c478bd9Sstevel@tonic-gate 	uint_t len;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	assert(limit > 3);
5177c478bd9Sstevel@tonic-gate 	if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
5187c478bd9Sstevel@tonic-gate 		prefix = "";
5197c478bd9Sstevel@tonic-gate 	else if (rawname[0] == '/')
5207c478bd9Sstevel@tonic-gate 		prefix = ".";
5217c478bd9Sstevel@tonic-gate 	else
5227c478bd9Sstevel@tonic-gate 		prefix = "./";
5237c478bd9Sstevel@tonic-gate 	(void) snprintf(canonname, limit, "%s%s", prefix, rawname);
5247c478bd9Sstevel@tonic-gate 	/*
5257c478bd9Sstevel@tonic-gate 	 * Eliminate multiple and trailing '/'s
5267c478bd9Sstevel@tonic-gate 	 */
5277c478bd9Sstevel@tonic-gate 	for (cp = np = canonname; *np != '\0'; cp++) {
5287c478bd9Sstevel@tonic-gate 		*cp = *np++;
5297c478bd9Sstevel@tonic-gate 		while (*cp == '/' && *np == '/')
5307c478bd9Sstevel@tonic-gate 			np++;
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 	*cp = '\0';
5337c478bd9Sstevel@tonic-gate 	if ((strlen(canonname) + 2) > limit) {
5347c478bd9Sstevel@tonic-gate 		fprintf(stderr,
5357c478bd9Sstevel@tonic-gate 		    gettext("canonical name is too long, ignoring name\n"));
5367c478bd9Sstevel@tonic-gate 		memset(canonname, 0, limit);
5377c478bd9Sstevel@tonic-gate 	} else {
5387c478bd9Sstevel@tonic-gate 		/* double null terminate string */
5397c478bd9Sstevel@tonic-gate 		*(cp + 1) = '\0';
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	if (*--cp == '/')
5437c478bd9Sstevel@tonic-gate 		*cp = '\0';
5447c478bd9Sstevel@tonic-gate 	/*
5457c478bd9Sstevel@tonic-gate 	 * Eliminate extraneous "." and ".." from pathnames.  Uses
5467c478bd9Sstevel@tonic-gate 	 * memmove(), as strcpy() might do the wrong thing for these
5477c478bd9Sstevel@tonic-gate 	 * small overlaps.
5487c478bd9Sstevel@tonic-gate 	 */
5497c478bd9Sstevel@tonic-gate 	np = canonname;
5507c478bd9Sstevel@tonic-gate 	while (*np != '\0') {
5517c478bd9Sstevel@tonic-gate 		np++;
5527c478bd9Sstevel@tonic-gate 		cp = np;
5537c478bd9Sstevel@tonic-gate 		while (*np != '/' && *np != '\0')
5547c478bd9Sstevel@tonic-gate 			np++;
5557c478bd9Sstevel@tonic-gate 		if (np - cp == 1 && *cp == '.') {
5567c478bd9Sstevel@tonic-gate 			cp--;
5577c478bd9Sstevel@tonic-gate 			len = strlen(np);
5587c478bd9Sstevel@tonic-gate 			(void) memmove(cp, np, len);
5597c478bd9Sstevel@tonic-gate 			*(cp + len) = '\0';
5607c478bd9Sstevel@tonic-gate 			/* double null terminate string */
5617c478bd9Sstevel@tonic-gate 			*(cp + len + 1) = '\0';
5627c478bd9Sstevel@tonic-gate 			np = cp;
5637c478bd9Sstevel@tonic-gate 		}
5647c478bd9Sstevel@tonic-gate 		if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
5657c478bd9Sstevel@tonic-gate 			cp--;
5667c478bd9Sstevel@tonic-gate 			/* find beginning of name */
5677c478bd9Sstevel@tonic-gate 			while (cp > &canonname[1] && *--cp != '/') {
5687c478bd9Sstevel@tonic-gate 				continue;
5697c478bd9Sstevel@tonic-gate 				/*LINTED [empty loop body]*/
5707c478bd9Sstevel@tonic-gate 			}
5717c478bd9Sstevel@tonic-gate 			len = strlen(np);
5727c478bd9Sstevel@tonic-gate 			(void) memmove(cp, np, len);
5737c478bd9Sstevel@tonic-gate 			*(cp + len) = '\0';
5747c478bd9Sstevel@tonic-gate 			/* double null terminate string */
5757c478bd9Sstevel@tonic-gate 			*(cp + len + 1) = '\0';
5767c478bd9Sstevel@tonic-gate 			np = cp;
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate }
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate /*
5827c478bd9Sstevel@tonic-gate  * globals (file name generation)
5837c478bd9Sstevel@tonic-gate  *
5847c478bd9Sstevel@tonic-gate  * "*" in params matches r.e ".*"
5857c478bd9Sstevel@tonic-gate  * "?" in params matches r.e. "."
5867c478bd9Sstevel@tonic-gate  * "[...]" in params matches character class
5877c478bd9Sstevel@tonic-gate  * "[...a-z...]" in params matches a through z.
5887c478bd9Sstevel@tonic-gate  */
5897c478bd9Sstevel@tonic-gate static void
expandarg(char * arg,struct arglist * ap)590*d9529689SToomas Soome expandarg(char *arg, struct arglist *ap)
5917c478bd9Sstevel@tonic-gate {
5927c478bd9Sstevel@tonic-gate 	static struct afile single;
5937c478bd9Sstevel@tonic-gate 	int size;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	ap->head = ap->last = (struct afile *)0;
5967c478bd9Sstevel@tonic-gate 	if (dontexpand)
5977c478bd9Sstevel@tonic-gate 		size = 0;
5987c478bd9Sstevel@tonic-gate 	else
5997c478bd9Sstevel@tonic-gate 		size = expand(arg, 0, ap);
6007c478bd9Sstevel@tonic-gate 	if (size == 0) {
6017c478bd9Sstevel@tonic-gate 		struct entry *ep;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 		ep = lookupname(arg);
6047c478bd9Sstevel@tonic-gate 		single.fnum = ep ? ep->e_ino : 0;
6057c478bd9Sstevel@tonic-gate 		single.fname = savename(arg);
6067c478bd9Sstevel@tonic-gate 		ap->head = &single;
6077c478bd9Sstevel@tonic-gate 		ap->last = ap->head + 1;
6087c478bd9Sstevel@tonic-gate 		return;
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 	if ((ap->last - ap->head) > ULONG_MAX) {
6117c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
6127c478bd9Sstevel@tonic-gate 		    gettext("Argument expansion too large to sort\n"));
6137c478bd9Sstevel@tonic-gate 	} else {
6147c478bd9Sstevel@tonic-gate 		/* LINTED pointer arith just range-checked */
6157c478bd9Sstevel@tonic-gate 		qsort((char *)ap->head, (size_t)(ap->last - ap->head),
6167c478bd9Sstevel@tonic-gate 		    sizeof (*ap->head),
6177c478bd9Sstevel@tonic-gate 		    (int (*)(const void *, const void *)) fcmp);
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate /*
6227c478bd9Sstevel@tonic-gate  * Do an "ls" style listing of a directory
6237c478bd9Sstevel@tonic-gate  */
6247c478bd9Sstevel@tonic-gate static void
printlist(char * name,ino_t ino,char * basename,int marked_only)625*d9529689SToomas Soome printlist(char *name, ino_t ino, char *basename, int marked_only)
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate 	struct afile *fp;
6287c478bd9Sstevel@tonic-gate 	struct direct *dp;
6297c478bd9Sstevel@tonic-gate 	static struct arglist alist = { 0, 0, 0, 0, "ls" };
6307c478bd9Sstevel@tonic-gate 	struct afile single;
6317c478bd9Sstevel@tonic-gate 	struct entry *np;
6327c478bd9Sstevel@tonic-gate 	RST_DIR *dirp;
6337c478bd9Sstevel@tonic-gate 	int list_entry;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	if ((dirp = rst_opendir(name)) == NULL) {
6367c478bd9Sstevel@tonic-gate 		single.fnum = ino;
6377c478bd9Sstevel@tonic-gate 		if (strncmp(name, basename, strlen(basename)) == 0)
6387c478bd9Sstevel@tonic-gate 			single.fname = savename(name + strlen(basename) + 1);
6397c478bd9Sstevel@tonic-gate 		else
6407c478bd9Sstevel@tonic-gate 			single.fname = savename(name);
6417c478bd9Sstevel@tonic-gate 		alist.head = &single;
6427c478bd9Sstevel@tonic-gate 		alist.last = alist.head + 1;
6437c478bd9Sstevel@tonic-gate 		if (alist.base != NULL) {
6447c478bd9Sstevel@tonic-gate 			free(alist.base);
6457c478bd9Sstevel@tonic-gate 			alist.base = NULL;
6467c478bd9Sstevel@tonic-gate 		}
6477c478bd9Sstevel@tonic-gate 	} else {
6487c478bd9Sstevel@tonic-gate 		alist.head = (struct afile *)0;
6497c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s:\n", name);
6507c478bd9Sstevel@tonic-gate 		while (dp = rst_readdir(dirp)) {
6517c478bd9Sstevel@tonic-gate 			if (dp == NULL || dp->d_ino == 0) {
6527c478bd9Sstevel@tonic-gate 				rst_closedir(dirp);
6537c478bd9Sstevel@tonic-gate 				dirp = NULL;
6547c478bd9Sstevel@tonic-gate 				break;
6557c478bd9Sstevel@tonic-gate 			}
6567c478bd9Sstevel@tonic-gate 			if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
6577c478bd9Sstevel@tonic-gate 				continue;
6587c478bd9Sstevel@tonic-gate 			if (vflag == 0 &&
6597c478bd9Sstevel@tonic-gate 			    (strcmp(dp->d_name, ".") == 0 ||
6607c478bd9Sstevel@tonic-gate 			    strcmp(dp->d_name, "..") == 0))
6617c478bd9Sstevel@tonic-gate 				continue;
6627c478bd9Sstevel@tonic-gate 			list_entry = 1;
6637c478bd9Sstevel@tonic-gate 			if (marked_only) {
6647c478bd9Sstevel@tonic-gate 				np = lookupino(dp->d_ino);
6657c478bd9Sstevel@tonic-gate 				if ((np == NIL) || ((np->e_flags & NEW) == 0))
6667c478bd9Sstevel@tonic-gate 					list_entry = 0;
6677c478bd9Sstevel@tonic-gate 			}
6687c478bd9Sstevel@tonic-gate 			if (list_entry) {
6697c478bd9Sstevel@tonic-gate 				if (!mkentry(dp->d_name, dp->d_ino, &alist)) {
6707c478bd9Sstevel@tonic-gate 					rst_closedir(dirp);
6717c478bd9Sstevel@tonic-gate 					return;
6727c478bd9Sstevel@tonic-gate 				}
6737c478bd9Sstevel@tonic-gate 			}
6747c478bd9Sstevel@tonic-gate 		}
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 	if (alist.head != 0) {
6777c478bd9Sstevel@tonic-gate 		if ((alist.last - alist.head) > ULONG_MAX) {
6787c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
6797c478bd9Sstevel@tonic-gate 			    gettext("Directory too large to sort\n"));
6807c478bd9Sstevel@tonic-gate 		} else {
6817c478bd9Sstevel@tonic-gate 			qsort((char *)alist.head,
6827c478bd9Sstevel@tonic-gate 			    /* LINTED range-checked */
6837c478bd9Sstevel@tonic-gate 			    (size_t)(alist.last - alist.head),
6847c478bd9Sstevel@tonic-gate 			    sizeof (*alist.head),
6857c478bd9Sstevel@tonic-gate 			    (int (*)(const void *, const void *)) fcmp);
6867c478bd9Sstevel@tonic-gate 		}
6877c478bd9Sstevel@tonic-gate 		formatf(&alist);
6887c478bd9Sstevel@tonic-gate 		for (fp = alist.head; fp < alist.last; fp++)
6897c478bd9Sstevel@tonic-gate 			freename(fp->fname);
6907c478bd9Sstevel@tonic-gate 		alist.head = NULL;
6917c478bd9Sstevel@tonic-gate 		/*
6927c478bd9Sstevel@tonic-gate 		 * Don't free alist.base, as we'll probably be called
6937c478bd9Sstevel@tonic-gate 		 * again, and might as well re-use what we've got.
6947c478bd9Sstevel@tonic-gate 		 */
6957c478bd9Sstevel@tonic-gate 	}
6967c478bd9Sstevel@tonic-gate 	if (dirp != NULL) {
6977c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
6987c478bd9Sstevel@tonic-gate 		rst_closedir(dirp);
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate /*
7037c478bd9Sstevel@tonic-gate  * Print out a pretty listing of a directory
7047c478bd9Sstevel@tonic-gate  */
7057c478bd9Sstevel@tonic-gate static void
formatf(struct arglist * ap)706*d9529689SToomas Soome formatf(struct arglist *ap)
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate 	struct afile *fp;
7097c478bd9Sstevel@tonic-gate 	struct entry *np;
7107c478bd9Sstevel@tonic-gate 	/* LINTED: result fits into an int */
7117c478bd9Sstevel@tonic-gate 	int nentry = (int)(ap->last - ap->head);
7127c478bd9Sstevel@tonic-gate 	int i, j;
7137c478bd9Sstevel@tonic-gate 	uint_t len, w, width = 0, columns, lines;
7147c478bd9Sstevel@tonic-gate 	char *cp;
7157c478bd9Sstevel@tonic-gate 	FILE *output = stderr;
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	if (ap->head == ap->last)
7187c478bd9Sstevel@tonic-gate 		return;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	if (paginating) {
7217c478bd9Sstevel@tonic-gate 		int fds[2];
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 		if (pipe(fds) < 0) {
7247c478bd9Sstevel@tonic-gate 			perror(gettext("could not create pipe"));
7257c478bd9Sstevel@tonic-gate 			goto no_page;
7267c478bd9Sstevel@tonic-gate 		}
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 		switch (fork()) {
7297c478bd9Sstevel@tonic-gate 		case -1:
7307c478bd9Sstevel@tonic-gate 			perror(gettext("could not fork"));
7317c478bd9Sstevel@tonic-gate 			goto no_page;
7327c478bd9Sstevel@tonic-gate 		case 0:
7337c478bd9Sstevel@tonic-gate 			/*
7347c478bd9Sstevel@tonic-gate 			 * Make sure final output still ends up in
7357c478bd9Sstevel@tonic-gate 			 * the same place.
7367c478bd9Sstevel@tonic-gate 			 */
7377c478bd9Sstevel@tonic-gate 			(void) dup2(fileno(stderr), fileno(stdout));
7387c478bd9Sstevel@tonic-gate 			(void) close(fds[0]);
7397c478bd9Sstevel@tonic-gate 			(void) dup2(fds[1], fileno(stdin));
7407c478bd9Sstevel@tonic-gate 			execvp(pager_vector[0], pager_vector);
7417c478bd9Sstevel@tonic-gate 			perror(gettext("execvp of pager failed"));
7427c478bd9Sstevel@tonic-gate 			exit(1);
7437c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
7447c478bd9Sstevel@tonic-gate 		default:
7457c478bd9Sstevel@tonic-gate 			(void) close(fds[1]);
7467c478bd9Sstevel@tonic-gate 			output = fdopen(fds[0], "w");
7477c478bd9Sstevel@tonic-gate 			if (output != (FILE *)NULL) {
7487c478bd9Sstevel@tonic-gate 				break;
7497c478bd9Sstevel@tonic-gate 			}
7507c478bd9Sstevel@tonic-gate 			perror(gettext("could not open pipe to pager"));
7517c478bd9Sstevel@tonic-gate 			output = stderr;
7527c478bd9Sstevel@tonic-gate 		no_page:
7537c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
7547c478bd9Sstevel@tonic-gate 			    gettext("pagination disabled\n"));
7557c478bd9Sstevel@tonic-gate 			paginating = 0;
7567c478bd9Sstevel@tonic-gate 		}
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	for (fp = ap->head; fp < ap->last; fp++) {
7607c478bd9Sstevel@tonic-gate 		fp->ftype = inodetype(fp->fnum);
7617c478bd9Sstevel@tonic-gate 		np = lookupino(fp->fnum);
7627c478bd9Sstevel@tonic-gate 		if (np != NIL)
7637c478bd9Sstevel@tonic-gate 			fp->fflags = np->e_flags;
7647c478bd9Sstevel@tonic-gate 		else
7657c478bd9Sstevel@tonic-gate 			fp->fflags = 0;
7667c478bd9Sstevel@tonic-gate 		len = strlen(fmtentry(fp));
7677c478bd9Sstevel@tonic-gate 		if (len > width)
7687c478bd9Sstevel@tonic-gate 			width = len;
7697c478bd9Sstevel@tonic-gate 	}
7707c478bd9Sstevel@tonic-gate 	width += 2;
7717c478bd9Sstevel@tonic-gate 	columns = 80 / width;
7727c478bd9Sstevel@tonic-gate 	if (columns == 0)
7737c478bd9Sstevel@tonic-gate 		columns = 1;
7747c478bd9Sstevel@tonic-gate 	lines = (nentry + columns - 1) / columns;
7757c478bd9Sstevel@tonic-gate 	for (i = 0; i < lines && !ferror(output); i++) {
7767c478bd9Sstevel@tonic-gate 		for (j = 0; j < columns && !ferror(output); j++) {
7777c478bd9Sstevel@tonic-gate 			fp = ap->head + j * lines + i;
7787c478bd9Sstevel@tonic-gate 			cp = fmtentry(fp);
7797c478bd9Sstevel@tonic-gate 			(void) fprintf(output, "%s", cp);
7807c478bd9Sstevel@tonic-gate 			if (fp + lines >= ap->last) {
7817c478bd9Sstevel@tonic-gate 				(void) fprintf(output, "\n");
7827c478bd9Sstevel@tonic-gate 				break;
7837c478bd9Sstevel@tonic-gate 			}
7847c478bd9Sstevel@tonic-gate 			w = strlen(cp);
7857c478bd9Sstevel@tonic-gate 			while (w < width) {
7867c478bd9Sstevel@tonic-gate 				w++;
7877c478bd9Sstevel@tonic-gate 				if (fprintf(output, " ") < 0)
7887c478bd9Sstevel@tonic-gate 					break;
7897c478bd9Sstevel@tonic-gate 			}
7907c478bd9Sstevel@tonic-gate 		}
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	if (paginating) {
7947c478bd9Sstevel@tonic-gate 		(void) fclose(output);
7957c478bd9Sstevel@tonic-gate 		(void) wait((int *)NULL);
7967c478bd9Sstevel@tonic-gate 	}
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate /*
8007c478bd9Sstevel@tonic-gate  * Comparison routine for qsort.
8017c478bd9Sstevel@tonic-gate  */
8027c478bd9Sstevel@tonic-gate static int
fcmp(struct afile * f1,struct afile * f2)803*d9529689SToomas Soome fcmp(struct afile *f1, struct afile *f2)
8047c478bd9Sstevel@tonic-gate {
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	return (strcoll(f1->fname, f2->fname));
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate /*
8107c478bd9Sstevel@tonic-gate  * Format a directory entry.
8117c478bd9Sstevel@tonic-gate  */
8127c478bd9Sstevel@tonic-gate static char *
fmtentry(struct afile * fp)813*d9529689SToomas Soome fmtentry(struct afile *fp)
8147c478bd9Sstevel@tonic-gate {
8157c478bd9Sstevel@tonic-gate 	static char fmtres[MAXCOMPLEXLEN];
8167c478bd9Sstevel@tonic-gate 	static int precision = 0;
8177c478bd9Sstevel@tonic-gate 	ino_t i;
8187c478bd9Sstevel@tonic-gate 	char *cp, *dp, *limit;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	if (!vflag) {
8217c478bd9Sstevel@tonic-gate 		/* MAXCOMPLEXLEN assumed to be >= 1 */
8227c478bd9Sstevel@tonic-gate 		fmtres[0] = '\0';
8237c478bd9Sstevel@tonic-gate 	} else {
8247c478bd9Sstevel@tonic-gate 		if (precision == 0) {
8257c478bd9Sstevel@tonic-gate 			for (i = maxino; i != 0; i /= 10)
8267c478bd9Sstevel@tonic-gate 				precision++;
8277c478bd9Sstevel@tonic-gate 			if (sizeof (fmtres) < (unsigned)(precision + 2)) {
8287c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
8297c478bd9Sstevel@tonic-gate "\nInternal check failed, minimum width %d exceeds available size %d\n"),
8307c478bd9Sstevel@tonic-gate 				    (precision + 2), sizeof (fmtres));
8317c478bd9Sstevel@tonic-gate 				done(1);
8327c478bd9Sstevel@tonic-gate 			}
8337c478bd9Sstevel@tonic-gate 		}
8347c478bd9Sstevel@tonic-gate 		(void) snprintf(fmtres, sizeof (fmtres), "%*ld ",
8357c478bd9Sstevel@tonic-gate 		    precision, fp->fnum);
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 	dp = &fmtres[strlen(fmtres)];
8387c478bd9Sstevel@tonic-gate 	limit = fmtres + sizeof (fmtres) - 1;
8397c478bd9Sstevel@tonic-gate 	if (dflag && BIT(fp->fnum, dumpmap) == 0)
8407c478bd9Sstevel@tonic-gate 		*dp++ = '^';
8417c478bd9Sstevel@tonic-gate 	else if ((fp->fflags & NEW) != 0)
8427c478bd9Sstevel@tonic-gate 		*dp++ = '*';
8437c478bd9Sstevel@tonic-gate 	else
8447c478bd9Sstevel@tonic-gate 		*dp++ = ' ';
8457c478bd9Sstevel@tonic-gate 	for (cp = fp->fname; *cp && dp < limit; cp++)
8467c478bd9Sstevel@tonic-gate 		/* LINTED: precedence ok, can't fix system macro */
8477c478bd9Sstevel@tonic-gate 		if (!vflag && (!ISPRINT(*cp, wp)))
8487c478bd9Sstevel@tonic-gate 			*dp++ = '?';
8497c478bd9Sstevel@tonic-gate 		else
8507c478bd9Sstevel@tonic-gate 			*dp++ = *cp;
8517c478bd9Sstevel@tonic-gate 	if (fp->ftype == NODE && dp < limit)
8527c478bd9Sstevel@tonic-gate 		*dp++ = '/';
8537c478bd9Sstevel@tonic-gate 	*dp++ = 0;
8547c478bd9Sstevel@tonic-gate 	return (fmtres);
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate /*
8587c478bd9Sstevel@tonic-gate  * respond to interrupts
8597c478bd9Sstevel@tonic-gate  */
8607c478bd9Sstevel@tonic-gate /* ARGSUSED */
8617c478bd9Sstevel@tonic-gate void
onintr(int sig)862*d9529689SToomas Soome onintr(int sig)
8637c478bd9Sstevel@tonic-gate {
8647c478bd9Sstevel@tonic-gate 	char	buf[300];
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	if (command == 'i' && reset_OK)
8677c478bd9Sstevel@tonic-gate 		longjmp(reset, 1);
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf),
8707c478bd9Sstevel@tonic-gate 	    gettext("%s interrupted, continue"), progname);
8717c478bd9Sstevel@tonic-gate 	if (reply(buf) == FAIL)
8727c478bd9Sstevel@tonic-gate 		done(1);
8737c478bd9Sstevel@tonic-gate }
8747c478bd9Sstevel@tonic-gate /*
8757c478bd9Sstevel@tonic-gate  * Set up pager_catenated and pager_vector.
8767c478bd9Sstevel@tonic-gate  */
8777c478bd9Sstevel@tonic-gate void
initpagercmd(void)8787c478bd9Sstevel@tonic-gate initpagercmd(void)
8797c478bd9Sstevel@tonic-gate {
8807c478bd9Sstevel@tonic-gate 	char *cp;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	cp = getenv("PAGER");
8837c478bd9Sstevel@tonic-gate 	if (cp != NULL)
8847c478bd9Sstevel@tonic-gate 		pager_catenated = strdup(cp);
8857c478bd9Sstevel@tonic-gate 	if ((pager_catenated == NULL) || (*pager_catenated == '\0')) {
8867c478bd9Sstevel@tonic-gate 		if (pager_catenated != NULL)
8877c478bd9Sstevel@tonic-gate 			free(pager_catenated);
8887c478bd9Sstevel@tonic-gate 		pager_catenated = strdup(DEF_PAGER);
8897c478bd9Sstevel@tonic-gate 	}
8907c478bd9Sstevel@tonic-gate 	if (pager_catenated == NULL) {
8917c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("out of memory\n"));
8927c478bd9Sstevel@tonic-gate 		done(1);
8937c478bd9Sstevel@tonic-gate 	}
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	pager_vector = (char **)malloc(sizeof (char *));
8967c478bd9Sstevel@tonic-gate 	if (pager_vector == NULL) {
8977c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("out of memory\n"));
8987c478bd9Sstevel@tonic-gate 		done(1);
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	pager_len = 1;
9027c478bd9Sstevel@tonic-gate 	cp = pager_catenated;
9037c478bd9Sstevel@tonic-gate 	(void) setpagerargs(&cp);
9047c478bd9Sstevel@tonic-gate }
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate /*
9087c478bd9Sstevel@tonic-gate  * Resets pager_catenated and pager_vector from user input.
9097c478bd9Sstevel@tonic-gate  */
9107c478bd9Sstevel@tonic-gate void
setpagercmd(void)9117c478bd9Sstevel@tonic-gate setpagercmd(void)
9127c478bd9Sstevel@tonic-gate {
9137c478bd9Sstevel@tonic-gate 	uint_t catenate_length;
9147c478bd9Sstevel@tonic-gate 	int index;
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	/*
9177c478bd9Sstevel@tonic-gate 	 * We'll get called immediately after setting a pager, due to
9187c478bd9Sstevel@tonic-gate 	 * our interaction with getcmd()'s internal state.  Don't do
9197c478bd9Sstevel@tonic-gate 	 * anything when that happens.
9207c478bd9Sstevel@tonic-gate 	 */
9217c478bd9Sstevel@tonic-gate 	if (*input == '\0')
9227c478bd9Sstevel@tonic-gate 		return;
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	if (pager_len > 0) {
9257c478bd9Sstevel@tonic-gate 		for (index = 0; pager_vector[index] != (char *)NULL; index += 1)
9267c478bd9Sstevel@tonic-gate 			free(pager_vector[index]);
9277c478bd9Sstevel@tonic-gate 		free(pager_vector);
9287c478bd9Sstevel@tonic-gate 		free(pager_catenated);
9297c478bd9Sstevel@tonic-gate 	}
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	pager_vector = (char **)malloc(2 * sizeof (char *));
9327c478bd9Sstevel@tonic-gate 	if (pager_vector == NULL) {
9337c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("out of memory\n"));
9347c478bd9Sstevel@tonic-gate 		done(1);
9357c478bd9Sstevel@tonic-gate 	}
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	pager_len = 2;
9387c478bd9Sstevel@tonic-gate 	pager_vector[0] = strdup(input);
9397c478bd9Sstevel@tonic-gate 	if (pager_vector[0] == NULL) {
9407c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("out of memory\n"));
9417c478bd9Sstevel@tonic-gate 		done(1);
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate 	if (dflag)
9447c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("got command `%s'\n"), input);
9457c478bd9Sstevel@tonic-gate 	catenate_length = setpagerargs(&nextarg) + strlen(pager_vector[0]) + 1;
9467c478bd9Sstevel@tonic-gate 	pager_catenated = (char *)malloc(catenate_length *
947*d9529689SToomas Soome 	    (size_t)sizeof (char));
9487c478bd9Sstevel@tonic-gate 	if (pager_catenated == (char *)NULL) {
9497c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("out of memory\n"));
9507c478bd9Sstevel@tonic-gate 		done(1);
9517c478bd9Sstevel@tonic-gate 	}
9527c478bd9Sstevel@tonic-gate 	for (index = 0; pager_vector[index] != (char *)NULL; index += 1) {
9537c478bd9Sstevel@tonic-gate 		if (index > 0)
9547c478bd9Sstevel@tonic-gate 			(void) strcat(pager_catenated, " ");
9557c478bd9Sstevel@tonic-gate 		(void) strcat(pager_catenated, pager_vector[index]);
9567c478bd9Sstevel@tonic-gate 	}
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate /*
9617c478bd9Sstevel@tonic-gate  * Extract arguments for the pager command from getcmd()'s input buffer.
9627c478bd9Sstevel@tonic-gate  */
9637c478bd9Sstevel@tonic-gate static uint_t
setpagerargs(char ** source)964*d9529689SToomas Soome setpagerargs(char **source)
9657c478bd9Sstevel@tonic-gate {
9667c478bd9Sstevel@tonic-gate 	char	word[MAXCOMPLEXLEN];
9677c478bd9Sstevel@tonic-gate 	char	*cp = *source;
9687c478bd9Sstevel@tonic-gate 	uint_t	length = 0;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	while ((cp != (char *)NULL) && (*cp != '\0')) {
9717c478bd9Sstevel@tonic-gate 		cp = copynext(cp, word, sizeof (word));
9727c478bd9Sstevel@tonic-gate 		if (dflag)
9737c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext("got word `%s'\n"), word);
9747c478bd9Sstevel@tonic-gate 		pager_vector = (char **)realloc(pager_vector,
975*d9529689SToomas Soome 		    (size_t)sizeof (char *) * (pager_len + 1));
9767c478bd9Sstevel@tonic-gate 		if (pager_vector == (char **)NULL) {
9777c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("out of memory\n"));
9787c478bd9Sstevel@tonic-gate 			done(1);
9797c478bd9Sstevel@tonic-gate 		}
9807c478bd9Sstevel@tonic-gate 		pager_vector[pager_len - 1] = strdup(word);
9817c478bd9Sstevel@tonic-gate 		if (pager_vector[pager_len - 1] == (char *)NULL) {
9827c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("out of memory\n"));
9837c478bd9Sstevel@tonic-gate 			done(1);
9847c478bd9Sstevel@tonic-gate 		}
9857c478bd9Sstevel@tonic-gate 		length += strlen(word) + 1;
9867c478bd9Sstevel@tonic-gate 		pager_len += 1;
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate 	pager_vector[pager_len - 1] = (char *)NULL;
9897c478bd9Sstevel@tonic-gate 	*source = cp;
9907c478bd9Sstevel@tonic-gate 	return (length);
9917c478bd9Sstevel@tonic-gate }
992