145e5710bSMark Peek /* $Header: /p/tcsh/cvsroot/tcsh/tw.spell.c,v 3.21 2006/03/02 18:46:45 christos Exp $ */ 2c80476e4SDavid E. O'Brien /* 3c80476e4SDavid E. O'Brien * tw.spell.c: Spell check words 4c80476e4SDavid E. O'Brien */ 5c80476e4SDavid E. O'Brien /*- 6c80476e4SDavid E. O'Brien * Copyright (c) 1980, 1991 The Regents of the University of California. 7c80476e4SDavid E. O'Brien * All rights reserved. 8c80476e4SDavid E. O'Brien * 9c80476e4SDavid E. O'Brien * Redistribution and use in source and binary forms, with or without 10c80476e4SDavid E. O'Brien * modification, are permitted provided that the following conditions 11c80476e4SDavid E. O'Brien * are met: 12c80476e4SDavid E. O'Brien * 1. Redistributions of source code must retain the above copyright 13c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer. 14c80476e4SDavid E. O'Brien * 2. Redistributions in binary form must reproduce the above copyright 15c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer in the 16c80476e4SDavid E. O'Brien * documentation and/or other materials provided with the distribution. 1729301572SMark Peek * 3. Neither the name of the University nor the names of its contributors 18c80476e4SDavid E. O'Brien * may be used to endorse or promote products derived from this software 19c80476e4SDavid E. O'Brien * without specific prior written permission. 20c80476e4SDavid E. O'Brien * 21c80476e4SDavid E. O'Brien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22c80476e4SDavid E. O'Brien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23c80476e4SDavid E. O'Brien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24c80476e4SDavid E. O'Brien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25c80476e4SDavid E. O'Brien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26c80476e4SDavid E. O'Brien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27c80476e4SDavid E. O'Brien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28c80476e4SDavid E. O'Brien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29c80476e4SDavid E. O'Brien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30c80476e4SDavid E. O'Brien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31c80476e4SDavid E. O'Brien * SUCH DAMAGE. 32c80476e4SDavid E. O'Brien */ 33c80476e4SDavid E. O'Brien #include "sh.h" 34c80476e4SDavid E. O'Brien 3545e5710bSMark Peek RCSID("$tcsh: tw.spell.c,v 3.21 2006/03/02 18:46:45 christos Exp $") 36c80476e4SDavid E. O'Brien 37c80476e4SDavid E. O'Brien #include "tw.h" 38c80476e4SDavid E. O'Brien 39c80476e4SDavid E. O'Brien /* spell_me : return corrrectly spelled filename. From K&P spname */ 40c80476e4SDavid E. O'Brien int 4145e5710bSMark Peek spell_me(struct Strbuf *oldname, int looking, Char *pat, eChar suf) 42c80476e4SDavid E. O'Brien { 4345e5710bSMark Peek struct Strbuf guess = Strbuf_INIT, newname = Strbuf_INIT; 4445e5710bSMark Peek const Char *old = oldname->s; 4545e5710bSMark Peek size_t ws; 4623338178SMark Peek int foundslash = 0; 47c80476e4SDavid E. O'Brien int retval; 48c80476e4SDavid E. O'Brien 4945e5710bSMark Peek cleanup_push(&guess, Strbuf_cleanup); 5045e5710bSMark Peek cleanup_push(&newname, Strbuf_cleanup); 51c80476e4SDavid E. O'Brien for (;;) { 52c80476e4SDavid E. O'Brien while (*old == '/') { /* skip '/' */ 5345e5710bSMark Peek Strbuf_append1(&newname, *old++); 54c80476e4SDavid E. O'Brien foundslash = 1; 55c80476e4SDavid E. O'Brien } 56c80476e4SDavid E. O'Brien /* do not try to correct spelling of single letter words */ 57c80476e4SDavid E. O'Brien if (*old != '\0' && old[1] == '\0') 5845e5710bSMark Peek Strbuf_append1(&newname, *old++); 5945e5710bSMark Peek Strbuf_terminate(&newname); 60c80476e4SDavid E. O'Brien if (*old == '\0') { 6145e5710bSMark Peek retval = (StrQcmp(oldname->s, newname.s) != 0); 6245e5710bSMark Peek cleanup_ignore(&newname); 6345e5710bSMark Peek xfree(oldname->s); 6445e5710bSMark Peek *oldname = newname; /* shove it back. */ 6545e5710bSMark Peek cleanup_until(&guess); 66c80476e4SDavid E. O'Brien return retval; 67c80476e4SDavid E. O'Brien } 6845e5710bSMark Peek guess.len = 0; /* start at beginning of buf */ 6945e5710bSMark Peek Strbuf_append(&guess, newname.s); /* add current dir if any */ 7045e5710bSMark Peek ws = guess.len; 71c80476e4SDavid E. O'Brien for (; *old != '/' && *old != '\0'; old++)/* add current file name */ 7245e5710bSMark Peek Strbuf_append1(&guess, *old); 7345e5710bSMark Peek Strbuf_terminate(&guess); 74c80476e4SDavid E. O'Brien 75c80476e4SDavid E. O'Brien /* 76c80476e4SDavid E. O'Brien * Don't tell t_search we're looking for cmd if no '/' in the name so 77c80476e4SDavid E. O'Brien * far but there are later - or it will look for *all* commands 78c80476e4SDavid E. O'Brien */ 79c80476e4SDavid E. O'Brien /* (*should* say "looking for directory" whenever '/' is next...) */ 8045e5710bSMark Peek retval = t_search(&guess, SPELL, 81c80476e4SDavid E. O'Brien looking == TW_COMMAND && (foundslash || *old != '/') ? 82c80476e4SDavid E. O'Brien TW_COMMAND : looking, 1, pat, suf); 8345e5710bSMark Peek if (retval >= 4 || retval < 0) { 8445e5710bSMark Peek cleanup_until(&guess); 85c80476e4SDavid E. O'Brien return -1; /* hopeless */ 8645e5710bSMark Peek } 8745e5710bSMark Peek Strbuf_append(&newname, guess.s + ws); 88c80476e4SDavid E. O'Brien } 89c80476e4SDavid E. O'Brien /*NOTREACHED*/ 90c80476e4SDavid E. O'Brien #ifdef notdef 91c80476e4SDavid E. O'Brien return (0); /* lint on the vax under mtXinu complains! */ 92c80476e4SDavid E. O'Brien #endif 93c80476e4SDavid E. O'Brien } 94c80476e4SDavid E. O'Brien 95c80476e4SDavid E. O'Brien #define EQ(s,t) (StrQcmp(s,t) == 0) 96c80476e4SDavid E. O'Brien 97c80476e4SDavid E. O'Brien /* 98c80476e4SDavid E. O'Brien * spdist() is taken from Kernighan & Pike, 99c80476e4SDavid E. O'Brien * _The_UNIX_Programming_Environment_ 100c80476e4SDavid E. O'Brien * and adapted somewhat to correspond better to psychological reality. 101c80476e4SDavid E. O'Brien * (Note the changes to the return values) 102c80476e4SDavid E. O'Brien * 103c80476e4SDavid E. O'Brien * According to Pollock and Zamora, CACM April 1984 (V. 27, No. 4), 104c80476e4SDavid E. O'Brien * page 363, the correct order for this is: 105c80476e4SDavid E. O'Brien * OMISSION = TRANSPOSITION > INSERTION > SUBSTITUTION 106c80476e4SDavid E. O'Brien * thus, it was exactly backwards in the old version. -- PWP 107c80476e4SDavid E. O'Brien */ 108c80476e4SDavid E. O'Brien 109c80476e4SDavid E. O'Brien int 11045e5710bSMark Peek spdist(const Char *s, const Char *t) 111c80476e4SDavid E. O'Brien { 112c80476e4SDavid E. O'Brien for (; (*s & TRIM) == (*t & TRIM); t++, s++) 113c80476e4SDavid E. O'Brien if (*t == '\0') 114c80476e4SDavid E. O'Brien return 0; /* exact match */ 115c80476e4SDavid E. O'Brien if (*s) { 116c80476e4SDavid E. O'Brien if (*t) { 117c80476e4SDavid E. O'Brien if (s[1] && t[1] && (*s & TRIM) == (t[1] & TRIM) && 118c80476e4SDavid E. O'Brien (*t & TRIM) == (s[1] & TRIM) && EQ(s + 2, t + 2)) 119c80476e4SDavid E. O'Brien return 1; /* transposition */ 120c80476e4SDavid E. O'Brien if (EQ(s + 1, t + 1)) 121c80476e4SDavid E. O'Brien return 3; /* 1 char mismatch */ 122c80476e4SDavid E. O'Brien } 123c80476e4SDavid E. O'Brien if (EQ(s + 1, t)) 124c80476e4SDavid E. O'Brien return 2; /* extra character */ 125c80476e4SDavid E. O'Brien } 126c80476e4SDavid E. O'Brien if (*t && EQ(s, t + 1)) 127c80476e4SDavid E. O'Brien return 1; /* missing character */ 128c80476e4SDavid E. O'Brien return 4; 129c80476e4SDavid E. O'Brien } 130c80476e4SDavid E. O'Brien 131c80476e4SDavid E. O'Brien int 13245e5710bSMark Peek spdir(struct Strbuf *extended_name, const Char *tilded_dir, const Char *item, 13345e5710bSMark Peek Char *name) 134c80476e4SDavid E. O'Brien { 13545e5710bSMark Peek Char *path, *s, oldch; 13645e5710bSMark Peek char *p; 137c80476e4SDavid E. O'Brien 138c80476e4SDavid E. O'Brien if (ISDOT(item) || ISDOTDOT(item)) 139c80476e4SDavid E. O'Brien return 0; 140c80476e4SDavid E. O'Brien 141c80476e4SDavid E. O'Brien for (s = name; *s != 0 && (*s & TRIM) == (*item & TRIM); s++, item++) 142c80476e4SDavid E. O'Brien continue; 143c80476e4SDavid E. O'Brien if (*s == 0 || s[1] == 0 || *item != 0) 144c80476e4SDavid E. O'Brien return 0; 145c80476e4SDavid E. O'Brien 14645e5710bSMark Peek path = xmalloc((Strlen(tilded_dir) + Strlen(name) + 1) * sizeof (*path)); 147c80476e4SDavid E. O'Brien (void) Strcpy(path, tilded_dir); 148c80476e4SDavid E. O'Brien oldch = *s; 149c80476e4SDavid E. O'Brien *s = '/'; 15045e5710bSMark Peek Strcat(path, name); 15145e5710bSMark Peek p = short2str(path); 15245e5710bSMark Peek xfree(path); 15345e5710bSMark Peek if (access(p, F_OK) == 0) { 15445e5710bSMark Peek extended_name->len = 0; 15545e5710bSMark Peek Strbuf_append(extended_name, name); 15645e5710bSMark Peek Strbuf_terminate(extended_name); 15745e5710bSMark Peek /* FIXME: *s = oldch? */ 158c80476e4SDavid E. O'Brien return 1; 159c80476e4SDavid E. O'Brien } 160c80476e4SDavid E. O'Brien *s = oldch; 161c80476e4SDavid E. O'Brien return 0; 162c80476e4SDavid E. O'Brien } 163