home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / phlspl10 / part01 < prev    next >
Encoding:
Text File  |  1993-04-30  |  20.5 KB  |  676 lines

  1. Newsgroups: comp.sources.unix
  2. From: phillip@soda.Berkeley.EDU (Phillip Nunez)
  3. Subject: v26i200: philspell - correct problematic spelling in text files, Part01/01
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: phillip@soda.Berkeley.EDU (Phillip Nunez)
  8. Posting-Number: Volume 26, Issue 200
  9. Archive-Name: philspell-1.0/part01
  10.  
  11. Name
  12.        philspell - correct problematic spelling in text files
  13.  
  14. Syntax
  15.        philspell [-v] [-f file]
  16.  
  17. Description
  18.        The  command  collects  words  from the standard input and
  19.        looks them up in a spelling list.  Words that are  not  on
  20.        the spelling list and are not deriveable from words on the
  21.        list (by applying certain inflections,  prefixes  or  suf-
  22.        fixes)  are corrected.  To the standard output, prints the
  23.        original text with all misspelled words corrected.
  24.  
  25.         phillip@soda.Berkeley.EDU (Phillip Nunez)
  26.  
  27. #! /bin/sh
  28. # This is a shell archive.  Remove anything before this line, then unpack
  29. # it by saving it into a file and typing "sh file".  To overwrite existing
  30. # files, type "sh file -c".  You can also feed this as standard input via
  31. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  32. # will see the following message at the end:
  33. #        "End of archive 1 (of 1)."
  34. # Contents:  MANIFEST Makefile README main.c philspell.man
  35. #   philspell.test skiplist.c skiplist.h
  36. # Wrapped by vixie@efficacy.home.vix.com on Sat May  1 17:05:52 1993
  37. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  38. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  39.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  40. else
  41. echo shar: Extracting \"'MANIFEST'\" \(362 characters\)
  42. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  43. X   File Name        Archive #    Description
  44. X-----------------------------------------------------------
  45. X MANIFEST                   1    This shipping list
  46. X Makefile                   1    
  47. X README                     1    
  48. X main.c                     1    
  49. X philspell.man              1    
  50. X philspell.test             1    
  51. X skiplist.c                 1    
  52. X skiplist.h                 1    
  53. END_OF_FILE
  54. if test 362 -ne `wc -c <'MANIFEST'`; then
  55.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  56. fi
  57. # end of 'MANIFEST'
  58. fi
  59. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  60.   echo shar: Will not clobber existing file \"'Makefile'\"
  61. else
  62. echo shar: Extracting \"'Makefile'\" \(321 characters\)
  63. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  64. X#CC = philcc
  65. X
  66. X# Change the above to something like gcc or cc if you don't have philcc.
  67. X
  68. XCFLAGS = -g -DNDEBUG
  69. X
  70. XSOURCES = main.c skiplist.c
  71. XOBJECTS = main.o skiplist.o
  72. X
  73. Xall: philspell
  74. X
  75. Xphilspell: $(OBJECTS)
  76. X    $(CC) $(OBJECTS) -o philspell
  77. X
  78. Xmain.c: skiplist.h
  79. Xskiplist.c: skiplist.h
  80. X
  81. Xclean:
  82. X    /bin/rm -rf $(OBJECTS) philspell
  83. END_OF_FILE
  84. if test 321 -ne `wc -c <'Makefile'`; then
  85.     echo shar: \"'Makefile'\" unpacked with wrong size!
  86. fi
  87. # end of 'Makefile'
  88. fi
  89. if test -f 'README' -a "${1}" != "-c" ; then 
  90.   echo shar: Will not clobber existing file \"'README'\"
  91. else
  92. echo shar: Extracting \"'README'\" \(1350 characters\)
  93. sed "s/^X//" >'README' <<'END_OF_FILE'
  94. XFrom: phillip@soda.Berkeley.EDU (Phillip "Edward" Nunez)
  95. XSubject: philspell 1.0 source code
  96. XDate: 17 Jun 1992 21:18:13 GMT
  97. X
  98. XHi everybody!!  I was recently trying to proofread some of the short stories
  99. Xthat I write a lot and found it really hard to do under UNIX without
  100. Xspecialized software.  I mean, even if you use "spell" to check a document,
  101. Xyou then have to go through by hand and change all the misspelled words to
  102. Xbe correct, and then to be safe you have to run it through "spell" again to
  103. Xmake sure you didn't make any mistakes, and that's all a big pain!
  104. X
  105. XI will keep this awful lack of UNIX word versatility in mind when I write
  106. XPhilOS, but until then -- while we all still have to use UNIX or system V or
  107. XMS-DOS or something like that -- I have written this really cool new utility
  108. Xcalled "philspell".
  109. X
  110. XPHILSPELL uses a words file (default /usr/dict/words) and a lot of
  111. Xcomplicated English grammar heuristics to spell-check a file-- but it is
  112. Xeven better than that!  Because, as its output, PHILSPELL prints the
  113. Xoriginal document, but with all spelling *correct*!!!  This is a lot cooler
  114. Xthan the output of more kludgey programs like "spell".
  115. X
  116. XThe source code for PHILSPELL is here at the end of this post.  Oh yeah, you
  117. Xcan also get it via ftp from soda.berkeley.edu in ~ftp/pub/phillip.
  118. X
  119. XBye for now everyone!!!
  120. X
  121. X    Phillip "Edward" Nunez
  122. END_OF_FILE
  123. if test 1350 -ne `wc -c <'README'`; then
  124.     echo shar: \"'README'\" unpacked with wrong size!
  125. fi
  126. # end of 'README'
  127. fi
  128. if test -f 'main.c' -a "${1}" != "-c" ; then 
  129.   echo shar: Will not clobber existing file \"'main.c'\"
  130. else
  131. echo shar: Extracting \"'main.c'\" \(7509 characters\)
  132. sed "s/^X//" >'main.c' <<'END_OF_FILE'
  133. X/*
  134. X *
  135. X * main.c for "philspell"
  136. X *
  137. X * This file is Copyright (c) 1992 Phillip "Edward" Nunez.  Phillip grants
  138. X * you full permission to copy and distribute this code provided you do not
  139. X * interfere with any of the copyrights (c)s installed therein.
  140. X *
  141. X * Phillip grants permission to extract portions of this code for use in
  142. X * other code provided you give full credit to him in all documentation
  143. X * pertaining to your program, preserve copyrights in files from which code
  144. X * is extracted, and put his name in your program's output.
  145. X *
  146. X *
  147. X * This header automatically generated by the UNIX program philcopyright,
  148. X * Copyright (c) 1991 Phillip "Edward" Nunez.  For information regarding
  149. X * philcopyright, mail phillip@soda.berkeley.edu.
  150. X *
  151. X */
  152. X
  153. X#include <stdio.h>
  154. X#include <ctype.h>
  155. X
  156. X#include "skiplist.h"
  157. X
  158. Xstatic char philSCCSid[] = "@(#)main.c          1.0     Phillip `Edward' Nunez";
  159. X
  160. X#define DEFAULT_FILENAME "/usr/dict/words"
  161. X#define SKIPMAX 16
  162. X
  163. Xstatic char  scratchbuf[BUFSIZ];
  164. Xstatic char *philsProgramName;
  165. X
  166. Xstatic char *philExists = "Phillip \"Edward\" Nunez";
  167. X
  168. Xtypedef skipnode philSkipNode;
  169. Xtypedef skipnode philSkipList;
  170. X
  171. Xchar *suffixes[] = {
  172. X    "ive", /**/ "ion", "tion", "en", /**/ "ions", "ications", "ens", /**/
  173. X    "th", "ieth", /**/ "ly", /**/ "ing", /**/ "ings", /**/ "ed", /**/
  174. X    "est", /**/ "er", /**/ "ers", /**/ "ers", /**/ "s", "es", "ies", /**/
  175. X    "ness", "iness", /****/ "ment", "al", "ally", "able", "speak"
  176. X};
  177. Xunsigned int *suffix_lens;
  178. X
  179. Xchar *prefixes[] = {
  180. X    "non", "anti", "un", "in", "re", "en", "ex", "im", "de", "phil"
  181. X};
  182. Xunsigned int *prefix_lens;
  183. X
  184. Xchar *muties[] = {
  185. X    "able", "tion", "sion", "tion", "ing", "ily", "ed", "ier", "ly", "tions",
  186. X    "tions", "ies", "ied"
  187. X};
  188. Xchar *mutie_results[] = {
  189. X    "e",    "te",   "de",   "t",    "e",   "y",   "e",  "y",   "le", "tion",
  190. X    "te",   "y",    "y"
  191. X};
  192. Xunsigned int *mutie_lens;
  193. X
  194. X/*
  195. X * Someone actually had the nerve to tell me today that the "right" way to
  196. X * impelment all the lists of prefixes and suffixes and stuff was to use
  197. X * a backward-indexed trie with type/data records stored at the nodes.  I
  198. X * think that's really dumb because who wants to spell all their words
  199. X * backwards?
  200. X * 
  201. X * She said this part of the program was really pathetic because it was O(n).
  202. X * But I like O(N)-- N for Nunez!  That starts with N and that's next to O and
  203. X * that's next to P and that stands for "Pool" and that rhymes with "Cool!"
  204. X *
  205. X *                                                         -Phillip
  206. X */
  207. X
  208. X#define NUMSUFFIXES (sizeof(suffixes) / sizeof(char *))
  209. X#define NUMPREFIXES (sizeof(prefixes) / sizeof(char *))
  210. X#define NUMMUTIES   (sizeof(muties)   / sizeof(char *))
  211. X
  212. Xunsigned int funny = 0;
  213. X
  214. Xvoid philPerror(char *s) {
  215. X    fprintf(stderr, "Error in Phillip's program \"%s\":\n>\t%s\n",
  216. X                philsProgramName, s);
  217. X}
  218. X
  219. Xchar *philLowerizeAndStrdup(char *t) {
  220. X    unsigned int len = strlen(t);
  221. X    char *start, *s;
  222. X
  223. X    start = s = (char *)malloc(len + 1);
  224. X
  225. X    do *s++ = (isupper(*t) ? tolower(*t) : *t);
  226. X        while (*t++);
  227. X
  228. X    return start;
  229. X}
  230. X
  231. XphilSkipNode philLookupNoPrefix(char *word, philSkipList list) {
  232. X    philSkipNode n;
  233. X    unsigned int i, l, m;
  234. X    char newtrybuf[BUFSIZ];
  235. X
  236. X    n = skip_lookup(word, list, SKIPMAX, NULL);
  237. X
  238. X    if (!n) {
  239. X        i = 0;
  240. X    l = strlen(word);
  241. X    while (!n && (i < NUMSUFFIXES)) {
  242. X        if (l > (m = suffix_lens[i])) {
  243. X            if (strcasecmp(word + (l - m), suffixes[i]) == 0) {
  244. X            strncpy(newtrybuf, word, l - m);
  245. X            newtrybuf[l - m] = '\0';
  246. X            if (funny) printf("\nTrying suffix '%s':  %s -> %s\n",
  247. X                          suffixes[i], word, newtrybuf);
  248. X            n = skip_lookup(newtrybuf, list, SKIPMAX, NULL);
  249. X        }
  250. X        }
  251. X        i++;
  252. X    }
  253. X        if (!n) {
  254. X        i = 0;
  255. X        while (!n && (i < NUMMUTIES)) {
  256. X            if (l > (m = mutie_lens[i])) {
  257. X            if (strcasecmp(word + (l - m), muties[i]) == 0) {
  258. X                strncpy(newtrybuf, word, l - m);
  259. X                strcpy(newtrybuf + l - m, mutie_results[i]);
  260. X            if (funny) printf("\nTrying mutie '%s/%s': %s -> %s\n",
  261. X                      muties[i], mutie_results[i],
  262. X                      word, newtrybuf);
  263. X            n = skip_lookup(newtrybuf, list, SKIPMAX, NULL);
  264. X            }
  265. X        }
  266. X        i++;
  267. X        }
  268. X    }
  269. X    }
  270. X    return n;
  271. X}
  272. X
  273. Xvoid philSpellCheckWord(char *word, philSkipList list) {
  274. X    philSkipNode n;
  275. X    unsigned int i, l, m;
  276. X    char newtrybuf[BUFSIZ];
  277. X
  278. X    n = skip_lookup(word, list, SKIPMAX, NULL);
  279. X
  280. X    if (!n) {
  281. X        i = 0;
  282. X    l = strlen(word);
  283. X    while (!n && (i < NUMPREFIXES)) {
  284. X        if (l > (m = prefix_lens[i])) {
  285. X            if (strncasecmp(word, prefixes[i], m) == 0) {
  286. X            strcpy(newtrybuf, word + m);
  287. X            if (funny) printf("\nTrying prefix '%s':  %s -> %s\n",
  288. X                      prefixes[i], word, newtrybuf);
  289. X            n = philLookupNoPrefix(newtrybuf, list);
  290. X        }
  291. X        }
  292. X        i++;
  293. X    }
  294. X    if (!n) n = philLookupNoPrefix(word, list);
  295. X    }
  296. X    fprintf(stdout, "%s%s", word, n ? "" : " (sic)");
  297. X}
  298. X
  299. Xvoid philSpellCheck(philSkipList list) {
  300. X    char *res;
  301. X    char wordbuf[BUFSIZ], *s;
  302. X
  303. X    while (res = gets(scratchbuf)) {
  304. X    while (*res) {
  305. X        while (*res && !isalpha(*res)) fputc(*res++, stdout);
  306. X        s = wordbuf;
  307. X        while (isalpha(*res)) *s++ = *res++;
  308. X        *s = '\0';
  309. X        if (*wordbuf) philSpellCheckWord(wordbuf, list);
  310. X    }
  311. X    fputc('\n', stdout);
  312. X    }
  313. X}
  314. X
  315. Xvoid philLoadAndGo(FILE *f) {
  316. X    philSkipList s = skip_create(SKIPMAX);
  317. X    unsigned int i;
  318. X
  319. X    suffix_lens = (unsigned int *)malloc(NUMSUFFIXES * sizeof(char *));
  320. X    i = 0;
  321. X    while (i < NUMSUFFIXES) (suffix_lens[i] = strlen(suffixes[i])), i++;
  322. X
  323. X    prefix_lens = (unsigned int *)malloc(NUMPREFIXES * sizeof(char *));
  324. X    i = 0;
  325. X    while (i < NUMPREFIXES) (prefix_lens[i] = strlen(prefixes[i])), i++;
  326. X
  327. X    mutie_lens = (unsigned int *)malloc(NUMMUTIES * sizeof(char *));
  328. X    i = 0;
  329. X    while (i < NUMMUTIES) (mutie_lens[i] = strlen(muties[i])), i++;
  330. X
  331. X    while (fgets(scratchbuf, BUFSIZ, f)) {
  332. X        scratchbuf[strlen(scratchbuf) - 1] = '\0';
  333. X        skip_add(philLowerizeAndStrdup(scratchbuf), philExists, s, SKIPMAX);
  334. X    }
  335. X
  336. X    fclose(f);
  337. X
  338. X    philSpellCheck(s);
  339. X}
  340. X
  341. Xstatic char *filename = DEFAULT_FILENAME;
  342. X
  343. Xvoid philParseCLA(int argc, char *argv[]) {
  344. X    unsigned int n = 1;
  345. X    char *s;
  346. X
  347. X    while (n < argc) {
  348. X        s = argv[n];
  349. X    if (*s++ != '-') {
  350. X        sprintf(scratchbuf, "Argument #%d doesn't start with a dash.", n);
  351. X        philPerror(scratchbuf);
  352. X    } else if (*s == 'v') funny = 1;
  353. X      else if (*s == 'f') {
  354. X          n++;
  355. X          if (n == argc) philPerror("Missing filename for option f.");
  356. X          else filename = argv[n];
  357. X      } else {
  358. X          sprintf(scratchbuf, "Unknown option: %s.", s);
  359. X          philPerror(scratchbuf);
  360. X      }
  361. X    n++;
  362. X    }
  363. X}
  364. X
  365. Xvoid philMain(int argc, char *argv[]) {
  366. X    FILE *f;
  367. X
  368. X    philsProgramName = argv[0];
  369. X
  370. X    philParseCLA(argc, argv);
  371. X
  372. X    f = fopen(filename, "r");
  373. X    if (f == NULL) {
  374. X        sprintf(scratchbuf, "Unable to open file \"%s\".", filename);
  375. X        philPerror(scratchbuf);
  376. X    exit(1);
  377. X    }
  378. X
  379. X    philLoadAndGo(f);
  380. X    exit(0);
  381. X}
  382. X
  383. X
  384. Xvoid main(int argc, char *argv[]) {
  385. X                                        /*        
  386. X                                         *  This is just a hook to make the
  387. X                                         *  program work even on compilers not
  388. X                                         *  smart enough to make philMain()
  389. X                                         *  the entry procedure instead of
  390. X                     *  main(), when philMain() exists.
  391. X                                         *  [gcc requires this, for example.]
  392. X                                         *
  393. X                                         */
  394. X    philMain(argc, argv);
  395. X}
  396. END_OF_FILE
  397. if test 7509 -ne `wc -c <'main.c'`; then
  398.     echo shar: \"'main.c'\" unpacked with wrong size!
  399. fi
  400. # end of 'main.c'
  401. fi
  402. if test -f 'philspell.man' -a "${1}" != "-c" ; then 
  403.   echo shar: Will not clobber existing file \"'philspell.man'\"
  404. else
  405. echo shar: Extracting \"'philspell.man'\" \(1800 characters\)
  406. sed "s/^X//" >'philspell.man' <<'END_OF_FILE'
  407. X.\" philSCCSid: @(#)philspell.man    1.0    6/16/92
  408. X.TH philspell 1
  409. X.SH Name
  410. Xphilspell \- correct problematic spelling in text files
  411. X.SH Syntax
  412. X.B philspell
  413. X[\fB\-v\fR] [\fB\-f\fI file\fR\|] 
  414. X.SH Description
  415. X.NXR "philspell command"
  416. XThe
  417. X.PN philspell
  418. Xcommand collects words from the standard input
  419. Xand looks them up in a spelling list.
  420. XWords that are not on the spelling list and
  421. Xare not deriveable from words on the list
  422. X(by applying certain inflections, prefixes or suffixes)
  423. Xare corrected.
  424. XTo the standard output,
  425. X.PN philspell
  426. Xprints the original text with all misspelled words corrected.
  427. X.SH Options
  428. X.NXR "philspell command" "options"
  429. X.IP \fB\-v\fR 15
  430. XVerbose mode; causes
  431. X.B philspell
  432. Xto output a description of the actions it performs when attempting
  433. Xto convert the input words into dictionary-bound forms.  This output
  434. Xis printed to stderr.
  435. X.IP "\fB\-\|f\fI file\fR" 
  436. XSpecifys the file used for the spelling list; the default is
  437. X/usr/dict/words.  The list specified here must be in the same format.
  438. X.SH Restrictions
  439. X.NXR "philspell command" "restricted"
  440. XBecause of the intricate nature of the calculations performed,
  441. Xspelling correction can be a very CPU intensive process.  On slow
  442. Xmachines with long files or big dictionarys,
  443. X.PN philspell
  444. Xcan take a few minutes to run.
  445. X.PP
  446. XThe coverage of the spelling list (dictionary) is uneven;
  447. Xnew installations will probably wish to 
  448. Xmonitor the output for several months to gather
  449. Xlocal additions.
  450. X.PP
  451. XThe 
  452. X.PN philspell
  453. Xcommand works only with ASCII text
  454. Xfiles.
  455. X.SH Files
  456. X.ta 2.0i
  457. X\f(CW/usr/dict/words\fR    spelling list, default for \fB\-f
  458. X.SH AUTHOR
  459. X.NXR "philspell author"
  460. XPhillip "Edward" Nunez, phillip@soda.berkeley.edu.
  461. X.SH See Also
  462. Xphilcc(1), philshar(1), philsort(1), philtee(1), ppp(1), philbiff(1X),
  463. Xowlspeak(6), propagandaspeak(6), philsccs(1)
  464. END_OF_FILE
  465. if test 1800 -ne `wc -c <'philspell.man'`; then
  466.     echo shar: \"'philspell.man'\" unpacked with wrong size!
  467. fi
  468. # end of 'philspell.man'
  469. fi
  470. if test -f 'philspell.test' -a "${1}" != "-c" ; then 
  471.   echo shar: Will not clobber existing file \"'philspell.test'\"
  472. else
  473. echo shar: Extracting \"'philspell.test'\" \(477 characters\)
  474. sed "s/^X//" >'philspell.test' <<'END_OF_FILE'
  475. XYou know, you should submit the design of PHILTRAN to SIGPLAN.
  476. XLots of really *lame* programming language designs get published there,
  477. Xand I think this one's much cooler than the other ones.  You should really
  478. Xconsider this, because it will make it lots easier to get into graduate
  479. Xschool if you get a paper published before you apply! (REALLY!)  If
  480. Xyou're not sure as to how to submit a paper, ask Kathy to help you ---
  481. Xshe's really nice and I'm sure will be willing to help.
  482. END_OF_FILE
  483. if test 477 -ne `wc -c <'philspell.test'`; then
  484.     echo shar: \"'philspell.test'\" unpacked with wrong size!
  485. fi
  486. # end of 'philspell.test'
  487. fi
  488. if test -f 'skiplist.c' -a "${1}" != "-c" ; then 
  489.   echo shar: Will not clobber existing file \"'skiplist.c'\"
  490. else
  491. echo shar: Extracting \"'skiplist.c'\" \(3508 characters\)
  492. sed "s/^X//" >'skiplist.c' <<'END_OF_FILE'
  493. X/*
  494. X * Skiplist library COPYRIGHT (c) 1992, 1991, 1990, 1989, 1988, 1987 by
  495. X * Phillip "Edward" Nunez.  I wrote all this stuff and had it copyrighted
  496. X * and don't let anyone ever tell you any different!
  497. X *
  498. X */
  499. X
  500. X#include <stdio.h>
  501. X#include <assert.h>
  502. X
  503. X#include "skiplist.h"
  504. X
  505. X#define PROBABILITY 4
  506. X
  507. X/*
  508. X * The definition of PROBABILITY determines how many pointers per node an
  509. X * element of a skiplist has.  A PROBABILITY of 4 means each node will have
  510. X * (3/4)1 + (1/4)(3/4)2 + (1/4)(1/4)(3/4)3... ~~ 1.31 pointers per node.
  511. X * A PROBABILITY of 5 yields (4/5)1 + (1/5)(4/5)2... ~~ 1.24 p/node.
  512. X */
  513. X
  514. X#define RANDOM rand
  515. X
  516. X/*
  517. X * The RANDOM function you define here should be seeded in your main program.
  518. X */
  519. X/*
  520. X * skip_create creates the header node for a skiplist.  The pointer to this
  521. X * node is what you should use to refer to the skiplist.  The argument 'max'
  522. X * determines the maximum height of any node in the skiplist; the head is
  523. X * always this high.  Skiplists can store on the order of 2^n elements
  524. X * efficiently where n is that maximum height.
  525. X */
  526. X
  527. Xskipnode skip_create(int max) {
  528. X
  529. X    skipnode newnode;
  530. X    int i;
  531. X
  532. X    newnode = (skipnode)malloc(sizeof(struct skipnode) + sizeof(skipnode) * max);
  533. X    assert(newnode != NULL);
  534. X
  535. X    newnode->name = "";
  536. X    newnode->ptr = NULL;
  537. X
  538. X    for (i = 0; i <= max; i++) newnode->next[i] = newnode;
  539. X    return newnode;
  540. X}
  541. X
  542. X/*
  543. X * skip_add adds an item to the skiplist.  'name' is the name (key)
  544. X * to the data; 'ptr' is the data; level is the maximum level (the same
  545. X * as used in the call to skip_create) and 'node' is the skiplist you're
  546. X * looking things up in.
  547. X *
  548. X * The 'name' parameter must have been allocated with 'malloc' or somesimilar.
  549. X * It will be freed when the node disappears.
  550. X */
  551. X
  552. Xvoid skip_add(char *name, void *ptr, skipnode node, int level) {
  553. X
  554. X    skipnode newnode;
  555. X    int size, newlevel;
  556. X
  557. X    newlevel = 0;
  558. X    while (RANDOM() % PROBABILITY) newlevel++;
  559. X    if (newlevel > level) newlevel = level;
  560. X
  561. X        size = sizeof(struct skipnode) + sizeof(skipnode) * newlevel;
  562. X        newnode = (skipnode)malloc(size);
  563. X    newnode->name = name;
  564. X    newnode->ptr = ptr;
  565. X
  566. X    while (level >= 0) {
  567. X        while (strcasecmp(name, node->next[level]->name) < 0)
  568. X            node = node->next[level];
  569. X        if (level <= newlevel) {
  570. X            newnode->next[level] = node->next[level];
  571. X            node->next[level] = newnode;
  572. X        }
  573. X        level--;
  574. X    }
  575. X}
  576. X
  577. X/*
  578. X * skip_lookup: Given the name of the data, the skiplist, the
  579. X * max level, and the default to return if the data cannot be found,
  580. X * look up the data in the list.
  581. X */
  582. X
  583. Xvoid *skip_lookup(char *name, skipnode node, int level, void *def) {
  584. X        int d;
  585. X
  586. X        while (level >= 0) {
  587. X                while ((d = strcasecmp(name, node->next[level]->name)) < 0)
  588. X                        node = node->next[level];
  589. X                if (!d) return node->next[level]->ptr;
  590. X                level--;
  591. X        }
  592. X        return def;
  593. X}
  594. X
  595. X/*
  596. X * skip_remove: remove a skipnode from a the skiplist given.  'name'
  597. X * is the key, 'level' is the max level.
  598. X */
  599. X
  600. Xvoid skip_remove(char *name, skipnode node, int level) {
  601. X    int cmpsav;
  602. X    skipnode n;
  603. X
  604. X    while (level >= 0) {
  605. X        while ((cmpsav = strcasecmp(name, node->next[level]->name)) < 0)
  606. X            node = node->next[level];
  607. X        if (cmpsav == 0)
  608. X            n = node->next[level];
  609. X            node->next[level] = node->next[level]->next[level];
  610. X        level--;
  611. X    }
  612. X    free(n->name);
  613. X    free(n);
  614. X}
  615. X
  616. X/*
  617. X * skip_free: free an entire skiplist.
  618. X */
  619. X
  620. Xvoid skip_free(skipnode node) {
  621. X    skipnode m, n = node->next[0];
  622. X    while (n != node) {
  623. X        free(n->name);
  624. X        m = n->next[0];
  625. X        free(n);
  626. X        n = m;
  627. X    }
  628. X    free(node);
  629. X}
  630. END_OF_FILE
  631. if test 3508 -ne `wc -c <'skiplist.c'`; then
  632.     echo shar: \"'skiplist.c'\" unpacked with wrong size!
  633. fi
  634. # end of 'skiplist.c'
  635. fi
  636. if test -f 'skiplist.h' -a "${1}" != "-c" ; then 
  637.   echo shar: Will not clobber existing file \"'skiplist.h'\"
  638. else
  639. echo shar: Extracting \"'skiplist.h'\" \(363 characters\)
  640. sed "s/^X//" >'skiplist.h' <<'END_OF_FILE'
  641. Xtypedef struct skipnode {
  642. X        char *name;
  643. X        void *ptr;
  644. X        struct skipnode *next[1];
  645. X} *skipnode;
  646. X
  647. Xvoid skip_remove(char *name, skipnode node, int level);
  648. Xvoid skip_free(skipnode node);
  649. Xvoid *skip_lookup(char *name, skipnode node, int level, void *def);
  650. Xvoid skip_add(char *name, void *ptr, skipnode node, int level);
  651. Xskipnode skip_create(int max);
  652. END_OF_FILE
  653. if test 363 -ne `wc -c <'skiplist.h'`; then
  654.     echo shar: \"'skiplist.h'\" unpacked with wrong size!
  655. fi
  656. # end of 'skiplist.h'
  657. fi
  658. echo shar: End of archive 1 \(of 1\).
  659. cp /dev/null ark1isdone
  660. MISSING=""
  661. for I in 1 ; do
  662.     if test ! -f ark${I}isdone ; then
  663.     MISSING="${MISSING} ${I}"
  664.     fi
  665. done
  666. if test "${MISSING}" = "" ; then
  667.     echo You have the archive.
  668.     rm -f ark[1-9]isdone
  669. else
  670.     echo You still need to unpack the following archives:
  671.     echo "        " ${MISSING}
  672. fi
  673. ##  End of shell archive.
  674. exit 0
  675.