tw.spell.c revision 59243
159243Sobrien/* $Header: /src/pub/tcsh/tw.spell.c,v 3.14 1996/04/26 19:23:27 christos Exp $ */
259243Sobrien/*
359243Sobrien * tw.spell.c: Spell check words
459243Sobrien */
559243Sobrien/*-
659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
759243Sobrien * All rights reserved.
859243Sobrien *
959243Sobrien * Redistribution and use in source and binary forms, with or without
1059243Sobrien * modification, are permitted provided that the following conditions
1159243Sobrien * are met:
1259243Sobrien * 1. Redistributions of source code must retain the above copyright
1359243Sobrien *    notice, this list of conditions and the following disclaimer.
1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1559243Sobrien *    notice, this list of conditions and the following disclaimer in the
1659243Sobrien *    documentation and/or other materials provided with the distribution.
1759243Sobrien * 3. All advertising materials mentioning features or use of this software
1859243Sobrien *    must display the following acknowledgement:
1959243Sobrien *	This product includes software developed by the University of
2059243Sobrien *	California, Berkeley and its contributors.
2159243Sobrien * 4. Neither the name of the University nor the names of its contributors
2259243Sobrien *    may be used to endorse or promote products derived from this software
2359243Sobrien *    without specific prior written permission.
2459243Sobrien *
2559243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2659243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2759243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2859243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2959243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3059243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3159243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3259243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3359243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3459243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3559243Sobrien * SUCH DAMAGE.
3659243Sobrien */
3759243Sobrien#include "sh.h"
3859243Sobrien
3959243SobrienRCSID("$Id: tw.spell.c,v 3.14 1996/04/26 19:23:27 christos Exp $")
4059243Sobrien
4159243Sobrien#include "tw.h"
4259243Sobrien
4359243Sobrien/* spell_me : return corrrectly spelled filename.  From K&P spname */
4459243Sobrienint
4559243Sobrienspell_me(oldname, oldsize, looking, pat, suf)
4659243Sobrien    Char   *oldname;
4759243Sobrien    int     oldsize, looking;
4859243Sobrien    Char   *pat;
4959243Sobrien    int     suf;
5059243Sobrien{
5159243Sobrien    /* The +1 is to fool hp's optimizer */
5259243Sobrien    Char    guess[FILSIZ + 1], newname[FILSIZ + 1];
5359243Sobrien    register Char *new = newname, *old = oldname;
5459243Sobrien    register Char *p, *cp, *ws;
5559243Sobrien    bool    foundslash = 0;
5659243Sobrien    int     retval;
5759243Sobrien
5859243Sobrien    for (;;) {
5959243Sobrien	while (*old == '/') {	/* skip '/' */
6059243Sobrien	    *new++ = *old++;
6159243Sobrien	    foundslash = 1;
6259243Sobrien	}
6359243Sobrien	/* do not try to correct spelling of single letter words */
6459243Sobrien	if (*old != '\0' && old[1] == '\0')
6559243Sobrien	    *new++ = *old++;
6659243Sobrien	*new = '\0';
6759243Sobrien	if (*old == '\0') {
6859243Sobrien	    retval = (StrQcmp(oldname, newname) != 0);
6959243Sobrien	    copyn(oldname, newname, oldsize);	/* shove it back. */
7059243Sobrien	    return retval;
7159243Sobrien	}
7259243Sobrien	p = guess;		/* start at beginning of buf */
7359243Sobrien	if (newname[0])		/* add current dir if any */
7459243Sobrien	    for (cp = newname; *cp; cp++)
7559243Sobrien		if (p < guess + FILSIZ)
7659243Sobrien		    *p++ = *cp;
7759243Sobrien	ws = p;
7859243Sobrien	for (; *old != '/' && *old != '\0'; old++)/* add current file name */
7959243Sobrien	    if (p < guess + FILSIZ)
8059243Sobrien		*p++ = *old;
8159243Sobrien	*p = '\0';		/* terminate it */
8259243Sobrien
8359243Sobrien	/*
8459243Sobrien	 * Don't tell t_search we're looking for cmd if no '/' in the name so
8559243Sobrien	 * far but there are later - or it will look for *all* commands
8659243Sobrien	 */
8759243Sobrien	/* (*should* say "looking for directory" whenever '/' is next...) */
8859243Sobrien	retval = t_search(guess, p, SPELL, FILSIZ,
8959243Sobrien			  looking == TW_COMMAND && (foundslash || *old != '/') ?
9059243Sobrien			  TW_COMMAND : looking, 1, pat, suf);
9159243Sobrien	if (retval >= 4 || retval < 0)
9259243Sobrien	    return -1;		/* hopeless */
9359243Sobrien	for (p = ws; (*new = *p++) != '\0'; new++)
9459243Sobrien	    continue;
9559243Sobrien    }
9659243Sobrien/*NOTREACHED*/
9759243Sobrien#ifdef notdef
9859243Sobrien    return (0);			/* lint on the vax under mtXinu complains! */
9959243Sobrien#endif
10059243Sobrien}
10159243Sobrien
10259243Sobrien#define EQ(s,t)	(StrQcmp(s,t) == 0)
10359243Sobrien
10459243Sobrien/*
10559243Sobrien * spdist() is taken from Kernighan & Pike,
10659243Sobrien *  _The_UNIX_Programming_Environment_
10759243Sobrien * and adapted somewhat to correspond better to psychological reality.
10859243Sobrien * (Note the changes to the return values)
10959243Sobrien *
11059243Sobrien * According to Pollock and Zamora, CACM April 1984 (V. 27, No. 4),
11159243Sobrien * page 363, the correct order for this is:
11259243Sobrien * OMISSION = TRANSPOSITION > INSERTION > SUBSTITUTION
11359243Sobrien * thus, it was exactly backwards in the old version. -- PWP
11459243Sobrien */
11559243Sobrien
11659243Sobrienint
11759243Sobrienspdist(s, t)
11859243Sobrien    register Char *s, *t;
11959243Sobrien{
12059243Sobrien    for (; (*s & TRIM) == (*t & TRIM); t++, s++)
12159243Sobrien	if (*t == '\0')
12259243Sobrien	    return 0;		/* exact match */
12359243Sobrien    if (*s) {
12459243Sobrien	if (*t) {
12559243Sobrien	    if (s[1] && t[1] && (*s & TRIM) == (t[1] & TRIM) &&
12659243Sobrien		(*t & TRIM) == (s[1] & TRIM) && EQ(s + 2, t + 2))
12759243Sobrien		return 1;	/* transposition */
12859243Sobrien	    if (EQ(s + 1, t + 1))
12959243Sobrien		return 3;	/* 1 char mismatch */
13059243Sobrien	}
13159243Sobrien	if (EQ(s + 1, t))
13259243Sobrien	    return 2;		/* extra character */
13359243Sobrien    }
13459243Sobrien    if (*t && EQ(s, t + 1))
13559243Sobrien	return 1;		/* missing character */
13659243Sobrien    return 4;
13759243Sobrien}
13859243Sobrien
13959243Sobrienint
14059243Sobrienspdir(extended_name, tilded_dir, item, name)
14159243Sobrien    Char   *extended_name;
14259243Sobrien    Char   *tilded_dir;
14359243Sobrien    Char   *item;
14459243Sobrien    Char   *name;
14559243Sobrien{
14659243Sobrien    Char    path[MAXPATHLEN + 1];
14759243Sobrien    Char   *s;
14859243Sobrien    Char    oldch;
14959243Sobrien
15059243Sobrien    if (ISDOT(item) || ISDOTDOT(item))
15159243Sobrien	return 0;
15259243Sobrien
15359243Sobrien    for (s = name; *s != 0 && (*s & TRIM) == (*item & TRIM); s++, item++)
15459243Sobrien	continue;
15559243Sobrien    if (*s == 0 || s[1] == 0 || *item != 0)
15659243Sobrien	return 0;
15759243Sobrien
15859243Sobrien    (void) Strcpy(path, tilded_dir);
15959243Sobrien    oldch = *s;
16059243Sobrien    *s = '/';
16159243Sobrien    catn(path, name, (int) (sizeof(path) / sizeof(Char)));
16259243Sobrien    if (access(short2str(path), F_OK) == 0) {
16359243Sobrien	(void) Strcpy(extended_name, name);
16459243Sobrien	return 1;
16559243Sobrien    }
16659243Sobrien    *s = oldch;
16759243Sobrien    return 0;
16859243Sobrien}
169