#include #include #include #include #include /* not available on UNIX PC #include */ #define GOTO(col,row) tputs(tgoto(CM,col,row),1,putchr) #define CLEARLINE tputs(CE,1,putchr) #define REVON tputs(SO,1,putchr) #define REVOFF tputs(SE,1,putchr) #define LINE 9 #define PROMPT 13 #define INSTR 11 #define ADDED 19 #define ALT 16 #define QUIT 2 #define NO 1 #define YES 0 #define INTR 3 #define MALLOC 4 #define QUITSV 5 #define GROPE "/usr/lbin/grope" #define BELL putchar('\007') #define BADWRDS 750 #define MAXALTS 28 /* words[*][0] will point to misspelled words. words[*][1] will point to entered corrections for words[*][0] */ char *words[BADWRDS][2]; int wordlen[BADWRDS]; char line[7][256],*malloc(),*prgname="vspell",*altwords[MAXALTS]; char *ldict,*tgoto(),*tgetstr(),entry[1024],caps[100],*getenv(),*area; char *CL, /* clear screen */ *SO, /* start highlight */ *SE, /* end highlight */ *CE, /* clear to end of line */ *AS, *AE, *CD, /* clear to end of display */ *CM; /* cursor motion */ char *term,*bufpt; FILE *fpdoc,*fpwrd,*fpldict,*fptty,*fpout; int dirtyalt=NO; int putchr(),first,last,wmid,numowrds,curpos,curwrd,change=NO,chkflag; int turnon(),turnoff(); struct termio termold,termnew; #ifdef DEBUG char debug1[100],debug2[100]; #endif main(argc,argv) int argc; char **argv; { register int i,j,ret,which; int lineno=1,fixret=1; int num_o_lines,intr(); char c; /* file being spell-checked */ if((fpdoc=fopen(argv[1],"r"))==NULL){ printf("%s: Can't open %s\n",prgname,argv[1]); exit(9); } /* misspelled words */ if((fpwrd=fopen(argv[2],"r"))==NULL){ printf("%s: Can't open %s\n",prgname,argv[2]); exit(9); } /* output file for corrected document */ if((fpout=fopen(argv[3],"w"))==NULL){ printf("%s: Can't open %s\n",prgname,argv[3]); exit(9); } chkflag=(*argv[4] == 'Y')?YES:NO; num_o_lines=atoi(argv[5]); ldict=getenv("LOCALDICT"); if(ldict==NULL){ printf("%s: LOCALDICT variable not set\n",prgname); exit(8); } if((fpldict=fopen(ldict,"a"))==NULL){ printf("%s: Can't open %s\n",prgname,ldict); exit(9); } if((fptty=fopen("/dev/tty","r+"))==NULL){ printf("%s: Can't open /dev/tty\n",prgname); exit(9); } setbuf(fptty,0); getrmcap(); /* get terminal caps */ getbadw(); /* get misspelled words */ setinit(); /* get initial window */ signal(SIGINT,intr); signal(SIGSEGV,intr); signal(SIGBUS,intr); signal(SIGIOT,intr); /* catch abort()'s */ turnoff(fileno(fptty)); /* turn off cannonical processing and echoing */ tputs(CL,1,putchr); GOTO(0,LINE); c='-'; for(i=1;i<=79;i++)putchar(c); GOTO(38,LINE-1);if(strlen(argv[1])>14)argv[1][14]='\0'; printf("Line Number: File: %s",argv[1]); GOTO(38,LINE+1); printf("Local Dict: %.30s",ldict); GOTO(0,INSTR); if(strcmp(SO,"[")==0){ /* no reverse video */ printf("a=Add to Dict c/C=Correct w/wo check \ i/I=Ignore/All s=Sgst Alt Q/q=Quit w/wo save"); } else{ /* we have reverse video */ REVON;putchar('a');REVOFF; printf("dd to dict "); /*REVON;putchar('c');REVOFF;putchar('/');REVON;putchar('C');REVOFF;*/ REVON;putchar('c');putchar('/');putchar('C');REVOFF; printf("orrect %s check ",chkflag==YES?"w/wo":"wo/w"); /*REVON;putchar('i');REVOFF;putchar('/');REVON;putchar('I');REVOFF;*/ REVON;putchar('i');putchar('/');putchar('I');REVOFF; printf("gnore/all "); REVON;putchar('s');REVOFF; printf("uggest alt "); /*REVON;putchar('Q');REVOFF;putchar('/');REVON;putchar('q');REVOFF;*/ REVON;putchar('Q');putchar('/');putchar('q');REVOFF; printf("uit w/wo save"); } /* Get next line number from fgrep */ /* while((ret=fscanf(stdin,"%d",&lineno)) != -1 && fixret){ */ while(lineno++ <= num_o_lines && fixret){ if(ret==0){ printf("fscanf returned 0\n"); abort(); } getlset(lineno); /* get a line set (i.e., window) */ which=0; /* "first search" flag */ /* 2nd arg==1 => just find word */ if(highword(which,1)==0)continue; while(showlset(which) && fixret){ /* correct errors in window */ fixret=fixit(); /* returns 0 on 'quit' */ which=1; } } /* clean up and go home */ /* flush remaining document */ if(fixret || change==QUITSV){ for(j=0;j<=6;j++)if(*line[j])fputs(line[j],fpout); while(fgets(line[0],256,fpdoc)!=NULL)fputs(line[0],fpout); } wrapup(); } wrapup() { fclose(fpdoc);fclose(fpwrd);fclose(fpldict),fclose(fpout); turnon(fileno(fptty)); tputs(CL,1,putchr); GOTO(0,0); switch(change){ case NO: printf("Normal completion.\n"); printf("No corrections were made.\n"); exit(0); case YES: printf("Normal completion.\n"); exit(1); case QUIT: printf("%s terminated via 'quit'.\n",prgname); exit(0); case QUITSV: printf("%s terminated via 'Quit'.\n",prgname); exit(1); case INTR: printf("%s terminated via interrupt.\n",prgname); exit(0); case MALLOC: printf("%s terminated due to insufficient memory.\n",prgname); exit(1); } } getbadw() { register int i=0,j; char temp[256]; bufpt=malloc(15000); /* buffer for all misspelled words */ if(bufpt==NULL){change=MALLOC;wrapup();} while( (fgets(temp,256,fpwrd) != NULL) && (i find and highlight word */ ret=highword(which,0); if(ret)continue; } CLEARLINE; printf("%s",line[i]); } } else{ /* next word in same window */ GOTO(0,wmid+1); ret=highword(which,0); /* if(ret)printf("%s",line[wmid]); */ } return(ret); /* ret=1 means found the word ret=0 means found no word */ } highword(which,testflag) /* highlight word */ int which; /* which=0 for 1st search on line[wmid] */ int testflag; /* =1 just find word, =0 find and highlight */ { /* static int curword,curpos; */ register int i,strtpos,j,len; char temp[256],*p,c; p=line[wmid]; len=strlen(p); i=which?curwrd:0; strtpos=which?curpos+1:0; for( ; i<=numowrds;i++){ if(*words[i][0]=='\0')continue; j=index(p,words[i][0],strtpos); if(j == -1){strtpos=0;continue;} /* found string - is it a 'word'? */ curpos=j;curwrd=i; if(j!=0 && isalpha(p[j-1])) continue; /* j=strlen(words[i][0])+j; */ j += wordlen[i]; if(j!=len && isalpha(p[j]))continue; /* we've found an errant word */ if(testflag)return(1); /* if just finding, return */ c=p[curpos]; p[curpos]='\0'; /* strcpy(temp,p); strcat(temp,SO);strcat(temp,words[curwrd]);strcat(temp,SE); strcat(temp,&p[j]); strcpy(p,temp); */ /* instead of modifying line, just print line with word highlighted */ CLEARLINE; printf("%s",p); p[curpos]=c; tputs(SO,1,putchr); printf("%s",words[curwrd][0]); tputs(SE,1,putchr); printf("%s",&p[j]); return(1); } /* if we get here we can't find a bad word */ return(curpos=curwrd=0); } index(s1,s2,p) /* find 1st occurrence of s2 in s1 starting at p in s1 */ register char *s1,*s2; register p; { /* old version register i,j,k; for(i=p;s1[i] != '\0'; i++){ for(j=i,k=0;s2[k]!='\0' && s1[j]==s2[k];j++,k++) ; if(s2[k]=='\0') return(i); } return(-1); */ register char *p1,*s11,*s22; for(p1=s1+p;*p1;p1++){ for(s11=p1,s22=s2;*s22 && *s11 == *s22;s11++,s22++) ; if( !(*s22) )return(p1-s1); } return(-1); } #ifdef DEBUG diag(s1,s2) char *s1,*s2; { GOTO(0,20); CLEARLINE; printf("%s",s1); CLEARLINE; printf("%s",s2); getc(fptty); } #endif fixit() { register ans; register int num_alts; register int savans,i; int j; char newword[100],temp[256]; resp1: GOTO(0,PROMPT); CLEARLINE; GOTO(25,PROMPT);printf("(Press "); REVON;putchar('?');REVOFF;printf(" for help)"); GOTO(0,PROMPT);printf("Action: "); resp: ans=getc(fptty); CLEARLINE; if(dirtyalt!=NO){clearalt();GOTO(8,PROMPT);} switch(savans=ans){ case 'I': /* ignore all */ printf("Ignore all"); *words[curwrd][0]='\0'; break; case 'i': /* ignore just this occurrence */ case ' ': printf("Ignore this instance"); break; case 'A': /* add to dictionary */ case 'a': printf("Add to local dictionary"); fprintf(fpldict,"%s\n",words[curwrd][0]); GOTO(0,ADDED); dirtyalt=ADDED; printf("'%s' added to local dictionary" ,words[curwrd][0]); *words[curwrd][0]='\0'; break; case 'C': /* correct word */ case 'c': printf("Correct misspelling"); getnwrd: /* see if we already have a correction */ if(words[curwrd][1]!=NULL){ GOTO(0,PROMPT+1); CLEARLINE; tputs(SO,1,putchr); printf(words[curwrd][1]); tputs(SE,1,putchr); printf(" was previously entered as the correction."); printf("\nDo you want this used here? (y/n) "); while((ans=tolower(getc(fptty)))!='n' && ans!='y')BELL; GOTO(0,PROMPT+2); CLEARLINE; if(ans=='y'){ strcpy(newword,words[curwrd][1]); GOTO(0,PROMPT+1); CLEARLINE; goto usenew; } } GOTO(0,PROMPT+1); CLEARLINE; printf("Enter correction: "); turnon(fileno(fptty)); fgets(newword,100,fptty); newword[strlen(newword)-1]='\0'; if(*newword=='\0'){ BELL; GOTO(0,PROMPT+1); CLEARLINE; turnoff(fileno(fptty)); goto resp1; } if(checkit(savans,newword)){ GOTO(0,PROMPT+2); printf("spell(1) does not recognize "); tputs(SO,1,putchr); printf("%s",newword); tputs(SE,1,putchr); printf(".\n"); printf("Do you still want to use this word? (y/n) "); turnoff(fileno(fptty)); while((ans=tolower(getc(fptty)))!='n' && ans!='y')BELL; turnon(fileno(fptty)); GOTO(0,PROMPT+2); CLEARLINE; GOTO(0,PROMPT+3); CLEARLINE; if(ans=='n')goto getnwrd; } else{ /* erase the 'Checking...' message */ GOTO(0,PROMPT+2); CLEARLINE; } /* erase the 'ENTER new word' prompt */ GOTO(0,PROMPT+1); CLEARLINE; turnoff(fileno(fptty)); usenew: line[wmid][curpos]='\0'; strcpy(temp, &(line[wmid][curpos+strlen(words[curwrd][0])])); strcat(line[wmid],newword); strcat(line[wmid],temp); change=YES; /* remember this correction */ if(words[curwrd][1]==NULL){ words[curwrd][1]=malloc(strlen(newword)); if(words[curwrd][1]==NULL){ change=MALLOC;wrapup(); } strcpy(words[curwrd][1],newword); } break; case 's': /* find alternatives */ printf("Suggest alternatives"); GOTO(0,ALT-1);dirtyalt=YES; printf("\nWorking..."); CLEARLINE; if((num_alts=showalts(words[curwrd][0]))==0){ BELL; GOTO(0,ALT); printf("Sorry, no alternatives found."); goto resp1; /* ask what to do next */ } altresp: GOTO(0,ALT);dirtyalt=YES; printf("Enter no. of alternative you want "); printf("to use (Just to use none): "); CLEARLINE; turnon(fileno(fptty)); i = -999; j=fscanf(fptty,"%[^\n]%*c",temp); turnoff(fileno(fptty)); i=atoi(temp); if(j!=1){fgetc(fptty);i= 0;} if(i==0){clearalt();goto resp1;} if(i<0 || i>num_alts){BELL;goto altresp;} clearalt(); strcpy(newword,altwords[i]); goto usenew; case 'q': /* quit */ printf("Quit (No save)"); change=QUIT; return(0); case 'Q': /* quit */ printf("Quit (Save work)"); change=(change==YES)?QUITSV:QUIT; return(0); case '?': /* help */ clearhelp(); printhelp(); clearhelp(); goto resp1; default: BELL; goto resp1; } GOTO(0,wmid+1); CLEARLINE; printf("%s",line[wmid]); return(1); } #define TOSPELL fd[1] #define FROMSPELL ffd[0] #define TOVSPELL ffd[1] #define FROMVSPELL fd[0] checkit(cmd,word) char cmd,*word; { int i,ffd[2],fd[2]; char temp[100]; if(chkflag==NO && cmd=='c')return(0); if(chkflag==YES && cmd=='C')return(0); GOTO(0,PROMPT+2); printf("Checking ...\n"); pipe(fd); pipe(ffd); if(fork()==0){ close(0); /* close stdin */ dup(FROMVSPELL); close(FROMVSPELL); close(1); /* close stdout */ dup(TOVSPELL); close(TOVSPELL); /* child now attached to pipe */ close(FROMSPELL); close(TOSPELL); execlp("spell","spell",0); perror("exec failed"); exit(0); } close(TOVSPELL);close(FROMVSPELL); strcpy(temp,word); strcat(temp,"\n"); write(TOSPELL,temp,strlen(temp)); close(TOSPELL); i=read(FROMSPELL,temp,100); if(i == -1){GOTO(0,PROMPT+5);perror(prgname);} /* printf("i=%d\n",i); printf("temp=%s\n",temp); */ close(FROMSPELL); wait((int *)0); /* clear zombie */ return(i); } clearalt() { register int i; if(dirtyalt==ADDED){GOTO(0,ADDED);CLEARLINE;} else{ if(CD){GOTO(0,ALT);tputs(CD,1,putchr);} else{ for(i=ALT;i<=24;i++){ GOTO(0,i); CLEARLINE; } } } dirtyalt=NO; } clearhelp() { register int i; if(CD){GOTO(0,PROMPT);tputs(CD,1,putchr);} else{ for(i=PROMPT;i<=24;i++){ GOTO(0,i); CLEARLINE; } } } char *help[]={ " The word that is highlighted above is considered by vspell as misspelled.\n", "You are now being asked to specify its disposition by entering a vspell\n", "command. Vspell commands are all single characters. Here is a brief \n", "description of some of them,\n", " a -- This command adds the highlighted word to your local dictionary\n", " c -- This command allows you to correct the highlighted word\n", " by entering its replacement\n", " i -- This command tells vspell that the highlighted word is\n", " correct and needs no correction\n", " q -- This commands aborts vspell\n", "See the documentation for more details. Press to continue... ", 0}; printhelp() { register int i; i=0; while(help[i])printf(help[i++]); getc(fptty); } #define FROMGROPE ffd[0] #define TOVSPELL ffd[1] showalts(word) char *word; { /* showalts will 'grope' the word and present the alternatives found on lines 18 through 24, 4 per line (max of MAXALTS alterna- tives). The alternatives are also stored in the array altwords[] for possible future replacement if selected. */ register i,cnt=1; int ffd[2]; FILE *fp; char temp[100],*t; pipe(ffd); if(fork()==0){ close(1); /* close stdout */ dup(TOVSPELL); close(TOVSPELL); /* child's stdout now attached to pipe to vspell */ execlp("sh","sh",GROPE,word,0); perror("exec failed"); exit(0); } close(TOVSPELL); fp=fdopen(FROMGROPE,"r"); GOTO(0,ALT+2); while((t=fgets(temp,100,fp)) && t!=NULL && cnt<=MAXALTS){ temp[i=(strlen(temp)-1)]='\0'; /* disgard newline */ if((altwords[cnt]=malloc(i))==NULL){ change=MALLOC; wrapup(); } strcpy(altwords[cnt],temp); printf("%2d:%-16.16s",cnt,temp); if(cnt++ % 4 == 0)putchar('\n'); } fclose(fp); wait((int *)0); return(cnt-1); /* return no. of alternatives found */ } /* * turnoff, turnon -- Routines to turn off and turn on canonical * input processing and echoing to a terminal. * Old terminal settings are saved in a static * structure for reinstatement. */ turnoff(fd) int fd; { if (isatty(fd)) { ioctl (fd, TCGETA, &termold); termnew = termold; termnew.c_cc[VMIN] = 1; termnew.c_cc[VTIME] = 0; termnew.c_lflag &= ~(ICANON | ECHO); ioctl (fd, TCSETA, &termnew); } } turnon(fd) int fd; { if (isatty(fd)) ioctl (fd, TCSETA, &termold); }