17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
237c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
287c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2967a4bb8fSGary Mills  * Copyright 2015 Gary Mills
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  *	cscope - interactive C symbol cross-reference
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  *	display functions
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include "global.h"
397c478bd9Sstevel@tonic-gate #include "version.h"	/* FILEVERSION and FIXVERSION */
407c478bd9Sstevel@tonic-gate #include <curses.h>	/* COLS and LINES */
417c478bd9Sstevel@tonic-gate #include <setjmp.h>	/* jmp_buf */
427c478bd9Sstevel@tonic-gate #include <string.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /* see if the function column should be displayed */
467c478bd9Sstevel@tonic-gate #define	displayfcn()	(field <= ASSIGN)
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #define	MINCOLS	68	/* minimum columns for 3 digit Lines message numbers */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate int	*displine;		/* screen line of displayed reference */
517c478bd9Sstevel@tonic-gate int	disprefs;		/* displayed references */
527c478bd9Sstevel@tonic-gate int	field;			/* input field */
537c478bd9Sstevel@tonic-gate unsigned fldcolumn;		/* input field column */
547c478bd9Sstevel@tonic-gate int	mdisprefs;		/* maximum displayed references */
557c478bd9Sstevel@tonic-gate int	selectlen;		/* selection number field length */
567c478bd9Sstevel@tonic-gate int	nextline;		/* next line to be shown */
577c478bd9Sstevel@tonic-gate int	topline = 1;		/* top line of page */
587c478bd9Sstevel@tonic-gate int	bottomline;		/* bottom line of page */
597c478bd9Sstevel@tonic-gate int	totallines;		/* total reference lines */
607c478bd9Sstevel@tonic-gate FILE	*refsfound;		/* references found file */
617c478bd9Sstevel@tonic-gate FILE	*nonglobalrefs;		/* non-global references file */
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate static	int	fldline;		/* input field line */
647c478bd9Sstevel@tonic-gate static	int	subsystemlen;		/* OGS subsystem name display */
657c478bd9Sstevel@tonic-gate 					/* field length */
667c478bd9Sstevel@tonic-gate static	int	booklen;		/* OGS book name display field length */
677c478bd9Sstevel@tonic-gate static	int	filelen;		/* file name display field length */
687c478bd9Sstevel@tonic-gate static	int	fcnlen;			/* function name display field length */
697c478bd9Sstevel@tonic-gate static	jmp_buf	env;			/* setjmp/longjmp buffer */
707c478bd9Sstevel@tonic-gate static	int	lastdispline;		/* last displayed reference line */
717c478bd9Sstevel@tonic-gate static	char	lastmsg[MSGLEN + 1];	/* last message displayed */
727c478bd9Sstevel@tonic-gate static	int	numlen;			/* line number display field length */
737c478bd9Sstevel@tonic-gate static	char	depthstring[] = "Depth: ";
747c478bd9Sstevel@tonic-gate static	char	helpstring[] = "Press the ? key for help";
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate typedef char *(*FP)();	/* pointer to function returning a character pointer */
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static	struct	{
807c478bd9Sstevel@tonic-gate 	char	*text1;
817c478bd9Sstevel@tonic-gate 	char	*text2;
827c478bd9Sstevel@tonic-gate 	FP	findfcn;
837c478bd9Sstevel@tonic-gate 	enum {
847c478bd9Sstevel@tonic-gate 		EGREP,
857c478bd9Sstevel@tonic-gate 		REGCMP
867c478bd9Sstevel@tonic-gate 	} patterntype;
877c478bd9Sstevel@tonic-gate } fields[FIELDS + 1] = {
887c478bd9Sstevel@tonic-gate 	/* last search is not part of the cscope display */
897c478bd9Sstevel@tonic-gate 	{ "Find this", "C symbol",
907c478bd9Sstevel@tonic-gate 	    (FP) findsymbol, REGCMP},
917c478bd9Sstevel@tonic-gate 	{ "Find this", "definition",
927c478bd9Sstevel@tonic-gate 	    (FP) finddef, REGCMP},
937c478bd9Sstevel@tonic-gate 	{ "Find", "functions called by this function",
947c478bd9Sstevel@tonic-gate 	    (FP) findcalledby, REGCMP},
957c478bd9Sstevel@tonic-gate 	{ "Find", "functions calling this function",
967c478bd9Sstevel@tonic-gate 	    (FP) findcalling, REGCMP},
977c478bd9Sstevel@tonic-gate 	{ "Find", "assignments to",
987c478bd9Sstevel@tonic-gate 	    (FP) findassignments, REGCMP},
997c478bd9Sstevel@tonic-gate 	{ "Change this", "grep pattern",
1007c478bd9Sstevel@tonic-gate 	    findgreppat, EGREP},
1017c478bd9Sstevel@tonic-gate 	{ "Find this", "egrep pattern",
1027c478bd9Sstevel@tonic-gate 	    findegreppat, EGREP},
1037c478bd9Sstevel@tonic-gate 	{ "Find this", "file",
1047c478bd9Sstevel@tonic-gate 	    (FP) findfile, REGCMP},
1057c478bd9Sstevel@tonic-gate 	{ "Find", "files #including this file",
1067c478bd9Sstevel@tonic-gate 	    (FP) findinclude, REGCMP},
1077c478bd9Sstevel@tonic-gate 	{ "Find all", "function/class definitions",
1087c478bd9Sstevel@tonic-gate 	    (FP) findallfcns, REGCMP},
1097c478bd9Sstevel@tonic-gate };
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /* initialize display parameters */
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate void
dispinit(void)1147c478bd9Sstevel@tonic-gate dispinit(void)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate 	/* calculate the maximum displayed reference lines */
1177c478bd9Sstevel@tonic-gate 	lastdispline = FLDLINE - 2;
1187c478bd9Sstevel@tonic-gate 	mdisprefs = lastdispline - REFLINE + 1;
1197c478bd9Sstevel@tonic-gate 	if (mdisprefs <= 0) {
1207c478bd9Sstevel@tonic-gate 		(void) printw("cscope: window must be at least %d lines high",
1217c478bd9Sstevel@tonic-gate 		    FIELDS + 6);
1227c478bd9Sstevel@tonic-gate 		myexit(1);
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 	if (COLS < MINCOLS) {
1257c478bd9Sstevel@tonic-gate 		(void) printw("cscope: window must be at least %d columns wide",
1267c478bd9Sstevel@tonic-gate 		    MINCOLS);
1277c478bd9Sstevel@tonic-gate 		myexit(1);
1287c478bd9Sstevel@tonic-gate 	}
1297c478bd9Sstevel@tonic-gate 	if (!mouse) {
1307c478bd9Sstevel@tonic-gate 		if (returnrequired == NO && mdisprefs > 9) {
1317c478bd9Sstevel@tonic-gate 			mdisprefs = 9;	/* single digit selection number */
1327c478bd9Sstevel@tonic-gate 		}
1337c478bd9Sstevel@tonic-gate 		/* calculate the maximum selection number width */
1347c478bd9Sstevel@tonic-gate 		(void) sprintf(newpat, "%d", mdisprefs);
1357c478bd9Sstevel@tonic-gate 		selectlen = strlen(newpat);
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 	/* allocate the displayed line array */
1387c478bd9Sstevel@tonic-gate 	displine = (int *)mymalloc(mdisprefs * sizeof (int));
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /* display a page of the references */
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate void
display(void)1447c478bd9Sstevel@tonic-gate display(void)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate 	char	*subsystem;		/* OGS subsystem name */
1477c478bd9Sstevel@tonic-gate 	char	*book;			/* OGS book name */
1487c478bd9Sstevel@tonic-gate 	char	file[PATHLEN + 1];	/* file name */
1497c478bd9Sstevel@tonic-gate 	char	function[PATLEN + 1];	/* function name */
1507c478bd9Sstevel@tonic-gate 	char	linenum[NUMLEN + 1];	/* line number */
1517c478bd9Sstevel@tonic-gate 	int	screenline;		/* screen line number */
1527c478bd9Sstevel@tonic-gate 	int	width;			/* source line display width */
1537c478bd9Sstevel@tonic-gate 	int	i;
1547c478bd9Sstevel@tonic-gate 	char	*s;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	(void) erase();
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	/* if there are no references */
1597c478bd9Sstevel@tonic-gate 	if (totallines == 0) {
1607c478bd9Sstevel@tonic-gate 		if (*lastmsg != '\0') {
1617c478bd9Sstevel@tonic-gate 			(void) addstr(lastmsg);	/* redisplay any message */
1627c478bd9Sstevel@tonic-gate 		} else {
1637c478bd9Sstevel@tonic-gate 			(void) printw("Cscope version %d%s", FILEVERSION,
1647c478bd9Sstevel@tonic-gate 			    FIXVERSION);
1657c478bd9Sstevel@tonic-gate 			(void) move(0, COLS - (int)sizeof (helpstring));
1667c478bd9Sstevel@tonic-gate 			(void) addstr(helpstring);
1677c478bd9Sstevel@tonic-gate 		}
1687c478bd9Sstevel@tonic-gate 	} else {	/* display the pattern */
1697c478bd9Sstevel@tonic-gate 		if (changing == YES) {
1707c478bd9Sstevel@tonic-gate 			(void) printw("Change \"%s\" to \"%s\"",
1717c478bd9Sstevel@tonic-gate 			    pattern, newpat);
1727c478bd9Sstevel@tonic-gate 		} else {
1737c478bd9Sstevel@tonic-gate 			(void) printw("%c%s: %s",
1747c478bd9Sstevel@tonic-gate 			    toupper(fields[field].text2[0]),
1757c478bd9Sstevel@tonic-gate 			    fields[field].text2 + 1, pattern);
1767c478bd9Sstevel@tonic-gate 		}
1777c478bd9Sstevel@tonic-gate 		/* display the cscope invocation nesting depth */
1787c478bd9Sstevel@tonic-gate 		if (cscopedepth > 1) {
1797c478bd9Sstevel@tonic-gate 			(void) move(0, COLS - (int)sizeof (depthstring) - 2);
1807c478bd9Sstevel@tonic-gate 			(void) addstr(depthstring);
1817c478bd9Sstevel@tonic-gate 			(void) printw("%d", cscopedepth);
1827c478bd9Sstevel@tonic-gate 		}
1837c478bd9Sstevel@tonic-gate 		/* display the column headings */
1847c478bd9Sstevel@tonic-gate 		(void) move(2, selectlen + 1);
1857c478bd9Sstevel@tonic-gate 		if (ogs == YES && field != FILENAME) {
1867c478bd9Sstevel@tonic-gate 			(void) printw("%-*s ", subsystemlen, "Subsystem");
1877c478bd9Sstevel@tonic-gate 			(void) printw("%-*s ", booklen, "Book");
1887c478bd9Sstevel@tonic-gate 		}
1897c478bd9Sstevel@tonic-gate 		if (dispcomponents > 0) {
1907c478bd9Sstevel@tonic-gate 			(void) printw("%-*s ", filelen, "File");
1917c478bd9Sstevel@tonic-gate 		}
1927c478bd9Sstevel@tonic-gate 		if (displayfcn()) {
1937c478bd9Sstevel@tonic-gate 			(void) printw("%-*s ", fcnlen, "Function");
1947c478bd9Sstevel@tonic-gate 		}
1957c478bd9Sstevel@tonic-gate 		if (field != FILENAME) {
1967c478bd9Sstevel@tonic-gate 			(void) addstr("Line");
1977c478bd9Sstevel@tonic-gate 		}
1987c478bd9Sstevel@tonic-gate 		(void) addch('\n');
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 		/* if at end of file go back to beginning */
2017c478bd9Sstevel@tonic-gate 		if (nextline > totallines) {
2027c478bd9Sstevel@tonic-gate 			seekline(1);
2037c478bd9Sstevel@tonic-gate 		}
2047c478bd9Sstevel@tonic-gate 		/* calculate the source text column */
2057c478bd9Sstevel@tonic-gate 		width = COLS - selectlen - numlen - 2;
2067c478bd9Sstevel@tonic-gate 		if (ogs == YES) {
2077c478bd9Sstevel@tonic-gate 			width -= subsystemlen + booklen + 2;
2087c478bd9Sstevel@tonic-gate 		}
2097c478bd9Sstevel@tonic-gate 		if (dispcomponents > 0) {
2107c478bd9Sstevel@tonic-gate 			width -= filelen + 1;
2117c478bd9Sstevel@tonic-gate 		}
2127c478bd9Sstevel@tonic-gate 		if (displayfcn()) {
2137c478bd9Sstevel@tonic-gate 			width -= fcnlen + 1;
2147c478bd9Sstevel@tonic-gate 		}
2157c478bd9Sstevel@tonic-gate 		/*
2167c478bd9Sstevel@tonic-gate 		 * until the max references have been displayed or
2177c478bd9Sstevel@tonic-gate 		 * there is no more room
2187c478bd9Sstevel@tonic-gate 		 */
2197c478bd9Sstevel@tonic-gate 		topline = nextline;
2207c478bd9Sstevel@tonic-gate 		for (disprefs = 0, screenline = REFLINE;
2217c478bd9Sstevel@tonic-gate 		    disprefs < mdisprefs && screenline <= lastdispline;
2227c478bd9Sstevel@tonic-gate 		    ++disprefs, ++screenline) {
2237c478bd9Sstevel@tonic-gate 			/* read the reference line */
2247c478bd9Sstevel@tonic-gate 			if (fscanf(refsfound, "%s%s%s %[^\n]", file, function,
2257c478bd9Sstevel@tonic-gate 			    linenum, yytext) < 4) {
2267c478bd9Sstevel@tonic-gate 				break;
2277c478bd9Sstevel@tonic-gate 			}
2287c478bd9Sstevel@tonic-gate 			++nextline;
2297c478bd9Sstevel@tonic-gate 			displine[disprefs] = screenline;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 			/* if no mouse, display the selection number */
2327c478bd9Sstevel@tonic-gate 			if (!mouse) {
2337c478bd9Sstevel@tonic-gate 				(void) printw("%*d", selectlen, disprefs + 1);
2347c478bd9Sstevel@tonic-gate 			}
2357c478bd9Sstevel@tonic-gate 			/* display any change mark */
2367c478bd9Sstevel@tonic-gate 			if (changing == YES &&
2377c478bd9Sstevel@tonic-gate 			    change[topline + disprefs - 1] == YES) {
2387c478bd9Sstevel@tonic-gate 				(void) addch('>');
2397c478bd9Sstevel@tonic-gate 			} else {
2407c478bd9Sstevel@tonic-gate 				(void) addch(' ');
2417c478bd9Sstevel@tonic-gate 			}
2427c478bd9Sstevel@tonic-gate 			/* display the file name */
2437c478bd9Sstevel@tonic-gate 			if (field == FILENAME) {
2447c478bd9Sstevel@tonic-gate 				(void) printw("%-.*s\n", COLS - 3, file);
2457c478bd9Sstevel@tonic-gate 				continue;
2467c478bd9Sstevel@tonic-gate 			}
2477c478bd9Sstevel@tonic-gate 			/* if OGS, display the subsystem and book names */
2487c478bd9Sstevel@tonic-gate 			if (ogs == YES) {
2497c478bd9Sstevel@tonic-gate 				ogsnames(file, &subsystem, &book);
2507c478bd9Sstevel@tonic-gate 				(void) printw("%-*.*s ", subsystemlen,
2517c478bd9Sstevel@tonic-gate 				    subsystemlen, subsystem);
2527c478bd9Sstevel@tonic-gate 				(void) printw("%-*.*s ", booklen, booklen,
2537c478bd9Sstevel@tonic-gate 				    book);
2547c478bd9Sstevel@tonic-gate 			}
2557c478bd9Sstevel@tonic-gate 			/* display the requested path components */
2567c478bd9Sstevel@tonic-gate 			if (dispcomponents > 0) {
2577c478bd9Sstevel@tonic-gate 				(void) printw("%-*.*s ", filelen, filelen,
2587c478bd9Sstevel@tonic-gate 				    pathcomponents(file, dispcomponents));
2597c478bd9Sstevel@tonic-gate 			}
2607c478bd9Sstevel@tonic-gate 			/* display the function name */
2617c478bd9Sstevel@tonic-gate 			if (displayfcn()) {
2627c478bd9Sstevel@tonic-gate 				(void) printw("%-*.*s ", fcnlen, fcnlen,
2637c478bd9Sstevel@tonic-gate 				    function);
2647c478bd9Sstevel@tonic-gate 			}
2657c478bd9Sstevel@tonic-gate 			/* display the line number */
2667c478bd9Sstevel@tonic-gate 			(void) printw("%*s ", numlen, linenum);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 			/* there may be tabs in egrep output */
2697c478bd9Sstevel@tonic-gate 			while ((s = strchr(yytext, '\t')) != NULL) {
2707c478bd9Sstevel@tonic-gate 				*s = ' ';
2717c478bd9Sstevel@tonic-gate 			}
2727c478bd9Sstevel@tonic-gate 			/* display the source line */
2737c478bd9Sstevel@tonic-gate 			s = yytext;
2747c478bd9Sstevel@tonic-gate 			for (;;) {
2757c478bd9Sstevel@tonic-gate 				/* see if the source line will fit */
2767c478bd9Sstevel@tonic-gate 				if ((i = strlen(s)) > width) {
2777c478bd9Sstevel@tonic-gate 					/* find the nearest blank */
2787c478bd9Sstevel@tonic-gate 					for (i = width; s[i] != ' ' && i > 0;
2797c478bd9Sstevel@tonic-gate 					    --i) {
2807c478bd9Sstevel@tonic-gate 					}
2817c478bd9Sstevel@tonic-gate 					if (i == 0) {
2827c478bd9Sstevel@tonic-gate 						i = width;	/* no blank */
2837c478bd9Sstevel@tonic-gate 					}
2847c478bd9Sstevel@tonic-gate 				}
2857c478bd9Sstevel@tonic-gate 				/* print up to this point */
2867c478bd9Sstevel@tonic-gate 				(void) printw("%.*s", i, s);
2877c478bd9Sstevel@tonic-gate 				s += i;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 				/* if line didn't wrap around */
2907c478bd9Sstevel@tonic-gate 				if (i < width) {
2917c478bd9Sstevel@tonic-gate 					/* go to next line */
2927c478bd9Sstevel@tonic-gate 					(void) addch('\n');
2937c478bd9Sstevel@tonic-gate 				}
2947c478bd9Sstevel@tonic-gate 				/* skip blanks */
2957c478bd9Sstevel@tonic-gate 				while (*s == ' ') {
2967c478bd9Sstevel@tonic-gate 					++s;
2977c478bd9Sstevel@tonic-gate 				}
2987c478bd9Sstevel@tonic-gate 				/* see if there is more text */
2997c478bd9Sstevel@tonic-gate 				if (*s == '\0') {
3007c478bd9Sstevel@tonic-gate 					break;
3017c478bd9Sstevel@tonic-gate 				}
3027c478bd9Sstevel@tonic-gate 				/* if the source line is too long */
3037c478bd9Sstevel@tonic-gate 				if (++screenline > lastdispline) {
3047c478bd9Sstevel@tonic-gate 					/*
3057c478bd9Sstevel@tonic-gate 					 * if this is the first displayed line,
3067c478bd9Sstevel@tonic-gate 					 * display what will fit on the screen
3077c478bd9Sstevel@tonic-gate 					 */
3087c478bd9Sstevel@tonic-gate 					if (topline == nextline - 1) {
3097c478bd9Sstevel@tonic-gate 						goto endrefs;
3107c478bd9Sstevel@tonic-gate 					}
3117c478bd9Sstevel@tonic-gate 					/* erase the reference */
3127c478bd9Sstevel@tonic-gate 					while (--screenline >=
3137c478bd9Sstevel@tonic-gate 					    displine[disprefs]) {
3147c478bd9Sstevel@tonic-gate 						(void) move(screenline, 0);
3157c478bd9Sstevel@tonic-gate 						(void) clrtoeol();
3167c478bd9Sstevel@tonic-gate 					}
3177c478bd9Sstevel@tonic-gate 					++screenline;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 					/*
3207c478bd9Sstevel@tonic-gate 					 * go back to the beginning of this
3217c478bd9Sstevel@tonic-gate 					 * reference
3227c478bd9Sstevel@tonic-gate 					 */
3237c478bd9Sstevel@tonic-gate 					--nextline;
3247c478bd9Sstevel@tonic-gate 					seekline(nextline);
3257c478bd9Sstevel@tonic-gate 					goto endrefs;
3267c478bd9Sstevel@tonic-gate 				}
3277c478bd9Sstevel@tonic-gate 				/* indent the continued source line */
3287c478bd9Sstevel@tonic-gate 				(void) move(screenline, COLS - width);
3297c478bd9Sstevel@tonic-gate 			}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 		}
3327c478bd9Sstevel@tonic-gate 	endrefs:
3337c478bd9Sstevel@tonic-gate 		/* check for more references */
3347c478bd9Sstevel@tonic-gate 		bottomline = nextline;
3357c478bd9Sstevel@tonic-gate 		if (bottomline - topline < totallines) {
3367c478bd9Sstevel@tonic-gate 			(void) move(FLDLINE - 1, 0);
3377c478bd9Sstevel@tonic-gate 			(void) standout();
3387c478bd9Sstevel@tonic-gate 			(void) printw("%*s", selectlen + 1, "");
3397c478bd9Sstevel@tonic-gate 			if (bottomline - 1 == topline) {
3407c478bd9Sstevel@tonic-gate 				(void) printw("Line %d", topline);
3417c478bd9Sstevel@tonic-gate 			} else {
3427c478bd9Sstevel@tonic-gate 				(void) printw("Lines %d-%d", topline,
3437c478bd9Sstevel@tonic-gate 				    bottomline - 1);
3447c478bd9Sstevel@tonic-gate 			}
3457c478bd9Sstevel@tonic-gate 			(void) printw(" of %d, press the space bar to "
3467c478bd9Sstevel@tonic-gate 			    "display next lines", totallines);
3477c478bd9Sstevel@tonic-gate 			(void) standend();
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 	/* display the input fields */
3517c478bd9Sstevel@tonic-gate 	(void) move(FLDLINE, 0);
3527c478bd9Sstevel@tonic-gate 	for (i = 0; i < FIELDS; ++i) {
3537c478bd9Sstevel@tonic-gate 		(void) printw("%s %s:\n", fields[i].text1, fields[i].text2);
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 	drawscrollbar(topline, nextline, totallines);
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate /* set the cursor position for the field */
3597c478bd9Sstevel@tonic-gate void
setfield(void)3607c478bd9Sstevel@tonic-gate setfield(void)
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate 	fldline = FLDLINE + field;
3637c478bd9Sstevel@tonic-gate 	fldcolumn = strlen(fields[field].text1) +
3647c478bd9Sstevel@tonic-gate 	    strlen(fields[field].text2) + 3;
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate /* move to the current input field */
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate void
atfield(void)3707c478bd9Sstevel@tonic-gate atfield(void)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	(void) move(fldline, (int)fldcolumn);
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate /* search for the symbol or text pattern */
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3787c478bd9Sstevel@tonic-gate SIGTYPE
jumpback(int sig)3797c478bd9Sstevel@tonic-gate jumpback(int sig)
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate 	longjmp(env, 1);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate BOOL
search(void)3857c478bd9Sstevel@tonic-gate search(void)
3867c478bd9Sstevel@tonic-gate {
3874c6c4a88SToomas Soome 	char	*volatile egreperror = NULL;	/* egrep error message */
3884c6c4a88SToomas Soome 	FINDINIT volatile rc = NOERROR;		/* findinit return code */
38967a4bb8fSGary Mills 	SIGTYPE	(*volatile savesig)() = SIG_DFL; /* old value of signal */
3907c478bd9Sstevel@tonic-gate 	FP	f;			/* searching function */
3917c478bd9Sstevel@tonic-gate 	char	*s;
3927c478bd9Sstevel@tonic-gate 	int	c;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	/* note: the pattern may have been a cscope argument */
3957c478bd9Sstevel@tonic-gate 	if (caseless == YES) {
3967c478bd9Sstevel@tonic-gate 		for (s = pattern; *s != '\0'; ++s) {
3977c478bd9Sstevel@tonic-gate 			*s = tolower(*s);
3987c478bd9Sstevel@tonic-gate 		}
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 	/* open the references found file for writing */
4017c478bd9Sstevel@tonic-gate 	if (writerefsfound() == NO) {
4027c478bd9Sstevel@tonic-gate 		return (NO);
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 	/* find the pattern - stop on an interrupt */
4057c478bd9Sstevel@tonic-gate 	if (linemode == NO) {
4067c478bd9Sstevel@tonic-gate 		putmsg("Searching");
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 	initprogress();
4097c478bd9Sstevel@tonic-gate 	if (setjmp(env) == 0) {
4107c478bd9Sstevel@tonic-gate 		savesig = signal(SIGINT, jumpback);
4117c478bd9Sstevel@tonic-gate 		f = fields[field].findfcn;
4127c478bd9Sstevel@tonic-gate 		if (fields[field].patterntype == EGREP) {
4137c478bd9Sstevel@tonic-gate 			egreperror = (*f)(pattern);
4147c478bd9Sstevel@tonic-gate 		} else {
4157c478bd9Sstevel@tonic-gate 			if ((nonglobalrefs = fopen(temp2, "w")) == NULL) {
4167c478bd9Sstevel@tonic-gate 				cannotopen(temp2);
4177c478bd9Sstevel@tonic-gate 				return (NO);
4187c478bd9Sstevel@tonic-gate 			}
4197c478bd9Sstevel@tonic-gate 			if ((rc = findinit()) == NOERROR) {
4207c478bd9Sstevel@tonic-gate 				(void) dbseek(0L); /* goto the first block */
4217c478bd9Sstevel@tonic-gate 				(*f)();
4227c478bd9Sstevel@tonic-gate 				findcleanup();
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 				/* append the non-global references */
4257c478bd9Sstevel@tonic-gate 				(void) freopen(temp2, "r", nonglobalrefs);
4267c478bd9Sstevel@tonic-gate 				while ((c = getc(nonglobalrefs)) != EOF) {
4277c478bd9Sstevel@tonic-gate 					(void) putc(c, refsfound);
4287c478bd9Sstevel@tonic-gate 				}
4297c478bd9Sstevel@tonic-gate 			}
4307c478bd9Sstevel@tonic-gate 			(void) fclose(nonglobalrefs);
4317c478bd9Sstevel@tonic-gate 		}
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate 	(void) signal(SIGINT, savesig);
4347c478bd9Sstevel@tonic-gate 	/* reopen the references found file for reading */
4357c478bd9Sstevel@tonic-gate 	(void) freopen(temp1, "r", refsfound);
4367c478bd9Sstevel@tonic-gate 	nextline = 1;
4377c478bd9Sstevel@tonic-gate 	totallines = 0;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	/* see if it is empty */
4407c478bd9Sstevel@tonic-gate 	if ((c = getc(refsfound)) == EOF) {
4417c478bd9Sstevel@tonic-gate 		if (egreperror != NULL) {
4427c478bd9Sstevel@tonic-gate 			(void) sprintf(lastmsg, "Egrep %s in this pattern: %s",
4437c478bd9Sstevel@tonic-gate 			    egreperror, pattern);
4447c478bd9Sstevel@tonic-gate 		} else if (rc == NOTSYMBOL) {
4457c478bd9Sstevel@tonic-gate 			(void) sprintf(lastmsg, "This is not a C symbol: %s",
4467c478bd9Sstevel@tonic-gate 			    pattern);
4477c478bd9Sstevel@tonic-gate 		} else if (rc == REGCMPERROR) {
4487c478bd9Sstevel@tonic-gate 			(void) sprintf(lastmsg,
449*bbf21555SRichard Lowe 			    "Error in this regcmp(3C) regular expression: %s",
4507c478bd9Sstevel@tonic-gate 			    pattern);
4517c478bd9Sstevel@tonic-gate 		} else {
4527c478bd9Sstevel@tonic-gate 			(void) sprintf(lastmsg, "Could not find the %s: %s",
4537c478bd9Sstevel@tonic-gate 			    fields[field].text2, pattern);
4547c478bd9Sstevel@tonic-gate 		}
4557c478bd9Sstevel@tonic-gate 		return (NO);
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 	/* put back the character read */
4587c478bd9Sstevel@tonic-gate 	(void) ungetc(c, refsfound);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	countrefs();
4617c478bd9Sstevel@tonic-gate 	return (YES);
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate /* open the references found file for writing */
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate BOOL
writerefsfound(void)4677c478bd9Sstevel@tonic-gate writerefsfound(void)
4687c478bd9Sstevel@tonic-gate {
4697c478bd9Sstevel@tonic-gate 	if (refsfound == NULL) {
4707c478bd9Sstevel@tonic-gate 		if ((refsfound = fopen(temp1, "w")) == NULL) {
4717c478bd9Sstevel@tonic-gate 			cannotopen(temp1);
4727c478bd9Sstevel@tonic-gate 			return (NO);
4737c478bd9Sstevel@tonic-gate 		}
4747c478bd9Sstevel@tonic-gate 	} else if (freopen(temp1, "w", refsfound) == NULL) {
4757c478bd9Sstevel@tonic-gate 		putmsg("Cannot reopen temporary file");
4767c478bd9Sstevel@tonic-gate 		return (NO);
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 	return (YES);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate /* count the references found */
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate void
countrefs(void)4847c478bd9Sstevel@tonic-gate countrefs(void)
4857c478bd9Sstevel@tonic-gate {
4867c478bd9Sstevel@tonic-gate 	char	*subsystem;		/* OGS subsystem name */
4877c478bd9Sstevel@tonic-gate 	char 	*book;			/* OGS book name */
4887c478bd9Sstevel@tonic-gate 	char	file[PATHLEN + 1];	/* file name */
4897c478bd9Sstevel@tonic-gate 	char	function[PATLEN + 1];	/* function name */
4907c478bd9Sstevel@tonic-gate 	char	linenum[NUMLEN + 1];	/* line number */
4917c478bd9Sstevel@tonic-gate 	int	i;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	/*
4947c478bd9Sstevel@tonic-gate 	 * count the references found and find the length of the file,
4957c478bd9Sstevel@tonic-gate 	 * function, and line number display fields
4967c478bd9Sstevel@tonic-gate 	 */
4977c478bd9Sstevel@tonic-gate 	subsystemlen = 9;	/* strlen("Subsystem") */
4987c478bd9Sstevel@tonic-gate 	booklen = 4;		/* strlen("Book") */
4997c478bd9Sstevel@tonic-gate 	filelen = 4;		/* strlen("File") */
5007c478bd9Sstevel@tonic-gate 	fcnlen = 8;		/* strlen("Function") */
5017c478bd9Sstevel@tonic-gate 	numlen = 0;
5027c478bd9Sstevel@tonic-gate 	while ((i = fscanf(refsfound, "%250s%250s%6s %5000[^\n]", file,
5037c478bd9Sstevel@tonic-gate 	    function, linenum, yytext)) != EOF) {
5047c478bd9Sstevel@tonic-gate 		if (i != 4 || !isgraph(*file) ||
5057c478bd9Sstevel@tonic-gate 		    !isgraph(*function) || !isdigit(*linenum)) {
5067c478bd9Sstevel@tonic-gate 			putmsg("File does not have expected format");
5077c478bd9Sstevel@tonic-gate 			totallines = 0;
5087c478bd9Sstevel@tonic-gate 			return;
5097c478bd9Sstevel@tonic-gate 		}
5107c478bd9Sstevel@tonic-gate 		if ((i = strlen(pathcomponents(file,
5117c478bd9Sstevel@tonic-gate 		    dispcomponents))) > filelen) {
5127c478bd9Sstevel@tonic-gate 			filelen = i;
5137c478bd9Sstevel@tonic-gate 		}
5147c478bd9Sstevel@tonic-gate 		if (ogs == YES) {
5157c478bd9Sstevel@tonic-gate 			ogsnames(file, &subsystem, &book);
5167c478bd9Sstevel@tonic-gate 			if ((i = strlen(subsystem)) > subsystemlen) {
5177c478bd9Sstevel@tonic-gate 				subsystemlen = i;
5187c478bd9Sstevel@tonic-gate 			}
5197c478bd9Sstevel@tonic-gate 			if ((i = strlen(book)) > booklen) {
5207c478bd9Sstevel@tonic-gate 				booklen = i;
5217c478bd9Sstevel@tonic-gate 			}
5227c478bd9Sstevel@tonic-gate 		}
5237c478bd9Sstevel@tonic-gate 		if ((i = strlen(function)) > fcnlen) {
5247c478bd9Sstevel@tonic-gate 			fcnlen = i;
5257c478bd9Sstevel@tonic-gate 		}
5267c478bd9Sstevel@tonic-gate 		if ((i = strlen(linenum)) > numlen) {
5277c478bd9Sstevel@tonic-gate 			numlen = i;
5287c478bd9Sstevel@tonic-gate 		}
5297c478bd9Sstevel@tonic-gate 		++totallines;
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 	rewind(refsfound);
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	/* restrict the width of displayed columns */
5347c478bd9Sstevel@tonic-gate 	i = (COLS - 5) / 3;
5357c478bd9Sstevel@tonic-gate 	if (ogs == YES) {
5367c478bd9Sstevel@tonic-gate 		i = (COLS - 7) / 5;
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate 	if (filelen > i && i > 4) {
5397c478bd9Sstevel@tonic-gate 		filelen = i;
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 	if (subsystemlen > i && i > 9) {
5427c478bd9Sstevel@tonic-gate 		subsystemlen = i;
5437c478bd9Sstevel@tonic-gate 	}
5447c478bd9Sstevel@tonic-gate 	if (booklen > i && i > 4) {
5457c478bd9Sstevel@tonic-gate 		booklen = i;
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 	if (fcnlen > i && i > 8) {
5487c478bd9Sstevel@tonic-gate 		fcnlen = i;
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate /* print error message on system call failure */
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate void
myperror(char * text)5557c478bd9Sstevel@tonic-gate myperror(char *text)
5567c478bd9Sstevel@tonic-gate {
5577c478bd9Sstevel@tonic-gate 	char	msg[MSGLEN + 1];	/* message */
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	(void) sprintf(msg, "%s: %s", text, strerror(errno));
5607c478bd9Sstevel@tonic-gate 	putmsg(msg);
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate /* putmsg clears the message line and prints the message */
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate void
putmsg(char * msg)5667c478bd9Sstevel@tonic-gate putmsg(char *msg)
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate 	if (incurses == NO) {
5697c478bd9Sstevel@tonic-gate 		*msg = tolower(*msg);
5707c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "cscope: %s\n", msg);
5717c478bd9Sstevel@tonic-gate 	} else {
5727c478bd9Sstevel@tonic-gate 		(void) move(MSGLINE, 0);
5737c478bd9Sstevel@tonic-gate 		(void) clrtoeol();
5747c478bd9Sstevel@tonic-gate 		(void) addstr(msg);
5757c478bd9Sstevel@tonic-gate 		(void) refresh();
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 	(void) strncpy(lastmsg, msg, sizeof (lastmsg) - 1);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate /* clearmsg2 clears the second message line */
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate void
clearmsg2(void)5837c478bd9Sstevel@tonic-gate clearmsg2(void)
5847c478bd9Sstevel@tonic-gate {
5857c478bd9Sstevel@tonic-gate 	if (incurses == YES) {
5867c478bd9Sstevel@tonic-gate 		(void) move(MSGLINE + 1, 0);
5877c478bd9Sstevel@tonic-gate 		(void) clrtoeol();
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate }
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate /* putmsg2 clears the second message line and prints the message */
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate void
putmsg2(char * msg)5947c478bd9Sstevel@tonic-gate putmsg2(char *msg)
5957c478bd9Sstevel@tonic-gate {
5967c478bd9Sstevel@tonic-gate 	if (incurses == NO) {
5977c478bd9Sstevel@tonic-gate 		putmsg(msg);
5987c478bd9Sstevel@tonic-gate 	} else {
5997c478bd9Sstevel@tonic-gate 		clearmsg2();
6007c478bd9Sstevel@tonic-gate 		(void) addstr(msg);
6017c478bd9Sstevel@tonic-gate 		(void) refresh();
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate /* position the references found file at the specified line */
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate void
seekline(int line)6087c478bd9Sstevel@tonic-gate seekline(int line)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	int	c;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	/* verify that there is a references found file */
6137c478bd9Sstevel@tonic-gate 	if (refsfound == NULL) {
6147c478bd9Sstevel@tonic-gate 		return;
6157c478bd9Sstevel@tonic-gate 	}
6167c478bd9Sstevel@tonic-gate 	/* go to the beginning of the file */
6177c478bd9Sstevel@tonic-gate 	rewind(refsfound);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	/* find the requested line */
6207c478bd9Sstevel@tonic-gate 	nextline = 1;
6217c478bd9Sstevel@tonic-gate 	while (nextline < line && (c = getc(refsfound)) != EOF) {
6227c478bd9Sstevel@tonic-gate 		if (c == '\n') {
6237c478bd9Sstevel@tonic-gate 			nextline++;
6247c478bd9Sstevel@tonic-gate 		}
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate /* get the OGS subsystem and book names */
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate void
ogsnames(char * file,char ** subsystem,char ** book)6317c478bd9Sstevel@tonic-gate ogsnames(char *file, char **subsystem, char **book)
6327c478bd9Sstevel@tonic-gate {
6337c478bd9Sstevel@tonic-gate 	static	char	buf[PATHLEN + 1];
6347c478bd9Sstevel@tonic-gate 	char	*s, *slash;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	*subsystem = *book = "";
6377c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, file);
6387c478bd9Sstevel@tonic-gate 	s = buf;
6397c478bd9Sstevel@tonic-gate 	if (*s == '/') {
6407c478bd9Sstevel@tonic-gate 		++s;
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 	while ((slash = strchr(s, '/')) != NULL) {
6437c478bd9Sstevel@tonic-gate 		*slash = '\0';
6447c478bd9Sstevel@tonic-gate 		if ((int)strlen(s) >= 3 && strncmp(slash - 3, ".ss", 3) == 0) {
6457c478bd9Sstevel@tonic-gate 			*subsystem = s;
6467c478bd9Sstevel@tonic-gate 			s = slash + 1;
6477c478bd9Sstevel@tonic-gate 			if ((slash = strchr(s, '/')) != NULL) {
6487c478bd9Sstevel@tonic-gate 				*book = s;
6497c478bd9Sstevel@tonic-gate 				*slash = '\0';
6507c478bd9Sstevel@tonic-gate 			}
6517c478bd9Sstevel@tonic-gate 			break;
6527c478bd9Sstevel@tonic-gate 		}
6537c478bd9Sstevel@tonic-gate 		s = slash + 1;
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate /* get the requested path components */
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate char *
pathcomponents(char * path,int components)6607c478bd9Sstevel@tonic-gate pathcomponents(char *path, int components)
6617c478bd9Sstevel@tonic-gate {
6627c478bd9Sstevel@tonic-gate 	int	i;
6637c478bd9Sstevel@tonic-gate 	char	*s;
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	s = path + strlen(path) - 1;
6667c478bd9Sstevel@tonic-gate 	for (i = 0; i < components; ++i) {
6677c478bd9Sstevel@tonic-gate 		while (s > path && *--s != '/') {
6687c478bd9Sstevel@tonic-gate 			;
6697c478bd9Sstevel@tonic-gate 		}
6707c478bd9Sstevel@tonic-gate 	}
6717c478bd9Sstevel@tonic-gate 	if (s > path && *s == '/') {
6727c478bd9Sstevel@tonic-gate 		++s;
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 	return (s);
6757c478bd9Sstevel@tonic-gate }
676