Blame hspell.c

Packit ca9683
/* Copyright (C) 2003-2017 Nadav Har'El and Dan Kenigsberg */
Packit ca9683
Packit ca9683
#include <stdio.h>
Packit ca9683
#include <sys/types.h>
Packit ca9683
#include <stdlib.h>
Packit ca9683
#include <assert.h>
Packit ca9683
#include <unistd.h>
Packit ca9683
#include <string.h>
Packit ca9683
Packit ca9683
#include "hash.h"
Packit ca9683
#include "hspell.h"
Packit ca9683
#ifdef USE_LINGINFO
Packit ca9683
#include "linginfo.h"
Packit ca9683
#endif
Packit ca9683
Packit ca9683
/* load_personal_dict tries to load ~/.hspell_words and ./hspell_words.
Packit ca9683
   Currently, they are read into a hash table, where each word in the
Packit ca9683
   file gets a non-zero value.
Packit ca9683
   Empty lines starting with # are ignored. Lines containing non-Hebrew
Packit ca9683
   characters aren't ignored, but they won't be tried as questioned words
Packit ca9683
   anyway.
Packit ca9683
Packit ca9683
   If a non-null int pointer is given as a second parameter, the pointed
Packit ca9683
   value is set to 1 if a personal dictionary was found in the current
Packit ca9683
   directory, or to 0 otherwise (it was found in the user's home directory,
Packit ca9683
   or none was found). This knowledge is useful when a modified personal
Packit ca9683
   wordlist is to be saved, and we want to know if to save it in the
Packit ca9683
   current directory, or home directory.
Packit ca9683
*/
Packit ca9683
static void
Packit ca9683
load_personal_dict(hspell_hash *personaldict, int *currentdir_dictfile)
Packit ca9683
{
Packit ca9683
	int i;
Packit ca9683
	hspell_hash_init(personaldict);
Packit ca9683
	if (currentdir_dictfile)
Packit ca9683
		*currentdir_dictfile = 0;
Packit ca9683
	for(i=0; i<=1; i++){
Packit ca9683
		char buf[512];
Packit ca9683
		FILE *fp;
Packit ca9683
		if(i==0){
Packit ca9683
			char *home = getenv("HOME");
Packit ca9683
			if(!home) continue;
Packit ca9683
			snprintf(buf, sizeof(buf),
Packit ca9683
				 "%s/.hspell_words", home);
Packit ca9683
		} else
Packit ca9683
			snprintf(buf, sizeof(buf), "./hspell_words");
Packit ca9683
		fp=fopen(buf, "r");
Packit ca9683
		if(!fp) continue;
Packit ca9683
		if (i == 1 && currentdir_dictfile)
Packit ca9683
			*currentdir_dictfile = 1;
Packit ca9683
		while(fgets(buf, sizeof(buf), fp)){
Packit ca9683
			int l=strlen(buf);
Packit ca9683
			if(buf[l-1]=='\n')
Packit ca9683
				buf[l-1]='\0';
Packit ca9683
			if(buf[0]!='#' && buf[0]!='\0')
Packit ca9683
				hspell_hash_incr_int(personaldict, buf);
Packit ca9683
		}
Packit ca9683
		fclose(fp);
Packit ca9683
	}
Packit ca9683
}
Packit ca9683
Packit ca9683
/* save_personal_dict() saves the personal dictionary to disk. It does this
Packit ca9683
   by appending the words in personaldict_new_words to the dictionary file
Packit ca9683
   (the one in the current directory, if that had been read, otherwise
Packit ca9683
   the one in the home directory)..
Packit ca9683
   Returns non-zero on success.
Packit ca9683
*/
Packit ca9683
static int
Packit ca9683
save_personal_dict(hspell_hash *personaldict,
Packit ca9683
		   hspell_hash *personaldict_new_words,
Packit ca9683
		   int currentdir_dictfile)
Packit ca9683
{
Packit ca9683
	FILE *fp;
Packit ca9683
	hspell_hash_keyvalue *new_words_array;
Packit ca9683
	int new_words_number, i;
Packit ca9683
	char dict_filename[512];
Packit ca9683
Packit ca9683
	char *home = getenv("HOME");
Packit ca9683
	if (currentdir_dictfile || !home)
Packit ca9683
		snprintf(dict_filename, sizeof(dict_filename),
Packit ca9683
			 "./hspell_words");
Packit ca9683
	else
Packit ca9683
		snprintf(dict_filename, sizeof(dict_filename),
Packit ca9683
			 "%s/.hspell_words", home);
Packit ca9683
Packit ca9683
	fp = fopen(dict_filename, "a");
Packit ca9683
	if (!fp)
Packit ca9683
		return 0; /* signal error */
Packit ca9683
Packit ca9683
	/* We append the new words to the file.
Packit ca9683
	   We also move them from personaldict_new_words to personaldict
Packit ca9683
	   so that subsequent calls to this function won't write them again
Packit ca9683
	   and again.
Packit ca9683
	*/
Packit ca9683
	/* NOTE: currently, we assume that the personal dictionary we
Packit ca9683
           originally read, or last wrote, is the current state of the
Packit ca9683
	   user's personal dictionary file. This may be wrong if several
Packit ca9683
	   hspell processes are running concurrently and adding words or the
Packit ca9683
	   user has been manually editing the file while hspell is running.
Packit ca9683
	   It might be safer, perhaps, to load the personal dictionary again
Packit ca9683
	   to see its really current state? In any case, the current
Packit ca9683
	   behavior isn't likely to cause any serious problems, just the
Packit ca9683
	   occasional words listed more than once, perhaps.
Packit ca9683
	*/
Packit ca9683
	new_words_array = hspell_hash_build_keyvalue_array(
Packit ca9683
		personaldict_new_words, &new_words_number);
Packit ca9683
	if (hspell_debug) {
Packit ca9683
		fprintf(stderr, "Saving %d words to %s\n",
Packit ca9683
				new_words_number, dict_filename);
Packit ca9683
	}
Packit ca9683
	for (i = 0; i < new_words_number; i++) {
Packit ca9683
		fprintf(fp, "%s\n", new_words_array[i].key);
Packit ca9683
		hspell_hash_incr_int(personaldict, new_words_array[i].key);
Packit ca9683
	}
Packit ca9683
	hspell_hash_free_keyvalue_array(personaldict_new_words,
Packit ca9683
			new_words_number, new_words_array);
Packit ca9683
Packit ca9683
	hspell_hash_destroy(personaldict_new_words);
Packit ca9683
	hspell_hash_init(personaldict_new_words);
Packit ca9683
Packit ca9683
	return (fclose(fp) == 0);
Packit ca9683
}
Packit ca9683
Packit ca9683
/* load_spelling_hints reads the spelling hints file (for the -n option).
Packit ca9683
   This is done in a somewhat ad-hoc manner.
Packit ca9683
*/
Packit ca9683
Packit ca9683
char *flathints;
Packit ca9683
int flathints_size;
Packit ca9683
void load_spelling_hints(hspell_hash *spellinghints) {
Packit ca9683
	FILE *fp;
Packit ca9683
	char s[1000];
Packit ca9683
	int len=0;
Packit ca9683
	int thishint=0;
Packit ca9683
Packit ca9683
	hspell_hash_init(spellinghints);
Packit ca9683
Packit ca9683
	flathints_size = 8192; /* initialize size (will grow as necessary) */
Packit ca9683
	flathints = (char *)malloc(flathints_size);
Packit ca9683
	/*flathints[0]=0;*/
Packit ca9683
Packit ca9683
	snprintf(s,sizeof(s),"gzip -dc '%s.hints'",
Packit ca9683
		 hspell_get_dictionary_path());
Packit ca9683
	fp = popen(s, "r");
Packit ca9683
	if(!fp) {
Packit ca9683
		fprintf(stderr,"Failed to open %s\n",s);
Packit ca9683
		return;
Packit ca9683
	}
Packit ca9683
	while(fgets(s, sizeof(s), fp)){
Packit ca9683
		int l=strlen(s);
Packit ca9683
		if(s[0]=='+') { /* this is a textual description line */
Packit ca9683
			if(!thishint){
Packit ca9683
				thishint=len;
Packit ca9683
			}
Packit ca9683
			/* reallocate the array, if no room */
Packit ca9683
			while(len+l >= flathints_size){
Packit ca9683
				flathints_size *= 2;
Packit ca9683
				flathints= (char *)
Packit ca9683
					realloc(flathints,flathints_size);
Packit ca9683
			}
Packit ca9683
			/* replace the '+' character by a space (this was
Packit ca9683
			   the way hints were printed in version 0.5, and
Packit ca9683
			   wee keep it for backward compatibility */
Packit ca9683
			s[0]=' ';
Packit ca9683
			/*strncpy(flathints+len, s, flathints_size-len);*/
Packit ca9683
			strcpy(flathints+len, s);
Packit ca9683
			len += l;
Packit ca9683
		} else if(s[0]=='\n'){ /* no more words for this hint */
Packit ca9683
			thishint = 0;
Packit ca9683
			len++;
Packit ca9683
		} else { /* another word for this hint */
Packit ca9683
			s[l-1]=0;
Packit ca9683
			hspell_hash_set_int(spellinghints, s, thishint);
Packit ca9683
		}
Packit ca9683
       }
Packit ca9683
       pclose(fp);
Packit ca9683
}
Packit ca9683
Packit ca9683
Packit ca9683
/* used for sorting later: */
Packit ca9683
static int
Packit ca9683
compare_key(const void *a, const void *b){
Packit ca9683
	register hspell_hash_keyvalue *aa = (hspell_hash_keyvalue *)a;
Packit ca9683
	register hspell_hash_keyvalue *bb = (hspell_hash_keyvalue *)b;
Packit ca9683
	return strcmp(aa->key, bb->key);
Packit ca9683
}
Packit ca9683
static int
Packit ca9683
compare_value_reverse(const void *a, const void *b){
Packit ca9683
	register hspell_hash_keyvalue *aa = (hspell_hash_keyvalue *)a;
Packit ca9683
	register hspell_hash_keyvalue *bb = (hspell_hash_keyvalue *)b;
Packit ca9683
	if(aa->value < bb->value)
Packit ca9683
		return 1;
Packit ca9683
	else if(aa->value > bb->value)
Packit ca9683
		return -1;
Packit ca9683
	else return 0;
Packit ca9683
}
Packit ca9683
Packit ca9683
static FILE *
Packit ca9683
next_file(int *argcp, char ***argvp)
Packit ca9683
{
Packit ca9683
	FILE *ret=0;
Packit ca9683
	if(*argcp<=0)
Packit ca9683
		return 0;
Packit ca9683
	while(*argcp && !ret){
Packit ca9683
		ret=fopen((*argvp)[0],"r");
Packit ca9683
		if(!ret)
Packit ca9683
			perror((*argvp)[0]);
Packit ca9683
		(*argvp)++;
Packit ca9683
		(*argcp)--;
Packit ca9683
	}
Packit ca9683
	return ret;
Packit ca9683
}
Packit ca9683
Packit ca9683
Packit ca9683
#define VERSION_IDENTIFICATION ("@(#) International Ispell Version 3.1.20 " \
Packit ca9683
			       "(but really Hspell/C %d.%d%s)\n")
Packit ca9683
Packit ca9683
Packit ca9683
/* ishebrew() checks for an intra-word Hebrew character. This includes the
Packit ca9683
   Hebrew alphabet and the niqqud characters. The 8-bit encoding that these
Packit ca9683
   characters may appear in is the "cp1255" encoding, Microsoft's extension
Packit ca9683
   to the iso-8859-8 standard (which did not contain niqqud). For the tables
Packit ca9683
   of these encodings, see
Packit ca9683
   http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1255.TXT
Packit ca9683
   http://www.unicode.org/Public/MAPPINGS/ISO8859/8859-8.TXT
Packit ca9683
 */
Packit ca9683
#define isniqqud(c) ((unsigned char)(c)>= 0xC0 && (unsigned char)(c) <= 0xD2 \
Packit ca9683
		     && (unsigned char)(c)!=0xCE && (unsigned char)(c)!=0xD0)
Packit ca9683
#define ishebrew(c) (((c)>=(int)(unsigned char)'א' && (c)<=(int)(unsigned char)'ת')||isniqqud(c))
Packit ca9683
Packit ca9683
static int uglyuglyflag = 0;
Packit ca9683
Packit ca9683
int notify_split(const char *w, const char *baseword, int preflen, int prefspec)
Packit ca9683
{
Packit ca9683
#ifdef USE_LINGINFO
Packit ca9683
	char *desc,*stem;
Packit ca9683
#endif
Packit ca9683
	if(preflen>0){
Packit ca9683
		printf("צירוף חוקי: %.*s+%s\n", preflen, w, baseword);
Packit ca9683
	} else if (!preflen){
Packit ca9683
		printf("מילה חוקית: %s\n",w);
Packit ca9683
	}
Packit ca9683
#ifdef USE_LINGINFO
Packit ca9683
	if (linginfo_lookup(baseword,&desc,&stem)) {
Packit ca9683
		int j;
Packit ca9683
		for (j=0; ;j++) {
Packit ca9683
			char buf[80];
Packit ca9683
			if (!linginfo_desc2text(buf, desc, j)) break;
Packit ca9683
			if (linginfo_desc2ps(desc, j) & prefspec) {
Packit ca9683
				printf("\t%s(%s%s)",linginfo_stem2text(stem,j),buf,uglyuglyflag ? ",##שגיאה##" : "");
Packit ca9683
				if (hspell_debug) printf("\t%d",linginfo_desc2ps(desc, j));
Packit ca9683
				printf("\n");
Packit ca9683
			}
Packit ca9683
		}
Packit ca9683
	}
Packit ca9683
#endif
Packit ca9683
	return 1;
Packit ca9683
}
Packit ca9683
Packit ca9683
int
Packit ca9683
main(int argc, char *argv[])
Packit ca9683
{
Packit ca9683
	struct dict_radix *dict;
Packit ca9683
#define MAXWORD 30
Packit ca9683
	char word[MAXWORD+1], *w;
Packit ca9683
	int wordlen=0, offset=0, wordstart;
Packit ca9683
	int c;
Packit ca9683
	int res;
Packit ca9683
	FILE *slavefp;
Packit ca9683
	int terse_mode=0;
Packit ca9683
	hspell_hash wrongwords;
Packit ca9683
	int preflen; /* used by -l */
Packit ca9683
	hspell_hash spellinghints;
Packit ca9683
Packit ca9683
	/* Following Ispell, we keep three lists of personal words to be
Packit ca9683
	   accepted: "personaldict" is the user's on-disk personal dictionary,
Packit ca9683
	   "personaldict_new_words" are words that the user asked to add to
Packit ca9683
	   the personal dictionary but which we haven't saved to disk yet,
Packit ca9683
	   and "sessiondict" are words that the user asked to accept during
Packit ca9683
	   this session, but not add to the on-disk personal dictionary.
Packit ca9683
	*/
Packit ca9683
	hspell_hash personaldict;
Packit ca9683
	hspell_hash personaldict_new_words;
Packit ca9683
	hspell_hash sessiondict;
Packit ca9683
	int currentdir_dictfile = 0;  /* file ./hspell_words exists? */
Packit ca9683
Packit ca9683
	/* command line options */
Packit ca9683
	char *progname=argv[0];
Packit ca9683
	int interpipe=0; /* pipe interface (ispell -a like) */
Packit ca9683
	int slave=0;  /* there's a slave ispell process (-i option) */
Packit ca9683
	int opt_s=0; /* -s option */
Packit ca9683
	int opt_c=0; /* -c option */
Packit ca9683
	int opt_l=0; /* -l option */
Packit ca9683
	int opt_v=0; /* -v option (show version and quit) */
Packit ca9683
	int opt_H=0; /* -H option (allow he ha-she'ela) */
Packit ca9683
	int opt_n=0; /* -n option (provide spelling hints) */
Packit ca9683
Packit ca9683
	/* TODO: when -a is not given, allow filename parameters, like
Packit ca9683
	   the "spell" command does. */
Packit ca9683
	FILE *in=stdin;
Packit ca9683
Packit ca9683
	/* Parse command-line options */
Packit ca9683
	while((c=getopt(argc, argv, "clnsviad:BmVhT:CSPp:w:W:HD:"))!=EOF){
Packit ca9683
		switch(c){
Packit ca9683
		case 'a':
Packit ca9683
			interpipe=1;
Packit ca9683
			break;
Packit ca9683
		case 'i':
Packit ca9683
			slave=1;
Packit ca9683
			break;
Packit ca9683
		/* The following options do something on ispell or aspell,
Packit ca9683
		   and some confused programs call hspell with them. We just
Packit ca9683
		   ignore them silently, hoping that all's going to be well...
Packit ca9683
		*/
Packit ca9683
		case 'd': case 'B': case 'm': case 'T': case 'C': case 'S':
Packit ca9683
		case 'P': case 'p': case 'w': case 'W':
Packit ca9683
			/*fprintf(stderr, "Warning: ispell options -d, -B and "
Packit ca9683
			  "-m are ignored by hspell.\n");*/
Packit ca9683
			break;
Packit ca9683
		case 's':
Packit ca9683
			opt_s=1;
Packit ca9683
			break;
Packit ca9683
		case 'c':
Packit ca9683
			opt_c=1;
Packit ca9683
			break;
Packit ca9683
		case 'l':
Packit ca9683
			opt_l=1;
Packit ca9683
			break;
Packit ca9683
		case 'H':
Packit ca9683
			/* Allow "he ha-she'ela" */
Packit ca9683
			opt_H=1;
Packit ca9683
			break;
Packit ca9683
		case 'n':
Packit ca9683
			opt_n=1;
Packit ca9683
			break;
Packit ca9683
		case 'v':
Packit ca9683
			opt_v++;
Packit ca9683
			break;
Packit ca9683
		case 'D':
Packit ca9683
			hspell_set_dictionary_path(optarg);
Packit ca9683
			break;
Packit ca9683
		case 'V':
Packit ca9683
			printf("Hspell %d.%d%s\nWritten by Nadav Har'El and "
Packit ca9683
			       "Dan Kenigsberg.\n\nCopyright (C) 2000-2017 "
Packit ca9683
			       "Nadav Har'El and Dan Kenigsberg.\nThis is "
Packit ca9683
			       "free software, released under the GNU Affero General "
Packit ca9683
			       "Public License\n(AGPL) version 3. See "
Packit ca9683
			       "http://hspell.ivrix.org.il/ for "
Packit ca9683
			       "more information.\n", HSPELL_VERSION_MAJOR,
Packit ca9683
			       HSPELL_VERSION_MINOR, HSPELL_VERSION_EXTRA);
Packit ca9683
			return 0;
Packit ca9683
		case 'h': case '?':
Packit ca9683
			fprintf(stderr,"hspell - Hebrew spellchecker\n"
Packit ca9683
				"Usage: %s [-acinslVH] [file ...]\n\n"
Packit ca9683
				"See hspell(1) manual for a description of "
Packit ca9683
				"hspell and its options.\nRun hspell -V for "
Packit ca9683
				"hspell's version and copyright.\n", progname);
Packit ca9683
			return 1;
Packit ca9683
		}
Packit ca9683
	}
Packit ca9683
	argc -= optind;
Packit ca9683
	argv += optind;
Packit ca9683
Packit ca9683
	/* The -v option causes ispell to print its current version
Packit ca9683
	   identification on the standard output and exit. If the switch is
Packit ca9683
	   doubled, ispell will also print the options that it was compiled
Packit ca9683
	   with.
Packit ca9683
	*/
Packit ca9683
	if(opt_v){
Packit ca9683
		printf(VERSION_IDENTIFICATION, HSPELL_VERSION_MAJOR,
Packit ca9683
		       HSPELL_VERSION_MINOR, HSPELL_VERSION_EXTRA);
Packit ca9683
		if (opt_v > 1) {
Packit ca9683
		    printf("Compiled-in options:\n");
Packit ca9683
		    printf("\tDICTFILE = \"%s\"\n", hspell_get_dictionary_path());
Packit ca9683
#ifdef USE_LINGINFO
Packit ca9683
		    printf("\tLINGINFO\n");
Packit ca9683
#endif
Packit ca9683
		}
Packit ca9683
		return 0;
Packit ca9683
	}
Packit ca9683
Packit ca9683
	/* If the program name ends with "-i", we enable the -i option.
Packit ca9683
	   This ugly hack is useful when a certain application can be given
Packit ca9683
	   a different spell-checker, but not extra options to pass to it */
Packit ca9683
	if(strlen(progname)>=2 && progname[strlen(progname)-2] == '-' &&
Packit ca9683
	   progname[strlen(progname)-1] == 'i'){
Packit ca9683
		slave=interpipe=1;
Packit ca9683
	}
Packit ca9683
Packit ca9683
	if(interpipe){
Packit ca9683
		/* for ispell -a like behavior, we want to flush every line: */
Packit ca9683
		setlinebuf(stdout);
Packit ca9683
	} else {
Packit ca9683
		/* No "-a" option: UNIX spell-like mode: */
Packit ca9683
Packit ca9683
		/* Set up hash-table for remembering the wrong words seen */
Packit ca9683
		hspell_hash_init(&wrongwords);
Packit ca9683
Packit ca9683
		/* If we have any more arguments, treat them as files to
Packit ca9683
		   spellcheck. Otherwise, just use stdin as set above.
Packit ca9683
		*/
Packit ca9683
		if(argc){
Packit ca9683
			in=next_file(&argc, &argv);
Packit ca9683
			if(!in)
Packit ca9683
				return 1; /* nothing to do, really... */
Packit ca9683
		}
Packit ca9683
	}
Packit ca9683
Packit ca9683
	if(hspell_init(&dict, (opt_H ? HSPELL_OPT_HE_SHEELA : 0) |
Packit ca9683
			      (opt_l ? HSPELL_OPT_LINGUISTICS : 0))<0){
Packit ca9683
		fprintf(stderr,"Sorry, could not read dictionary. Hspell "
Packit ca9683
			"was probably installed improperly.\n");
Packit ca9683
		return 1;
Packit ca9683
	}
Packit ca9683
	load_personal_dict(&personaldict, &currentdir_dictfile);
Packit ca9683
	hspell_hash_init(&personaldict_new_words);
Packit ca9683
	hspell_hash_init(&sessiondict);
Packit ca9683
Packit ca9683
	if(opt_n)
Packit ca9683
		load_spelling_hints(&spellinghints);
Packit ca9683
Packit ca9683
	if(interpipe){
Packit ca9683
		if(slave){
Packit ca9683
			/* We open a pipe to an "ispell -a" process, letting
Packit ca9683
			   it output directly to the user. We also let it
Packit ca9683
			   output its own version string instead of ours. Is
Packit ca9683
			   this wise? I don't know. Does anyone care?
Packit ca9683
			   Note that we also don't make any attempts to catch
Packit ca9683
			   broken pipes.
Packit ca9683
			*/
Packit ca9683
			slavefp=popen("ispell -a", "w");
Packit ca9683
			if(!slavefp){
Packit ca9683
				fprintf(stderr, "Warning: Cannot create slave "
Packit ca9683
				    "ispell process. Disabling -i option.\n");
Packit ca9683
				slave=0;
Packit ca9683
			} else {
Packit ca9683
				setlinebuf(slavefp);
Packit ca9683
			}
Packit ca9683
		}
Packit ca9683
		if(!slave)
Packit ca9683
			printf(VERSION_IDENTIFICATION, HSPELL_VERSION_MAJOR,
Packit ca9683
			       HSPELL_VERSION_MINOR, HSPELL_VERSION_EXTRA);
Packit ca9683
	}
Packit ca9683
Packit ca9683
	for(;;){
Packit ca9683
		c=getc(in);
Packit ca9683
		if(ishebrew(c) || c=='\'' || c=='"'){
Packit ca9683
			/* swallow up another letter into the word (if the word
Packit ca9683
			 * is too long, lose the last letters) */
Packit ca9683
			if(wordlen
Packit ca9683
				word[wordlen++]=c;
Packit ca9683
		} else if(wordlen){
Packit ca9683
			/* found word separator, after a non-empty word */
Packit ca9683
			word[wordlen]='\0';
Packit ca9683
			wordstart=offset-wordlen;
Packit ca9683
			/* TODO: convert two single quotes ('') into one
Packit ca9683
			 * double quote ("). For TeX junkies. */
Packit ca9683
Packit ca9683
			/* remove quotes from end or beginning of the word
Packit ca9683
			 * (we do leave, however, single quotes in the middle
Packit ca9683
			 * of the word - used to signify "j" sound in Hebrew,
Packit ca9683
			 * for example, and double quotes used to signify
Packit ca9683
			 * acronyms. A single quote at the end of the word is
Packit ca9683
			 * used to signify an abbreviation, or can be an actual
Packit ca9683
			 * quote (there is no difference in ASCII...), so we
Packit ca9683
			 * must check both possibilities. */
Packit ca9683
			w=word;
Packit ca9683
			if(*w=='"' || *w=='\''){
Packit ca9683
				w++; wordlen--; wordstart++;
Packit ca9683
			}
Packit ca9683
			if(w[wordlen-1]=='"'){
Packit ca9683
				w[wordlen-1]='\0'; wordlen--;
Packit ca9683
			}
Packit ca9683
			res=hspell_check_word(dict,w,&preflen);
Packit ca9683
			if(res!=1 && (res=hspell_is_canonic_gimatria(w))){
Packit ca9683
				if(hspell_debug)
Packit ca9683
					fprintf(stderr,"found canonic gimatria\n");
Packit ca9683
				if(opt_l){
Packit ca9683
					printf("גימטריה: %s=%d\n",w,res);
Packit ca9683
					preflen = -1; /* yes, I know it is bad programming, but I need to tell later printf not to print anything, and I hate to add a flag just for that. */
Packit ca9683
				}
Packit ca9683
				res=1;
Packit ca9683
			}
Packit ca9683
			if(res!=1 && w[wordlen-1]=='\''){
Packit ca9683
				/* try again, without the quote */
Packit ca9683
				w[wordlen-1]='\0'; wordlen--;
Packit ca9683
				res=hspell_check_word(dict,w,&preflen);
Packit ca9683
			}
Packit ca9683
			/* as last resort, try the user's personal word list */
Packit ca9683
			if(res!=1)
Packit ca9683
			   res = hspell_hash_exists(&personaldict, w)
Packit ca9683
			      || hspell_hash_exists(&personaldict_new_words, w)
Packit ca9683
			      || hspell_hash_exists(&sessiondict, w);
Packit ca9683
Packit ca9683
			if(res){
Packit ca9683
				if(hspell_debug)
Packit ca9683
					fprintf(stderr,"correct: %s\n",w);
Packit ca9683
				if(interpipe && !terse_mode)
Packit ca9683
					if(wordlen)
Packit ca9683
						printf("*\n");
Packit ca9683
				if(opt_l){
Packit ca9683
					hspell_enum_splits(dict,w,notify_split);
Packit ca9683
				}
Packit ca9683
			} else if(interpipe){
Packit ca9683
				/* Misspelling in -a mode: show suggested
Packit ca9683
				   corrections */
Packit ca9683
				struct corlist cl;
Packit ca9683
				int i;
Packit ca9683
				if(hspell_debug)
Packit ca9683
					fprintf(stderr,"misspelling: %s\n",w);
Packit ca9683
				corlist_init(&cl);
Packit ca9683
				hspell_trycorrect(dict, w, &cl);
Packit ca9683
				if(corlist_n(&cl))
Packit ca9683
					printf("& %s %d %d: ", w,
Packit ca9683
					       corlist_n(&cl), wordstart);
Packit ca9683
				else
Packit ca9683
					printf("# %s %d", w, wordstart);
Packit ca9683
				for(i=0;i
Packit ca9683
					printf("%s%s",
Packit ca9683
					       i ? ", " : "",
Packit ca9683
					       corlist_str(&cl,i));
Packit ca9683
				}
Packit ca9683
				printf("\n");
Packit ca9683
				corlist_free(&cl);
Packit ca9683
				if(opt_n){
Packit ca9683
					int index;
Packit ca9683
					if(hspell_hash_get_int(&spellinghints,
Packit ca9683
							       w, &index))
Packit ca9683
						printf("%s", flathints+index);
Packit ca9683
				}
Packit ca9683
			} else {
Packit ca9683
				/* Misspelling in "spell" mode: remember this
Packit ca9683
				   misspelling for later */
Packit ca9683
Packit ca9683
				if(hspell_debug)
Packit ca9683
					fprintf(stderr,"misspelling: %s\n",w);
Packit ca9683
				hspell_hash_incr_int(&wrongwords, w);
Packit ca9683
			}
Packit ca9683
			/* We treat the combination of the -l (linguistic
Packit ca9683
			   information) and -c (suggest corrections) option
Packit ca9683
			   as special. In that case we suggest "corrections"
Packit ca9683
			   to every word (regardless if they are in the
Packit ca9683
			   dictionary or not), and show the linguistic
Packit ca9683
			   information on all those words. This can be useful
Packit ca9683
			   for a reader application, which may also want to
Packit ca9683
			   be able to understand misspellings and their possible
Packit ca9683
			   meanings.
Packit ca9683
			*/
Packit ca9683
			if (opt_l && opt_c) {
Packit ca9683
				struct corlist cl;
Packit ca9683
				int i;
Packit ca9683
				if(hspell_debug)
Packit ca9683
					fprintf(stderr,"misspelling: %s\n",w);
Packit ca9683
				corlist_init(&cl);
Packit ca9683
				hspell_trycorrect(dict, w, &cl);
Packit ca9683
				uglyuglyflag = 1;
Packit ca9683
				for(i=0;i
Packit ca9683
					hspell_enum_splits(dict,corlist_str(&cl,i),notify_split);
Packit ca9683
				}
Packit ca9683
				uglyuglyflag = 0;
Packit ca9683
				corlist_free(&cl);
Packit ca9683
			}
Packit ca9683
			/* we're done with this word: */
Packit ca9683
			wordlen=0;
Packit ca9683
		} else if(interpipe &&
Packit ca9683
			  offset==0 && (c=='#' || c=='!' || c=='~' || c=='@' ||
Packit ca9683
					c=='%' || c=='-' || c=='+' || c=='&' ||
Packit ca9683
					c=='*')){
Packit ca9683
			/*
Packit ca9683
			   Summary of ispell's commands:
Packit ca9683
			   -----------------------------
Packit ca9683
			   ! - enter terse mode
Packit ca9683
			   % - exit terse mode
Packit ca9683
Packit ca9683
			   * <word> - add to personal dict
Packit ca9683
			   & <word> - ditto
Packit ca9683
			   @ <word> - accept, but leave out of dict
Packit ca9683
			   # - save personal dict
Packit ca9683
			*/
Packit ca9683
			char rest[512];
Packit ca9683
			int  isheb = 0;
Packit ca9683
Packit ca9683
			/* Read rest of line, to get the command parameters. */
Packit ca9683
			if(!fgets(rest, sizeof(rest), in)){
Packit ca9683
				rest[0]='\0'; /* unexpected EOF... */
Packit ca9683
			} else if (rest[0] && rest[strlen(rest)-1] == '\n') {
Packit ca9683
				rest[strlen(rest)-1] = '\0';
Packit ca9683
			} else {
Packit ca9683
				/* We shouldn't arrive here, but if we do:
Packit ca9683
				   Eat up rest of line. */
Packit ca9683
				int rc;
Packit ca9683
				while ((rc = getc(in)) != EOF && rc != '\n')
Packit ca9683
					;
Packit ca9683
			}
Packit ca9683
Packit ca9683
			switch (c) {
Packit ca9683
			case '!': terse_mode = 1; break;
Packit ca9683
			case '%': terse_mode = 0; break;
Packit ca9683
			case '*': case '&': case '@':
Packit ca9683
				isheb = ishebrew((int)(unsigned char)rest[0]);
Packit ca9683
				/* We don't handle non-Hebrew words */
Packit ca9683
				if (isheb) {
Packit ca9683
					if (c == '@') {
Packit ca9683
					/* Add word to the session dictionary,
Packit ca9683
					   which is never saved to disk. */
Packit ca9683
					  if (hspell_debug)
Packit ca9683
					    fprintf(stderr, "hspell_add_to_session(%s)\n", rest);
Packit ca9683
					  hspell_hash_incr_int(
Packit ca9683
					    &sessiondict, rest);
Packit ca9683
					} else {
Packit ca9683
					/* Add word to personaldict_new_words,
Packit ca9683
					   which is saved to disk when the '#'
Packit ca9683
					   command is issued. */
Packit ca9683
					   if (hspell_debug)
Packit ca9683
					     fprintf(stderr, "hspell_add_to_personal(%s)\n", rest);
Packit ca9683
					   if (!hspell_hash_exists(
Packit ca9683
					     &personaldict, rest) &&
Packit ca9683
					       !hspell_hash_exists(
Packit ca9683
					     &personaldict_new_words, rest)) {
Packit ca9683
					     hspell_hash_incr_int(
Packit ca9683
                                                &personaldict_new_words, rest);
Packit ca9683
					   }
Packit ca9683
					}
Packit ca9683
				}
Packit ca9683
				break;
Packit ca9683
			case '#':
Packit ca9683
				save_personal_dict(&personaldict,
Packit ca9683
						   &personaldict_new_words,
Packit ca9683
						   currentdir_dictfile);
Packit ca9683
				break;
Packit ca9683
			}
Packit ca9683
Packit ca9683
			/* Pass the command to ispell only if it
Packit ca9683
			   doesn't involve a Hebrew word. */
Packit ca9683
			if (slave && !isheb) {
Packit ca9683
				fprintf(slavefp, "%c%s\n", c, rest);
Packit ca9683
			}
Packit ca9683
			/* offset=0 remains but we don't want to output
Packit ca9683
			   a newline */
Packit ca9683
			continue;
Packit ca9683
		}
Packit ca9683
		if(c==EOF) {
Packit ca9683
			/* If we were in the middle of the line (no newline)
Packit ca9683
			   we nevertheless need to finish with the old line */
Packit ca9683
			if(offset){
Packit ca9683
				offset=0;
Packit ca9683
				if(interpipe && !slave)
Packit ca9683
					printf("\n");
Packit ca9683
			}
Packit ca9683
			/* in UNIX spell mode (!interpipe) we should read
Packit ca9683
			   all the files given in the command line...
Packit ca9683
			   Otherwise, an EOF is the end of this loop.
Packit ca9683
			*/
Packit ca9683
			if(!interpipe && argc>0){
Packit ca9683
				if(in!=stdin)
Packit ca9683
					fclose(in);
Packit ca9683
				in=next_file(&argc, &argv);
Packit ca9683
				if(!in)
Packit ca9683
					break;
Packit ca9683
			} else
Packit ca9683
				break;
Packit ca9683
		}
Packit ca9683
		if(c=='\n'){
Packit ca9683
			offset=0;
Packit ca9683
			if(interpipe && !slave)  /*slave already outputs a newline...*/
Packit ca9683
			printf("\n");
Packit ca9683
		} else {
Packit ca9683
			offset++;
Packit ca9683
		}
Packit ca9683
		/* pass the character also to the slave, replacing Hebrew
Packit ca9683
		   characters by spaces */
Packit ca9683
		if(interpipe && slave)
Packit ca9683
			putc(ishebrew(c) ? ' ' : c, slavefp);
Packit ca9683
	}
Packit ca9683
Packit ca9683
	/* in spell-like mode (!interpipe) - list the wrong words */
Packit ca9683
	if(!interpipe){
Packit ca9683
		hspell_hash_keyvalue *wrongwords_array;
Packit ca9683
		int wrongwords_number;
Packit ca9683
		wrongwords_array = hspell_hash_build_keyvalue_array(
Packit ca9683
			&wrongwords, &wrongwords_number);
Packit ca9683
Packit ca9683
		if(wrongwords_number){
Packit ca9683
			int i;
Packit ca9683
			if(opt_c)
Packit ca9683
				printf("שגיאות כתיב שנמצאו, ותיקוניהן "
Packit ca9683
				       "המומלצים:\n\n");
Packit ca9683
			else
Packit ca9683
				printf("שגיאות כתיב שנמצאו:\n\n");
Packit ca9683
Packit ca9683
			/* sort word list by key or value (depending on -s
Packit ca9683
			   option) */
Packit ca9683
			qsort(wrongwords_array, wrongwords_number,
Packit ca9683
			      sizeof(hspell_hash_keyvalue),
Packit ca9683
			      opt_s ? compare_value_reverse : compare_key);
Packit ca9683
Packit ca9683
			for(i=0; i
Packit ca9683
				if(opt_c){
Packit ca9683
					struct corlist cl;
Packit ca9683
					int j;
Packit ca9683
					printf("%d %s -> ",
Packit ca9683
					       (int)wrongwords_array[i].value,
Packit ca9683
					       wrongwords_array[i].key);
Packit ca9683
					corlist_init(&cl);
Packit ca9683
					hspell_trycorrect(dict,
Packit ca9683
					       wrongwords_array[i].key, &cl);
Packit ca9683
					for(j=0;j
Packit ca9683
						printf("%s%s",
Packit ca9683
						       j ? ", " : "",
Packit ca9683
						       corlist_str(&cl,j));
Packit ca9683
					}
Packit ca9683
					corlist_free(&cl);
Packit ca9683
					printf("\n");
Packit ca9683
				} else if(opt_s){
Packit ca9683
					printf("%d %s\n",
Packit ca9683
					       (int)wrongwords_array[i].value,
Packit ca9683
					       wrongwords_array[i].key);
Packit ca9683
				} else {
Packit ca9683
					printf("%s\n",wrongwords_array[i].key);
Packit ca9683
				}
Packit ca9683
				if(opt_n){
Packit ca9683
					int index;
Packit ca9683
					if(hspell_hash_get_int(&spellinghints,
Packit ca9683
					     wrongwords_array[i].key, &index))
Packit ca9683
						printf("%s", flathints+index);
Packit ca9683
				}
Packit ca9683
			}
Packit ca9683
		}
Packit ca9683
#if 0
Packit ca9683
		hspell_hash_free_keyvalue_array(&wrongwords, wrongwords_number,
Packit ca9683
						wrongwords_array);
Packit ca9683
#endif
Packit ca9683
	}
Packit ca9683
Packit ca9683
	return 0;
Packit ca9683
}