/* * (c) Copyright David Cusimano, 1989 * * Program: spell * Usage: spell [-q] textfile [dictionary] * Purpose: Display a sorted list of words from textfile that * are not in the dictionary. The default filename * for the dictionary is "c:\words". The dictionary * is a list of words that have been sorted * alphabetically by a case-insensitive sort. That * is, "APPLE" appears before "orange". The program * spellsrt.exe performs a case-insensitive sort. * Version: 1.00 * Compiler: MANX C * Author: David Cusimano * Date Created: May 28, 1989 * Date Revised: September 3, 1989 */ #include #include #define NOTICE "SPELL v1.00, (C)1989 David Cusimano" #define LENWORD 32 /* maximum words length */ #define DICTIONARY "c:\\words" /* dictionary filename */ #define TRUE 1 #define FALSE 0 struct word_t { char *word; struct word_t *left; struct word_t *right; }; unsigned int numwords; unsigned int badwords; /* * Read words from a text file, sort the words, compare them to * the words in the dictionary file, and display those words that * do not appear in the dictionary. */ main(argc, argv) int argc; char *argv[]; { FILE *fpdata; FILE *fpdict; struct word_t *root; int quiet; struct word_t *readfile(); FILE *openfile(); chkusage(argc); quiet = FALSE; argc--; argv++; while (argc > 0 && argv[0][0] == '-') { switch (argv[0][1]) { case 'q': case 'Q': quiet = TRUE; break; default: fputs("unknown option\n", stderr); showusage(); break; } argc--; argv++; } if (argc == 0) showusage(); fpdata = openfile(argv[0]); fpdict = openfile(argc >= 2 ? argv[1] : DICTIONARY); if (!quiet) fputs("Reading", stderr); numwords = 0; root = readfile(fpdata); fclose(fpdata); if (root != NULL) { if (!quiet) fprintf(stderr, ", checking %u words\n", numwords); badwords = 0; cmpdict(fpdict, root); fclose(fpdict); if (!quiet) fprintf(stderr, "%u misspellings.\n", badwords); } exit(0); } /* * Check and display program usage. */ chkusage(argc) int argc; { if (argc < 2 || argc > 4) showusage(); } showusage() { fputs(NOTICE, stderr); fputs("\nusage: spell [-q] textfile [dictionary]\n", stderr); exit(1); } /* * Open specified file for read-only mode. If the file cannot be * opened, an error message is displayed and the program halts. */ FILE * openfile(name) char *name; { register FILE *fp; FILE *fopen(); if ((fp = fopen(name, "r")) == NULL) { fputs(name, stderr); fputs(": can't open file\n", stderr); exit(1); } return (fp); } /* * Compare two strings as strcmp() would except ignore the case * of the two strings. */ strlcmp(s, t) register char *s; register char *t; { for ( ; tolower(*s) == tolower(*t); s++, t++) if (*s == '\0') return(0); return (tolower(*s) - tolower(*t)); } /* * Read words from the specified file, allocate memory for them, * and save pointers to the start of the words in an array. */ struct word_t * readfile(fp) FILE *fp; { char bufr[LENWORD]; register int len; register struct word_t *root; struct word_t *insrtword(); root = NULL; while ((len = getword(fp, bufr, LENWORD)) != EOF) if (len != 0) root = insrtword(root, bufr); return (root); } /* * Insert a word into a binary tree of words. */ struct word_t * insrtword(node, word) struct word_t *node; char *word; { int cond; extern unsigned int numwords; struct word_t *walloc(); char *strsave(); if (node == NULL) { node = walloc(); node->word = strsave(word); node->left = node->right = NULL; numwords++; } else if ((cond = strlcmp(word, node->word)) == 0) ; else if (cond < 0) node->left = insrtword(node->left, word); else node->right = insrtword(node->right, word); return (node); } /* * Allocate memory for a word. */ struct word_t * walloc() { register struct word_t *mem; char *malloc(); mem = (struct word_t *) malloc(sizeof(struct word_t)); if (mem == NULL) { fputs("\ncan't allocate memory\n", stderr); exit(1); } else return (mem); } /* * Save a string in memory by allocating storage for it and * copying it to the newly allocated memory. */ char * strsave(str) register char *str; { register char *mem; char *malloc(); mem = malloc(strlen(str) + 1); if (mem == NULL) { fputs("\ncan't allocate memory\n", stderr); exit(1); } else strcpy(mem, str); return (mem); } /* * Read a word from the specified file. A word is delimited by any * non-alphabetic character which include numerals and punctuation. * The returned word contains only alphabetics. The length of the * word read is returned. */ getword(fp, bufr, max) FILE *fp; char *bufr; int max; { register int ch; register int len; len = 0; while (1) { ch = getc(fp); if (ch == EOF) { if (len == 0) return(EOF); else { bufr[len] = '\0'; return (len); } } else if (!isalpha(ch) || iscntrl(ch)) { bufr[len] = '\0'; return (len); } else { bufr[len++] = ch; if (len >= max) { bufr[max - 1] = '\0'; return (max - 1); } } } } /* * Compare a list of words with the specified dictionary and display * any word that is not in the dictionary. This comparison assumes * that both the words and the dictionary are sorted. */ cmpdict(fpdict, node) FILE *fpdict; struct word_t *node; { static char dict[LENWORD] = { '\0' }; int cond; extern unsigned int badwords; if (node->left) cmpdict(fpdict, node->left); if (dict[0] == '\0') getdict(dict, sizeof(dict), fpdict); while ((cond = strlcmp(node->word, dict)) > 0) getdict(dict, sizeof(dict), fpdict); if (cond < 0) { puts(node->word); badwords++; } else getdict(dict, sizeof(dict), fpdict); if (node->right) cmpdict(fpdict, node->right); } /* * Get string from file as fgets() would except remove newline * character from string. */ getdict(bufr, size, fp) register char *bufr; int size; FILE *fp; { register int len; char *fgets(); if (fgets(bufr, size, fp) == NULL) { bufr[0] = 255; bufr[1] = '\0'; } else { len = strlen(bufr); if (len != 0 && bufr[len - 1] == '\n') bufr[len - 1] = '\0'; } }