[comp.sys.hp] look for HP-UX

rer@hpfcdc.HP.COM (Rob Robason) (07/20/90)

h> I notice that our HP9000/840 doesn't have the "look" command.
h> Is the source for this pd and available somewhere for anon-ftp?

To my knowledge, look in not pd.  It is part of the BSD4.3 release
and doesn't appear on the list of CONTRIBUTED utilities I have.

Rob Robason

jewett@hpl-opus.HP.COM (Bob Jewett) (07/23/90)

> I notice that our HP9000/840 doesn't have the "look" command.
> Is the source for this pd and available somewhere for anon-ftp?

I hacked together a version of look (which has -f but lacks -d) to get
the dictionary search command to work in ispell.  The shar is 8 kbytes.
If I get three e-mail requests, I'll post it, unless someone has a better
version they can part with, or wants to add -d first.

Bob

jewett@hpl-opus.HP.COM (Bob Jewett) (07/25/90)

> If I get three e-mail requests, I'll post it, unless someone has a better
> version they can part with, or wants to add -d first.

There were requests, but no offers of improved versions.  If you add the
-d option (which seems to be unnecessary since /usr/dict/words is -f?),
please send me the context diffs.

The binary search routine is by Alan Silverstein; I wrote the (now old and
crufty) wrapper to turn it into "look".

Bob Jewett


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Bob Jewett <jewett@hpl-bill> on Wed Jul 25 08:51:05 1990
#
# This archive contains:
#	look.1		Makefile	look.c		
#

LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH

echo x - look.1
cat >look.1 <<'@EOF'
.TH LOOK 1 Local
.AT 3
.SH NAME
look \- find lines in a sorted list
.SH SYNOPSIS
.B look
[
.B \-f
]
string
[ file ]
.SH DESCRIPTION
.I Look
searches a sorted
.I file
and prints all lines that begin with
.IR string .
It uses binary search.
.PP
The option
.B f
says that upper and lower case characters are equal.
.PP
If no
.I file
is specified,
.I /usr/dict/words
is assumed with collating sequence
.B \-f.
.SH BUGS
This is a quick and dirty version of the BSD
.I look
command to make ispell work.
It lacks the 
.B -d
option.
.SH FILES
/usr/dict/words
.SH "SEE ALSO"
sort(1), grep(1)
@EOF

chmod 644 look.1

echo x - Makefile
cat >Makefile <<'@EOF'
# Makefile for look
#

PROGNAME = look
CFLAGS = -O
SRC = ${PROGNAME}.c
MANSECT=1
MAN = ${PROGNAME}.1
BINDIR = /usr/local/bin
MANDIR = /usr/local/man

$(PROGNAME): $(SRC) 
	cc ${CFLAGS} ${SRC}
	mv a.out ${PROGNAME}
	strip ${PROGNAME}

install: $(PROGNAME)
	cp $(PROGNAME) $(BINDIR)/${PROGNAME}
	cp $(MAN) ${MANDIR}/man${MANSECT}/${PROGNAME}.${MANSECT}
	/bin/rm -f  ${MANDIR}/cat${MANSECT}/${PROGNAME}.${MANSECT}

clean:
	/bin/rm -f $(PROGNAME) core *.o

shar : Makefile ${SRC} ${MAN}
	shar ${MAN} Makefile ${SRC} > shar
@EOF

chmod 664 Makefile

echo x - look.c
cat >look.c <<'@EOF'
#include <stdio.h>
#include <ctype.h>

#define	chNull	('\0')
#define	cpNull	((char *) NULL)
#define WORDLIST "/usr/dict/words"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

char *progname;
char *ap_upstr();

/*
 * Usage:  look [ -f ] string [ file ]
 *
 * -f means fold lower case to upper
 */

main (argc, argv)
	int	argc;
	char	**argv;
{
    FILE	*fp;
    char	buf[BUFSIZ];
    char	upbuf[BUFSIZ];
    int		argpoint;
    int		foldcase=FALSE;
    char	instring[BUFSIZ];
    char	upinstring[BUFSIZ];
    char	*sortedfile=WORDLIST;

    instring[0]='\0';
    progname=argv[0];
    if(argc < 2 || argc > 4) Usage();
    if(argv[1][0] == '-')
	{
	if(strcmp(argv[1],"-f")) Usage();
	if(argc < 3) Usage();
	foldcase=TRUE;
	strcpy(instring,argv[2]);
	if(argc == 4) sortedfile=argv[3];
	}
    else
	{
	if(argc > 3) Usage();
	strcpy(instring,argv[1]);
	if(argc == 2) foldcase=TRUE;
	if(argc == 3) sortedfile=argv[2];
	}

    strcpy(upinstring,instring);
    ap_upstr(upinstring);
    if(foldcase) ap_upstr(instring);
    fp = fopen (sortedfile, "r");
    if(fp == NULL)
	{
	fprintf(stderr,"%s: file %s not readable.\n",progname,sortedfile);
	exit(1);
	}
    if(bsearchstr (fp, upinstring, TRUE, FALSE) < 0L)
	{
	/* fprintf(stderr,"bsearchstr failed to find anything\n"); */
	exit(0);
	}
    while ( fgets(buf,BUFSIZ,fp) != NULL &&
	    starts2(upinstring,ap_upstr(strcpy(upbuf,buf))))
	if(foldcase || starts2(instring,buf))
	printf ("%s", buf);  /* no newline required ??? */
    exit(0);
}


/***************************************************************************
 * B S E A R C H S T R
 *
 * Binary search a stream consisting of sorted lines of data for the first
 * line that starts with the given pattern, or the next line if none and
 * tellnext == 1.  Set the file location to the first byte of that line
 * and return the offset.
 *
 * When caseins is set, takes pains not to modify the memory pointed to by
 * pattern.  Uses multi-statement macros for efficiency.
 *
 * See bsearchstr(3) for more information.
 *
 * Author:  Alan Silverstein, Hewlett-Packard Fort Collins Systems Division
 */

#define	LT 0
#define	EQ 1
#define	GT 2

#define	RETURN(value)	{ if (caseins) free (pattern); return (value); }
#define	SETPOS		{ if (fseek (filep, pos, 0) < 0) RETURN (-2L); }

long bsearchstr (filep, pattern, caseins, tellnext)
	FILE	*filep;			/* file to search	   */
	char	*pattern;		/* start of line to match  */
	int	caseins;		/* case insensitive?	   */
	int	tellnext;		/* tell next if not found? */
{
	/* start of first line not yet compared (lower limit) */
	long	min = 0;
	/* start of line after last line not yet compared (upper limit) */
	long	max;

	 long	pos;			/* current offset in file  */
	 char	*patp;			/* pattern pointer	   */
	 /* warning: this must be an int, not a char */
register int	ch;			/* current char to compare */
register int	cmp;			/* results of comparison   */
	 int	match = 0;		/* true if match found	   */

	 char	*malloc();

/*
 * PREPARE PATTERN FOR CASE-INSENSITIVE SEARCH:
 *
 * Use toupper(), not tolower(), to be compatible with the actual function
 * of sort -f.
 */

	if (caseins)
	{
	    int	  len = strlen (pattern) + 1;	/* chars to uppercase	*/
	    char  *cp;				/* for copying data	*/
	    char  *cpend;			/* end of copy range	*/

	    if ((cp = patp = malloc (len)) == cpNull)
		return (-2L);

	    /* now remember to free (pattern) before returning	*/
	    /* can use the RETURN() macro to accomplish this	*/

	    cpend = cp + len;

	    while (cp < cpend)			/* copy chNull also	     */
		*cp++ = toupper (*pattern++);	/* toupper() is not a macro! */

	    pattern = patp;			/* "move" to new location */
	}

/*
 * SET MAX TO END OF FILE (byte past last) by seeking there:
 */

	if ((fseek (filep, 0L, 2) < 0) || ((max = ftell (filep)) < 0))
	    RETURN (-2L);

/*
 * SET NEXT STARTING POSITION (where to find string and compare):
 */

	while (min < max)			/* do until closure happens */
	{
	    pos = (min + max) / 2;
	    SETPOS;

#ifdef DEBUG
	    printf ("%8ld %8ld %8ld ", min, max, pos);
#endif

/*
 * LOOK FOR THE NEXT END OF LINE IN THE FORWARD DIRECTION:
 */

	    while ((pos < max) && (getc (filep) != '\n'))
		pos++;

	    pos++;				/* skip newline */

/*
 * If we ran into max, we are nearly done, assuming the current last line is
 * not really huge compared to all the others (but this will work out OK too).
 * Simply reset pos = min and check the first current line.
 */

	    if (pos >= max)
		pos = min;

/*
 * COMPARE THE CURRENT LINE TO THE PATTERN:
 *
 * If pattern[0] == chNull, never does the for loop, so it matches anything.
 */

	    SETPOS;

	    for (cmp = EQ, patp = pattern; (*patp != chNull); patp++)
	    {
		ch = caseins ? toupper (getc (filep)) : getc (filep);

		if ((ch < *patp) || (ch == '\n') || (ch == EOF))
		{				/* line < pattern */
		    cmp = LT;
		    break;
		}
		else if (ch > *patp)		/* line > pattern */
		{
		    cmp = GT;
		    break;
		}
	    }

	    match += (cmp == EQ);		/* note a match */

#ifdef DEBUG
	    printf ("%8ld  %c  %5d\n", pos,
		    ((cmp == LT) ? '<' : ((cmp == EQ) ? '=' : '>')), match);
#endif
		
/*
 * MOVE MIN OR MAX according to the results of comparison:
 *
 * If pattern[0] == chNull, cmp == EQ, which is "safe".
 */

	    if (cmp == LT)				/* min => next line */
	    {
		min = pos + (patp - pattern);

		while ((ch != '\n') && (min < max))	/* find end */
		{
		    ch = getc (filep);
		    min++;
		}
		min++;					/* skip newline */
	    }
	    else					/* max => this line */
	    {
		max = pos;
	    }

	} /* while */

/*
 * FINISH UP:
 *
 * Note that min could be one too large if the last line is unterminated
 * and less than pattern, so we use max instead.
 */

	if (match || tellnext)			/* success */
	{
	    pos = max;
	    SETPOS;
	    RETURN (pos);
	}
	else					/* failure */
	{
	    RETURN (-1L);
	}

} /* bsearchstr */

Usage()
{
    fprintf(stderr,"Usage: %s [ -f ] string [ file ]\n",progname);
    exit(1);
}

char *ap_upstr(str)
char *str;
{
int i;
for(i=0;str[i] != '\0';i++)
	if(str[i] >= 'a' && str[i] <= 'z') str[i]=str[i]+'A'-'a';
return(str);
}

/*  string 1 starts string 2.  Must be followed by whitespace or nothing */

starts(s1,s2)
char s1[], s2[];
{
int i;
for(i=0; s1[i] != 0; i++)
	if(s1[i] != s2[i]) return(0);
if(s2[i] == '\0' ||
   s2[i] == ' '  ||
   s2[i] == '\011' ) return(1);
return(0);
}

/*  string 1 starts string 2.  May be followed by printing characters */

starts2(s1,s2)
char s1[], s2[];
{
int i;
for(i=0; s1[i] != 0; i++)
	if(s1[i] != s2[i]) return(0);
return(1);
}
@EOF

chmod 666 look.c

exit 0