home *** CD-ROM | disk | FTP | other *** search
- /* This file is CC.CC */
- #include "em.h"
- //#include <stdio.h>
- //FILE*debug;
- //#define DB 4
- /*-----*/
- #ifdef DB
- static int depth(){long j,i;for(i=long(&i+2),j=0;i;i=*((long*)i),j++);return j;}
- static void In(){int i=depth(),j; for(j=1;j<i;j++) putc(' ',debug);}
- #endif
- /*----- move M forwards 1, but skip certain char sequences; stop at whoa */
- int rightC(mark&M,mark whoa){enum{endcomment=1,instring,incomment};
- line*R=M.r; char*S=R->s; int C=M.c,z=0, n=R==whoa.r?(whoa.c<?R->n):R->n;
- char A=C<n?S[C]:LF, B=C<n-1?S[C+1]:LF;
- if(A=='/') if(B=='*') {C+=2; z=incomment; /* skip / * */
- Z: if(C<n-1) if(S[C]=='*') if(S[C+1]=='/') {C+=2; z=0; goto E;}
- if(C>=n) {if(R==whoa.r) goto E; /* skip * / */
- C=0; if(!(R=R->next)) goto E; S=R->s; n=R==whoa.r?whoa.c:R->n;}
- else ++C; goto Z;}
- /* if(A=='/') if(B=='/') {C=n; goto E;} */ /* C++ // comment, skip to eol */
- if(A=='\'') {if(++C>=n) goto E; /* character value */
- if(S[C++]=='\\') {if(C>=n) goto E; /* \ found */
- if(!((S[C]-'0')&~7)) { /* \nnn */
- if(++C<n) if(!((S[C]-'0')&~7)) if(++C<n) if(!((S[C]-'0')&~7)) C++;}
- else if(C<n) C++;}
- if(C<n) if(S[C]=='\'') C++; goto E;}
- if(A=='"') {C++; z=instring;
- X: if((A=C<n?S[C]:LF)=='"') {C++; z=0; goto E;} /* string */
- if(C>=n) {if(R==whoa.r) goto E; /* M.r=0 if runs off file */
- C=0; if(!(R=R->next)) goto E; S=R->s; n=R==whoa.r?whoa.c:R->n;}
- else C+=(A=='\\')?2:1; goto X;} /* in string, skip \ and char */
- if(A=='*') if(B=='/') {C+=2; z=endcomment; goto E;} /* skip * / */
- if(C<n) C++; else {if(R==whoa.r) goto E;
- C=0; if(!(R=R->next)) goto E; /* S=R->s; */ n=R==whoa.r?whoa.c:R->n;}
- E: M.c=C<?n; M.r=R; return z;} /* = whether now in string or comment */
- /*----- move mark 1 char *//* if runs off file, leaves this->r==0 */
- /* void mark::operator++(){if(++c>r->n) {c=0; r=r->next;}} */
- /* void mark::operator--(){if(--c<0) if(r=r->prev) c=r->n; else c=0;} */
- /*----- check C bracket matching in region R */
- val bracketsC(const region&R){enum{endcomment=1,instring,incomment};
- mark Q; static char *w,c,b[64],*X="([{}])"; int i,j=0,k=0,n=0;
- for(Q=R.beg;!Q.r?0:Q!=R.end;j=rightC(Q,R.end)) {
- if(!k) if(j==endcomment) {k=2; b[0]='*'; b[1]='/'; n=2;}
- c=*Q; n<?=63;
- if(w=index(X,c)) if(i=w-X,!n?0:i<3?0:b[n-1]+i==5) n--; else b[n++]=i;}
- for(i=k;i<n;i++) b[i]=X[b[i]];
- if(n>63?0:j==instring) b[n++]='"';
- else if(n>62?0:j==incomment) {b[n++]='/'; b[n++]='*';}
- b[n]=0; return val(b,n);}
- /*-----*/
- KF(cbrackets) {val b=bracketsC(B->Mark(N.i)-B->dot);
- (B->Mark(N.i)-B->dot).color(White,Magenta);
- if(!b.n) {Display="all brackets in region match"; return;}
- pr(CW,"unpaired brackets in region: %s",b.s); Display=CW;}
- /*-----*//* START OF DIRECTORY READER */
- /* format of a directory entry returned by int21 ah=0x4e & ah=4f */
- class FCBtime{public: uns short x;
- void strcat(char*B){short hr=(x>>11)&31,min=(x>>5)&63,twosec=x&31;
- pa(B,"%2d.%02d.%02d",hr,min,twosec*2);};};
- class FCBdate{public: uns short x;
- void strcat(char*B){static char*Month[]={"@","Jan","Feb","Mar","Apr","May",
- "Jun","Jul","Aug","Sep","Oct","Nov","Dec",".",",",":"};
- short year=(x>>9)&127,month=(x>>5)&15,day=x&31;
- pa(B,"%4d %3s %2d",year+1980,Month[month],day);};};
- class dirbuf{public:byte Reservebuf[21],attrib; FCBtime time; FCBdate date;
- uns long size; char name[13];
- void setDTA(){_ax=0x1a00; _dx=(uns int)this; int21();};/* DTA -> user var */
- /*----- read first directory entry into DTA *//* 1 if file found, else 0 */
- byte GetFirst(char*dirname, uns int attrib=0){
- _ax=0x4e00; _cx=attrib; _dx=(uns int)dirname; int21(); return !_carry;};
- /*----- read next directory entry into DTA *//* 1 if file found, else 0 */
- byte GetNext(){_ax=0x4f00; int21(); return !_carry;}
- int get(char*name){setDTA(); return GetFirst(name,~0);};};
- dirbuf fileinfo;
- unsigned long filesize(char*name){return fileinfo.get(name)?fileinfo.size:-1;}
- class direntry{public:
- byte attrib; FCBtime time; FCBdate date; uns long size; char name[13];
- direntry*next;
- direntry(dirbuf&d,direntry*n){reg char*s,*t,*u; attrib=d.attrib;size=d.size;
- for(s=name,t=d.name,u=s+12;s<u;s++,t++) *s=to__lower[byte(*t)];
- name[12]=0; date.x=d.date.x; time.x=d.time.x; next=n;};
- /*----- information about an entry */
- void print(char*B){pr(B,"%-15s%8u ",name,size);
- date.strcat(B); strcat(B," "); time.strcat(B); if(attrib&31) strcat(B," (");
- if(attrib&1) strcat(B,"readonly,"); if(attrib&2) strcat(B,"hidden,");
- if(attrib&4) strcat(B,"system,"); if(attrib&8) strcat(B,"volname,");
- if(attrib&16) strcat(B,"dir,"); if(attrib&31) B[strlen(B)-1]=')';};};
- class directory{public:direntry**entry; int n; char*name;
- directory(char*Name);
- ~directory(){int i;
- for(i=0;i<n;i++) delete entry[i]; delete entry; delete name;};
- Text copy();};
- /*------*/
- Text directory::copy(){int i,s;line*L[n+2]; for(i=n+1;i>=0;i--) L[i]=new line();
- for(i=0;i<=n;i++) *L[i]-*L[i+1]; for(s=i=0;i<n;i++) s+=entry[i]->size;
- pr(CW,"directory %s, has %1d entries, %1d bytes",name,n,s); *L[0]=val(CW);
- for(i=0;i<n;i++) {entry[i]->print(CW); *L[i+1]=val(CW);}
- return Text(L[0],L[n+1]);}
- /*-----*/
- KF(copydir){T1.getifn(Fn,"directory to list?"); setrek(T1,T1.copy());
- directory D(T1.s); B->dot.yank(D.copy(),0);}
- /*-----*/
- /* int compare(void*S,void*T,int n){register uns char*s=S,*t=T,*u=s+n;
- while(s<u) if(*s++-*t++) return s[-1]-t[-1]; return 0;} */
- /*-----*/
- enum {s_dont=0,s_name=1,s_size=2,s_date=3}; static char dirsorttype=s_name;
- int ifswop(direntry*a,direntry*b){int i; switch(dirsorttype){
- case s_dont: return 0;
- case s_name: default: return strcmp(a->name,b->name)>0;
- case s_size: return a->size>b->size;
- case s_date: i=a->date.x-b->date.x; return i?i>0:(a->time.x>b->time.x);}}
- /*----- read a directory */
- directory::directory(char*N){name=new char[strlen(N)+1]; strcpy(name,N);
- int attrib=~0; int i,k; reg int j; direntry*ch=0; n=0;
- dirbuf db; db.setDTA(); if(!db.GetFirst(N,attrib)) {entry=0; return;}
- do if(db.name[0]!='.') {n++; ch=new direntry(db,ch);} while(db.GetNext());
- reg direntry**e=new direntry*[n];
- {reg direntry*dc; for(j=0,dc=ch;dc;j++,dc=dc->next) e[j]=dc;}
- for(k=1,i=n-1;k;i--) for(k=j=0;j<i;j++) {reg direntry*a,**b=e+j; /* sort */
- if(ifswop(b[0],b[1])) {a=b[0]; b[0]=b[1]; b[1]=a; k=1;}}
- entry=e;}
- /*-----*/
- int samefile(reg char*s,reg char*t){reg int S=strlen(s),T=strlen(t);
- return S>T ?0: strcmp(s,t+T-S) ?0: S==T ?1: t[T-S-1]=='\\';}
- /*-----*/
- struct {char x; int n; char*s;} dmh[17]={
- {0, CR, " go to marked file or dir"},
- {1, -ins, " new buffer in this dir"},
- {1, -ctrl_insert," new subdir in this dir"},
- {0, -pageup, " up a page"},
- {0, -pagedown, " down a page"},
- {0, -del_, " delete marked file or dir"},
- {1, -home, " go to parent dir"},
- {1, -alt_K, " copy this dir list into a kill"},
- {0, 'K'-64, " copy file's full path to a kill"},
- {0, -alt_del, " drop marked file's buffer"},
- {0, -alt_R, " rename marked file"},
- {1, 'N'-64, " sort by name"},
- {1, 'S'-64, " sort by size"},
- {1, 'D'-64, " sort by date"},
- {1, 'X'-64, " don't sort"},
- {1, -2, " exit from this submenu"},
- {1, -alt_end, " abort this subr call"}}; enum{dmhn=17,exitoption=15};
- /*-----*/
- void filefromdirmenu(val&Dir,char*prompt,char*at/*=0*/){directory*D=0;
- char*kk,d[256],fn[13]; extern char*dirmenuhelp[]; val T; buffer*Z;
- mousestate ms,MS; int c,Q,i,I,j,k,n,s,v=gp_Rows-1,w=v-2,X=0,x=0,Y; line*L;
- B->dotcc=-1; strcpy(d,Dir.s); c=strlen(d); if(c) if(d[c-1]=='\\') d[--c]=0;
- if(at?strlen(at)>c:0) strncpy(fn,at+c+1,13); else fn[0]=0; j=0; ms=Jerry;
- READDIC: strcpy(d+c,"\\*.*"); delete D; D=new directory(d); x=X; X=0;
- YY: if(n=D->n) j%=n; else j=0; for(s=i=0;i<n;i++) s+=D->entry[i]->size;
- Jerry.range(D->n?:1,4); Jerry.move(0,0);
- if(fn[0]) if(!x?1:j<0) {j=0;
- for(i=0;i<n;i++) if(samefile(D->entry[i]->name,fn)) break; if(i<n) j=i;}
- j<?=n-1; d[c]=0; k=w/2; k=n<w?0:((j-w/4)/k)*k; k<?=n-w; k>?=0;
- Y: pr(CW,"directory %s, %1d entries, %1d bytes (I was asking \"%s\")",
- D->name,n,s,prompt); display(CW,0,0,Cyan); d[c]='\\';
- for(i=k;i<n;i++) {if(i-k>=w) break; CW[1]=' '; D->entry[i]->print(CW+2);
- strcpy(d+c+1,D->entry[i]->name);
- CW[0]=!(Z=buf_named(d))?' ':Z->changed?'*':'o';
- CW[gp_Cols]=0; display(CW,i-k+1,0,Orange);} d[c]=0;
- display(n<2? "(ctrl-_ full help, home \032 parent directory, altend aborts)":
- "(\030\031 select, ctrl-_ full help, home \032 parent dir, altend aborts, \
- return chooses)", (i-k+1)>?1,0,Orange);
- AA: i=k; k=w/2; k=n<w?0:((j-w/4)/k)*k; k<?=n-w; k>?=0;
- if(i!=k) goto Y; Y=j-k+1; if(x!=-mousemove) Jerry.move(j,1);
- if(n) scr(Y,1)=sch(2,White); Jerry.mc=1;
- switch(x=getkey()){default: goto AA;
- case -ins: strcat(d,"\\"); T.n=0; T.s=0; T.getifn(Fn,prompt,_buffer,d);
- findbuf(T)->go_to(); setrek(T1,T.copy()); delete D; Jerry=ms; return;
- case -ctrl_insert: strcat(d,"\\"); T.n=0; T.getifn(Fn,"new directory?",0,d);
- display(" ",v,0); _ax=0x3900; _dx=(int)T.s; int21(); if(_carry) beep();
- /** setrek(T1,T.copy()); */ X=1; goto READDIC;
- case -alt_end: Jerry=ms; MOAN("aborted");
- case -downarrow: if(n) j=(j+1 )%n; break;
- case -uparrow: if(n) j=(j-1+n)%n; break;
- case -pagedown: if(n) j=(j+w)<?(n-1); break;
- case -pageup: if(n) j=(j-w)>?0; break;
- case -mousemove: if(n) j=Jerry.y; break;
- case -lbutton: case CR: Jerry.mc=0; if(!n) goto AA;
- d[c++]='\\'; strcpy(d+c,D->entry[j]->name);
- if(D->entry[j]->attrib&16) {
- c=strlen(d); strcpy(d+c,"\\*.*"); directory*E=new directory(d);
- delete D; D=E; refreshscreen(); fn[0]=0; j=0; goto YY;}
- delete D; strcpy(Dir.s,d); Dir.n=strlen(d); Jerry=ms; return;
- case -del_: if(!n) goto AA; i=D->entry[j]->attrib&0x18;
- if(i&0x16) goto DD; if(i) goto AA; /* volume name */
- beep(); if(!yesno("do you really want to delete this PC file?")) goto AA;
- beep(); i=yesno("do you REALLY want to delete this PC file?");
- display(" ",v,0);if(!i) goto AA; d[c++]='\\'; strcpy(d+c,D->entry[j]->name);
- _ax=0x4100; _dx=(int)d; int21(); d[--c]=0; X=1; goto READDIC;
- DD: beep(); i=yesno("do you really want to delete this directory?");
- display(" ",v,0);if(!i) goto AA; d[c]='\\'; strcpy(d+c+1,D->entry[j]->name);
- _ax=0x3a00;_dx=(int)d; int21(); if(_carry)beep(); d[c]=0; X=1; goto READDIC;
- case -home: delete D;
- c=k=strlen(d); for(i=0;i<k;i++) if(d[i]=='\\') c=i; d[c]=0; refreshscreen();
- if(c<k-1) strncpy(fn,d+c+1,13); else fn[0]=0; j=0; goto READDIC;
- case -alt_K: setref(f,©dir); strcpy(d,!D?"D_isnull":D->name?:"(null)");
- setrek(T1,copyof(d));
- if(D) {nkill++; killring[nkill&=15].clear(); killring[nkill]=D->copy();}
- j=0; goto READDIC;
- case 'K'-64: if(!n) goto AA; d[i=c]='\\'; strcpy(d+i+1,D->entry[j]->name);
- if(D->entry[j]->attrib&16) strcat(d,"\\"); L=new line(copyof(d)); d[c]=0;
- killring[(++nkill)&=15].clear(); killring[nkill]=Text(L,L); goto AA;
- case -alt_del: d[c]='\\'; strcpy(d+c+1,D->entry[j]->name); X=1;
- Z=buf_named(d); d[c]=0; if(Z) if(deletebuffer(Z))goto READDIC; X=0; goto AA;
- case -alt_R: d[c]='\\'; d[c+1]=T.n=0; T.s=0;
- T.getifn(Fn,"rename this file as:",0,d); strcpy(d+c+1,D->entry[j]->name);
- _ax=0x5600; _dx=(int)d; _di=(int)T.s; int21(); if(_carry) beep(); d[c]=0;
- display(" ",v,0); X=1; goto READDIC;
- case '_'-64: for(i=0;kk=dirmenuhelp[i];i++) display(kk,i+1,0,Cyan); X=1;
- display("(type any char to continue)",i+1,0,Cyan); getkey(); goto READDIC;
- case 'N'-64: dirsorttype=s_name; goto READDIC;
- case 'S'-64: dirsorttype=s_size; goto READDIC;
- case 'D'-64: dirsorttype=s_date; goto READDIC;
- case 'X'-64: dirsorttype=s_dont; goto READDIC;
- case -f1: case -rbutton: case -mbutton: Q=0;
- for(i=0;i<dmhn;i++) display((n?:dmh[i].x)?dmh[i].s:" ",i+1,47,Cyan);
- MS=Jerry; Jerry.move(0,0); Jerry.range(dmhn,4); i=0; scr(1,47)=1+256*White;
- MENU: I=i; scr(i+1,47)=1+256*White; if(Q!=-mousemove) Jerry.move(i,0);
- switch(Q=getkey()) {
- case -uparrow: i=(i+dmhn-1)%dmhn; break;
- case -downarrow: i=(i+1)%dmhn; break;
- case -mousemove: i=Jerry.y; break;
- case -mbutton: case -rbutton: i=exitoption;
- case CR: case -lbutton: if(n?:dmh[i].x) inject(dmh[i].n); else break;
- Jerry=MS; for(i=0;i<dmhn;i++) display(" ",i+1,47,White); goto Y;}
- if(I!=i) scr(I+1,47)=' '+256*White; goto MENU;}
- if(n) scr(Y,1)=sch(' ',White); goto AA;}
- /*-----*/
- KF(gotodir){char*s; strcpy(s=Fn.s,B->name); int i,j=-1,n=Fn.n=strlen(Fn.s);
- for(i=0;i<n;i++) if(s[i]=='\\') j=i;
- if(j<1) MOAN("this buffer has no file name and thus no directory"); s[j]=0;
- Fn.n=j; filefromdirmenu(Fn,"file?",B->name); findbuf(Fn)->go_to();}
- /*-----*/
- void bitpack(char*s,char*t,int n){int i; reg char*u;
- for(i=0;i<n-7;i+=8) {u=t+i; *s++=
- (u[0]<<7)+(u[1]<<6)+(u[2]<<5)+(u[3]<<4)+(u[4]<<3)+(u[5]<<2)+(u[6]<<1)+u[7];}
- if(i==n) return; *s=0; for(;i<n;i++) *s=(*s<<1)|t[i];}
- /*-----*/
- void bitexp(reg char*t,reg char*s,int n) {reg char *a=t+n,c;
- if(s) while(t<a) {c=*s++; *t++=c&1; *t++=(c&2)>>1; *t++=(c&4)>>2; *t++=(c&8)>>3;
- *t++=(c&16)>>4; *t++=(c&32)>>5; *t++=(c&64)>>6; *t++=(c&128)>>7;}
- else while(t<a) *t++=0;}
- /*-----*/
- void bitcopy(reg char*t,reg char*s,int n) {reg char *a=t+((n+7)>>3);
- if(t) if(s) while(t<a) *t++=*s++; else while(t<a) *t++=0;}
- /*-----*//* MY OWN FORMATTED PRINT */
- /**** These print functions rely on C function arg values being stored at */
- /* (sizeof(each arg's value) rounded up to a multiple of 4) byte intervals ****/
- char*pr(char*B,char*F0,...) { return pr_(B, F0,(int*)(&F0)+1);}
- char*pa(char*B,char*F0,...) { return pr_(B+strlen(B), F0,(int*)(&F0)+1);}
- void pf(int f,char*F0,...) {if(f>=0) pr_((char*)f, F0,(int*)(&F0)+1);}
- void pb(char*F0,...) { pr_((char*)_buffer,F0,(int*)(&F0)+1);}
- void ps(char*F0,...) { pr_(0, F0,(int*)(&F0)+1);}
- void p_r(char*B,char*F0,...) { pr_(B, F0,(int*)(&F0)+1);}
- /* pr=string B, pa=string B append, pf=file f, pb=current buffer, ps=screen */
- /*-----*/
- char*pr_(char*S,char*F0,int*args){
- static char d[]="0123456789abcdef"; val*v; char *F=F0,*t,*u,*bb,*b,W[1024],s;
- int c,m,n,p,q,r,rs,i,j,w,*P=args; uns long X,V; bb=b=(int)S>=4096?S:W;
- /* Gnu C subr args are at 4*n-byte intervals */
- while(c=*F++) {if(c!='%') {*b++=c; continue;} rs=s=w=0; p=1;
- Z: switch (c=*F++) { /* w=wanted width, m=actual width, p=min width zerofill */
- case 0: goto END;
- case 'k': s=1;
- case 'K': ((val*)(*P++))->expandkeyseq(b,s); b+=strlen(b); break;
- case ' ': if(!s) s=' '; goto Z;
- case '-': rs=1; goto Z;
- case '+': s='+'; goto Z;
- case '.': p=0; while(isdigit(c=*F++)) p=10*p+c-'0'; F--; goto Z;
- case '0': p=-1; goto Z;
- case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9':
- w=c-'0'; while(isdigit(c=*F++)) w=10*w+c-'0'; F--; goto Z;
- case 'c': t=(char*)(P++); n=1; goto STR; /****works as PC is little-endian*/
- case 's': if(!(t=(char*)*P++)) t="(null)"; n=strlen(t); goto STR;
- case 'S': if(!(t=(char*)*P++)) t="(null)"; n=strlen(t); goto TT;
- case 't': n=strlen(t=keysort[-(int)*P++]); goto STR;
- case 'T': u=b; b=(b+1)>?(bb+((int)*P++)); while(u<b) *u++=' '; break;
- case 'v': v=(val*)*P++; t=v->s; n=t?v->n:0; if(v->magic()) goto MAGIC;
- TT: *b++='"';
- for(i=0;i<n;i++) {w=strlen(u=chname(t[i])); for(j=0;j<w;j++) *b++=u[j];}
- *b++='"'; break;
- MAGIC: n&=0x00ffffff; *b++='"';
- for(i=0;i<n;i++) {if(bit(t+n+1,i)) *b++='`';
- w=strlen(u=chname(t[i])); for(j=0;j<w;j++) *b++=u[j];}
- *b++='"'; break;
- case 'd': X=*P++; if((long)X<0) {X=-X; s='-';} r=10; goto NUM;
- case 'o': X=*P++; r=8; goto NUM;
- case 'u': X=*P++; r=10; goto NUM;
- case 'x': X=*P++; r=16; goto NUM;
- default: *b++=c;}; goto Y;
- NUM: if(p<0) p=s?w-1:w; V=X;
- m=0; if(V?:p) do m++; while(V/=r); m>?=p; /* m=#digits */ n=m+(s?1:0);
- if(!rs) for(q=n;q<w;q++) *b++=' '; if(s) *b++=s;
- for(c=m-1;c>=0;c--) {b[c]=d[X%r]; X/=r;} b+=m; goto J;
- STR: if(!rs) for(q=n;q<w;q++) *b++=' '; u=t+n; while(t<u) *b++=*t++;
- J: if(rs) for(q=n;q<w;q++) *b++=' '; Y:;}
- END: *b=0;
- if((int)S==_buffer) *B+=W; /* insert into current buffer */
- else if(!S) wr(W); /* write to screen */
- else if((int)S<4096) write((int)S,W,b-W); /* write on a file */ return b;}
- /*-----*/
- char**readtext(char*file){char*s; int F; if((F=open(file,0x8001))<0) return 0;
- dirbuf d; if(!d.get(file)) return 0; int i,j,n=d.size; char*text=new char[n+1];
- n=read(F,text,n); close(F); if(!n?:text[n-1]!=LF) text[n++]=LF;
- for(i=j=0;i<n;i++) if(text[i]==LF) j++; char**lin=new char*[j+1]; lin[0]=text;
- for(i=0,j=1;i<n;i++) if(text[i]==LF) {text[i]=0; lin[j++]=&text[i+1];}
- for(s=lin[0]-2,i=1;i<j;i++) if(s[2]) if(*(s=lin[i]-2)==CR) *s=0; lin[j-1]=0;
- return lin;}
- /*-----*//* START OF SPELLING CHECKER */
- typedef unsigned char byte; /* V=vowel, C=consonant, E=anything but 'e' */
- static char*Buf,*P,*Be;
- static int Wn=0,sn,D,pradd,alteredfrom,pfstart,RV;
- #define upb(array) (sizeof(array)/sizeof((array)[0]))
- #define forways(m,w) for(m##e=(m=w.way)+w.wayn;m<m##e;m++)
- enum{MAXDICT=200000,NWORDS=20000};
- enum{noGem=0,Gem=1,GemUK=2};
- enum{e_normal=0,e_keep=1,e_soften=2};
- enum{supine=0,conjA=1,conjI=2,notlatin=3};
- class Decl{public: uns int gem:2,cap:1,conj:2,e:2,bad:1;};
- class Word{public: char*s; byte n; Decl decl;
- inline char*suf(){return s+n+1;};
- inline void operator=(val&v){s=v.s; n=v.n;};};
- class Way {public: char*del,*add; byte deln,addn;};
- class Suf {public: Way*way; byte wayn;};
- static val*pre; static int npre; static Word word[NWORDS]; /******/
- static Suf suf[256],desuf[32];
- static int findword(val w);
- static byte _CV[32]=
- {0,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0};
- inline int cons(char c){return _CV[c&31];}
- inline int vowel(char c){return 1-_CV[c&31];}
- #define forwords(w) for(w=sn;w<Wn;w++)
- #define forall(w) for(w=1;w<Wn;w++)
- #define forsuffs(s,w) for(s=w.suf();*s;s++)
- /*-----*/
- class wordlist{public: char**s; int n;
- wordlist(int i=1){s=new char*[16]; s[0]=""; n=1;}; /* word 0 is dummy */
- int place(char*w){int i,j,k,m; if(n<2) return -1; int wl=strlen(w);
- for(j=0x8000,m=0;j>=1;j>>=1) if((k=m+j)<n) {
- i=strncmp(w,s[k]+1,wl+1); if(!i) return k; if(i>0) m=k;}
- return -m-1;};
- inline int contains(char*w){return place(w)>0;};
- int operator+(char*w){char**t; int i,k; int wl=strlen(w);
- if((k=place(w))>0) return k; k=-k; t=s;
- if(!(n&15)) {s=(char**)myalloc((n+16)*sizeof(char*));
- for(i=0;i<k;i++) s[i]=t[i];}
- for(i=n;i>k;i--) s[i]=t[i-1];
- s[k]=(char*)myalloc(wl+2); memcpy(s[k]+1,w,wl+1);
- s[k][0]=0; if(s!=t) delete t; n++; return k;};
- void empty(){int i; for(i=1;i<n;i++) delete s[i]; delete s; s=new char*[16];
- s[0]=""; n=1;};
- Text copy(int min){int i,j,m=0; for(i=1;i<n;i++) if(s[i][0]>=min) m++;
- line*L[m+1]; for(i=0;i<=m;i++) L[i]=new line();
- if(min>=0) {for(i=1,j=0;i<n;i++) if(s[i][0]>=min) {
- *L[j]-*L[j+1]; *L[j++]=val(s[i]+1);}}
- else for(i=1;i<n;i++) {*L[i-1]-*L[i]; strcpy(CW,s[i]+1); j=strlen(CW);
- CW[j++]='/';CW[j++]='#'; CW[j++]='0'+s[i][0]; CW[j]=0; *L[i-1]=val(CW);}
- return Text(L[0],L[m]);};};
- wordlist appendix(1); int&appendixsize=appendix.n;
- /*----- ONE-LINERS */
- static void skipsp(){while(*P==' ') P++;}
- static void findeol(){while(*P!='\n') P++; P++;}
- static int nextis(char c){reg int j; skipsp(); if(j=*P==c) P++; return j;}
- //static int getn(){reg int n=0; while(isdigit(*P))n=n*10+*P++-'0'; return n;}
- static void X(char*moan) {Wn=0;
- pr(CW,"bad data at %dth byte of dictionary: %s",P-Buf,moan); MOAN(CW);}
- /*-----*/
- static char*getwword(byte&N){reg char c,*s=P,*t; reg int n=0; skipsp();
- while(isalnum(c=*P)?1:c=='!'?:c=='+') {P++; n++;}
- if(!(N=n)) return 0; t=new char[n+1]; memcpy(t,s,n); t[n]=0; return t;}
- /*-----*/
- static val getheadword(){reg char *s; reg int n=0; skipsp(); s=P;
- if(*P=='-'?:*P=='<') {n++; P++;} while(isalnum(*P)?:*P=='\'') {n++; P++;}
- if(!n) return val(0,0); return val(s,n);}
- /*-----*/
- static void readways(Suf&S){Way way[32],*m; bzero(m=way,32*sizeof(Way));
- do {if(m-way>=32) X("this suffix has > 32 methods");
- m->del=getwword(m->deln)?:"";
- if(nextis(':')) m->add=getwword(m->addn)?:"";
- else {m->add=m->del; m->del=""; m->addn=m->deln; m->deln=0;}
- m++;} while(nextis(','));
- S.way=new Way[S.wayn=m-way]; memcpy(S.way,way,S.wayn*sizeof(Way));}
- /*-----*/
- static void setup(){static Way nullway={"","",0,0};
- int i,j,k,l,n; char *p,*q,*Q[256+1]; byte sf[256];
- bzero(word,sizeof(word)); Buf=new char[MAXDICT]; val DF(0,0),v;
- suf[0].wayn=1; suf[0].way=&nullway; suf[1]=suf[0]; i=1;
- strcpy(T2t.s,dictname); T2t.n=strlen(T2t.s);
- DF.getifn(T2t,"dictionary file name?");
- D=open(T2t.s,0x4001); /*read text*/ Display="reading dictionary"; showmoan();
- Be=Buf+(n=read(D,Buf,MAXDICT)); if(n<=0) MOAN("I can't read the dictionary");
- if(n==MAXDICT) MOAN("dictionary too big for buffer");
- if(Be[-1]!='\n') *Be++='\n'; pradd=0;
- for(P=Buf;strncmp(P,"--------",8);findeol()) if(P>=Be) X("bad dictionary");
- findeol(); for(i=0;i<32;i++) {desuf[i].way=0; desuf[i].wayn=0;}
- while(nextis('^')) {if(!isalpha(*P)) X("bad char after '^'"); i=(*P)&31; P+=2;
- readways(desuf[i]); findeol();}
- for(i=0,sn=1;;sn++) {findeol(); v=getheadword(); if(!v.n) X("bad headword");
- Q[sn]=P; word[sn]=v; if(v.s[0]=='<') i++; else if(v.s[0]!='-') break;
- if(sn>=256-1) X("too many suffixes");}
- Wn=sn; pre=new val[npre=i]; RV=findword(val("-RV",3));
- for(j=0,i=1;i<sn;i++) {reg Suf&S=suf[i]; P=Q[i]; S.wayn=0; S.way=0;
- if(nextis('=')) readways(S); Q[i]=P;
- if(word[i].s[0]=='<') pre[j++]=val(word[i].s+1,word[i].n-1);}
- for(j=1;findeol(),P<Be;j++) {reg Word&W=word[j]; char*s;
- if(j>=NWORDS) X("too many entries");
- if(j<=sn) P=Q[j]; else {v=getheadword(); if(!v.n) X("bad headword"); W=v;}
- k=W.n;
- if(j>1) if(strncmp(word[j-1].s,W.s,W.n+1)>=0) X("entry out of ascii order");
- if(k>1)if(W.s[k-1]=='e')if(W.s[k-2]=='c'?1:W.s[k-2]=='g') W.decl.e=e_soften;
- for(i=0;i<sn;i++) sf[i]=0;
- while(nextis('/')) {skipsp(); /* stop at / \\ \n space */
- for(s=P;*P=='/'?0:*P=='\\'?0:*P=='\n'?0:*P!=' ';P++);
- i=(n=P-s)==1 ? *s : n==2 ? *s+256*s[1] : 0;
- if(i=='2') W.decl.gem=Gem; /* doubles last letter */
- else if(i=='3') W.decl.gem=GemUK; /* ditto, optional */
- else if(i=='X') W.decl.bad=1; /* illegal word */
- else if(*s=='#') ; /* start of marker used by putappendix */
- else if(i=='!'+256*'a') W.decl.conj=conjA;
- else if(i=='!'+256*'i') W.decl.conj=conjI;
- else if(i=='!'+256*'n') W.decl.conj=notlatin;
- else if(i=='K'+256*'E') W.decl.e=e_keep; /* -e stays before vowel */
- else if(i=='P'+256*'N') W.decl.cap=1;
- else if(i=='N'+256*'S') sf[0]=255; /* not self */
- else if((*s=='-'?:*s=='<')?n>1:0) {k=1; if(s[n-1]=='*') {k=255; n--;}
- if(!(l=findword(val(s,n)))) X("not a known suffix"); sf[l]=k;}
- else X("rubbish after '/'");}
- skipsp(); if(*P!='\n') X("rubbish after entry");
- for(i=l=0;i<sn;i++) l+=(sf[i]<?2);
- p=new char[W.n+1+l+1]; memcpy(p,W.s,W.n); p[W.n]=0; q=p+W.n+1;
- if(k=sf[0]) *q++=k; for(i=1;i<sn;i++) if(k=sf[i]) {*q++=i; if(k-1) *q++=k;}
- *q=0; W.s=p;}
- close(D); delete Buf; Wn=j;
- for(pfstart=1;pfstart<sn;pfstart++) if(word[pfstart].s[0]=='<') break;
- pr(CW,"dictionary read: %d words",Wn); Display=CW; showmoan();}
- /*-----*/
- static int addsuffix(val w,Decl decl,Way&m,char*saveend){
- /* try a form of a suffix. Return 0 if this suffix won't work this way */
- reg char dn=m.deln,*s,*t; if(w.n-(w.s[0]=='-'?0:1)<dn) return 0;
- #ifdef DB
- debug=fopen("t$debug","a"); In();
- fprintf(debug,"addsuffix(%s - %s + %s)\n",w.s,m.del,m.add); fclose(debug);
- #endif
- if(!dn) {saveend[0]=0; s=w.s+w.n;}
- else {if(m.del[0]=='e') switch(decl.e) {
- default: break;
- case e_keep: return 0;
- case e_soften: if(!index("iey",m.add[0])) return 0;}
- for(s=w.s+w.n-dn,t=m.del;*t;t++,s++){
- if(*t=='V') if(vowel(*s)) continue;
- if(*t=='C') if(cons(*s)) continue;
- if(*t!=*s) return 0;}
- if(dn) memcpy(saveend,s=w.s+w.n-dn,dn); saveend[dn]=0;}
- if(t=m.add) if(*t) {
- if(!dn) if(vowel(*t)?:*t=='y') if(decl.gem) {*s=s[-1]; s++;}
- while(*t) if(*t=='!') switch(t++,decl.conj){
- case conjA: *s++='a'; *s++='t'; break;
- case conjI: *s++='i'; *s++='t'; default:;}
- else if(*t=='+') {s++; t++;} else *s++=*t++;} *s=0;
- alteredfrom=w.n-dn; return s-w.s;} /* return length of suffixed word */
- /*-----*/
- static int findword(val w){int i,j,k,n; if(!w.s) return 0;
- for(j=0x8000,n=0;j>=1;j>>=1) if((k=n+j)<Wn) {/* word 0 in dictionary is dummy */
- i=strncmp(w.s,word[k].s,w.n); if(!i) if(w.n<word[k].n) i=-1;
- if(!i) return k; if(i>0) n=k;} return 0;}
- /*-----*/
- int checkderivs(val w,val u,Word&U,Decl decl){char*sf=U.suf(),rv; Word*Q;
- #ifdef DB
- debug=fopen("t$debug","a"); In();
- fprintf(debug,"checkderivs(%s,%s as %s)",w.s,u.s,U.s);
- int I; for(I=0;I<16;I++) fprintf(debug," %02x",byte(sf[I])); putc('\n',debug);
- fclose(debug);
- #endif
- if(Breakin()) return 0; if(u.n>w.n+1) return 0; /* word has got too long */
- int i,k,newun; Way*m,*me; byte s; if(!sf) return 0; if(byte(*sf)==255) sf++;
- for(;s=*sf;sf++) {Word&W=word[s]; Suf&S=suf[s]; if(rv=(byte(sf[1])==255)) sf++;
- #ifdef DB
- debug=fopen("t$debug","a"); In();
- fprintf(debug,"checkderivs(%s,%s as %s: %s)\n",w.s,u.s,U.s,W.s);
- In(); fprintf(debug,"S.wayn=%1d\n",S.wayn);
- fclose(debug);
- #endif
- if(W.s[0]=='<') {Way&P=S.way[0]; i=P.addn+u.n; char T[i+1],*s; val v(T,i);
- memcpy(T,P.add,P.addn); memcpy(T+P.addn,u.s,u.n+1);
- if(!strncmp(w.s,T,v.n+1)) return 1; s=W.suf();
- if(byte(s[0])==255?!s[1]:0) {Word V; V.decl=U.decl; V.n=U.n; char*t;
- char Y[512]; memcpy(V.s=Y,U.s,i=U.n+1); t=Y+i; s=U.s+i;
- while(*s) /* if(byte(*s)>=pfstart) break; else */ *t++=*s++; *t=0;
- Q=&V;}
- else Q=&W;
- if(checkderivs(w,v,*Q,decl)) return 1;}
- else if(!S.wayn) {if(checkderivs(w,u,W,decl)) return 1;}
- else for(me=(m=S.way)+S.wayn;m<me;m++) {char T[16];
- if(newun=addsuffix(u,decl,*m,T)) {
- if(!strncmp(w.s,u.s,newun+1)) k=byte(*W.suf())!=255;
- else k=checkderivs(w,val(u.s,newun),W,W.decl) ?: !rv?0:
- checkderivs(w,val(u.s,newun),word[RV],W.decl);
- strcpy(u.s+u.n-m->deln,T); if(k) return k; break;}}}
- return 0; /* fault: no way to make the suffix wanted */}
- /*-----*/
- val Stak[64];
- /*-----*/
- static int checkwd(val w,val u,int D=0){if(D>=63?:Breakin()) return 0;
- #ifdef DB
- debug=fopen("t$debug","a"); In();
- fprintf(debug,"checkwd(%s,%s)\n",w.s,u.s); fclose(debug);
- #endif
- int i,j,k,n; char T[512]; Way*m,*me; byte s; Suf*S; val*pr;
- for(i=0;i<D;i++) if(!strncmp(u.s,Stak[i].s,u.n+1)) return 0; Stak[D]=u;
- //for(j=i=0;i<D;i++) if(!strncmp(u.s,Stak[i].s,u.n+1)) j=i;
- // if(j) {debug=fopen("t$debug","a"); In();
- // fprintf(debug,"same as Stak[%d]\n",j); fclose(debug); return 0;}
- //Stak[D]=u;
- /* to stop a loop that developed e.g. ble -> blee -> ble -> etc */
- for(j=0x8000,n=0;j>=1;j>>=1) if((k=n+j)<Wn) {Word&W=word[k];
- i=strncmp(u.s,W.s,u.n+1); if(!i) if(u.n<W.n) i=-1;
- if(!i) {if(W.decl.bad) return 0; /* word u found exactly */
- if(!strncmp(w.s,u.s,u.n+1)) return (s=*W.suf())==255?0:k;
- memcpy(T,W.s,u.n+1); /* find if u can be extended to w */
- if(checkderivs(w,val(T,u.n),W,W.decl)) return 1;
- if(W.decl.gem==GemUK){Decl d=W.decl; d.gem=noGem; /* UK/USA variation */
- if(checkderivs(w,val(T,u.n),W,d)) return 1;}
- break;}
- if(i>0) n=k;}
- for(pr=pre+npre-1;pr>=pre;pr--) if(*u.s==*pr->s) if(!strncmp(u.s,pr->s,j=pr->n))
- if(k=checkwd(w,val(u.s+j,u.n-j),D+1)) return k; /*try removing prefix from u*/
- for(S=desuf+(u.s[u.n-1]&31),me=(m=S->way)+S->wayn;m<me;m++) {
- if(u.n>m->deln) if(!strncmp(u.s+u.n-m->deln,m->del,m->deln)) {
- if(u.n-m->deln+m->addn>511) break;
- memcpy(T,u.s,u.n+1); /* try removing suffix from u */
- memcpy(T+u.n-m->deln,m->add,m->addn+1); j=strlen(T);
- if(m->addn>m->deln) if(j>2) if(T[j-1]==T[j-2]) if(T[j-2]==T[j-3]) break;
- /* to stop a loop that developed: ble -> blee -> bleee -> etc */
- if(k=checkwd(w,val(T,j),D+1)) return k;}}
- if(u.n>2) if(cons(i=u.s[u.n-1])) if(i==u.s[u.n-2]) { /* doubled consonant */
- memcpy(T,u.s,u.n-1); T[j=u.n-1]=0;
- k=checkwd(w,val(T,j),D+1); u.s[u.n++]=i; return k;}
- return 0;}
- /*-----*/
- KF(checkspelling){char*eor="end of region"; int z=N.i?0:N.n; if(!N.n) N.i=0;
- int i,j,k; mark X,Y=B->dot,Z=B->eof(); char *S,T[512]; B->dotcc=B->dotcc2=-1;
- if(N.i) {Z=B->Mark(N.i); if(Z<Y) {X=Z; Z=Y; Y=X; setmark(N); B->dot=Y;}}
- LOOP: X=Y; if(Breakin()) {B->dot=Y; Moan="user breakin"; return;}
- if(X.is_alnum()) X.skip_alnum(1); else X.find_alnum(0,0);
- if(X.eol()) {if(X.r==Z.r) {Display=eor; return;} ++X;
- if(!X.r) {Moan="hit eof"; return;} Y=X; goto LOOP;}
- Y=X; SW: Y.skipword(1); if(Y.r==Z.r) if(Y.c>Z.c) {Display=eor; return;}
- B->dot=Y; B->display(); (X-Y).color(White,Magenta);
- if(X.r!=Y.r) MOAN("bad craziness: end-of-line in word!");
- if(X.c>=Y.c) MOAN("no word found"); if(Y.c-X.c>500) MOAN("word too long");
- S=X.r->s+X.c; T[j=(Y.c-X.c)<?511]=0;
- for(k=0,i=j;k<j;k++) if(isdigit(T[k]=to_lower(S[k]))) i--;
- if(!Wn) setup(); i=!i ?: checkwd(val(T,j),val(T,j)) ?: appendix.contains(T);
- if(!i) if(Y.c<Y.r->n-1) if(*Y=='\'') if(++Y,Y.is_alnum()) goto SW; else --Y;
- if(i) if(!N.i) {Display="spelt correctly"; return;} else goto LOOP;
- if(T1.n) {i=appendix+T; appendix.s[i][0]=1; goto LOOP;}
- B->display(); B->dotcc=B->dotcc2=-1;
- k=!N.i?1:yesno("misspelt or unknown word: shall I stop and let you change it?");
- if(!k?:z) {
- j=yesno("misspelt or unknown word: shall I list it as vocabulary?");
- i=appendix+T; appendix.s[i][0]=j?1:0;} if(!k) goto LOOP;
- (X-Y).color(White,Magenta); Moan="misspelt or unknown word";}
- /*-----*/
- KF(getappendix){checkspelling(N.n?N:val(1),val("y",1),val(0,0));}
- /*-----*/
- KF(putappendix){Text A=appendix.copy(N.i<?1); B->changed=1;
- *(B->dot.r->prev?:&B->text)-*A.beg; *A.end-*B->dot.r; B->text.next->prev=0;
- if(yesno("shall I also empty the dictionary's appendix?")) appendix.empty();}
- /*-----*/
- KF(emptyappendix){appendix.empty();}
- /*-----*/
- int bottommenu(
- char*prompt,int nrb,char*codes,char**names,int L/*=8*/,int defolt/*=0*/){
- mousestate ms; ms=Jerry; int c,j,k,m,n=strlen(codes),N=n*L,p; char*s,MN[L*n+1];
- Jerry.range(4,n*L); Jerry.move(0,(k=defolt)*L); Jerry.mc=1; c=Jerry.bd=0;
- for(c=0;c<L*n;c++) MN[c]=' '; p=strlen(prompt);
- short ls[gp_Cols]; c_short_addr q=scr(gp_Rows-1,0).adr(); c_get(ls,q,gp_Cols);
- for(c=0;c<n;c++) for(j=strlen(s=names[c])-1;j>=0;j--) MN[L*c+j]=s[j]; MN[N]=0;
- display(prompt,gp_Rows-1,0,Magenta); displayn(MN,gp_Rows-1,p,White+8,Blue);
- M1: if(c!=-mousemove) Jerry.move(0,k); counterchange(scr(gp_Rows-1,k+p));
- c=getkey(); if(c>='a') if(c<='z') c-=32; counterchange(scr(gp_Rows-1,k+p));
- if(Jerry.buttons) {c=-mousemove; goto M1;} switch(c){
- case -lbutton: case CR: m=k/L; goto RET;
- case -mousemove: k=Jerry.x; goto M1;
- case -leftarrow: k=(k-1)%N; goto M1;
- case -rightarrow: k=(k+1)%N; goto M1;
- case -mbutton: case -rbutton: m=nrb; goto RET;
- default: for(m=0;m<n;m++) if(c==codes[m]) goto RET;} goto M1;
- RET: Jerry=ms; c_put(q,ls,gp_Cols); return m;}
- /*-----*/
- KF(char_from_menu) {int c; if((c=charfrommenu())<0) {basemi.rec=0; return;}
- Insert(N.i,c); setref(f,&insert); setrek(T1,(char)c);}
- /*-----*/
- Subr*subrmenu(char*prompt,int fromKF){
- int i,j,k,n,u,v; char*s,**z; c_short_addr p,q,r; subr*sb; mark MK;
- short scrsave[gp_Cols*gp_Rows]; int ss=gp_Cols*gp_Rows;
- typedef struct{char submenu; subr*sub; char*text;} menuline;
- static menuline _bindmenu[]={{6,0,0},
- {0,&bindkeybuf,"bind key to current buffer"},
- {0,&bindkeymacro,"bind key to current macro"},
- {0,&bindkeysubr,"bind key to subroutine"},
- {0,&prbindings,"insert list of key bindings"},
- {0,&prkeys,"insert list of keys & key bindings"},
- {0,&unbindkey,"unbind key"}};
- static menuline*bindmenu=_bindmenu;
- static menuline _buf[]={{14,0,0},
- {0,&buffermenu,"go to buffer by menu of buffers"},
- {0,&gotodir,"go to file by menu of DOS directory"},
- {0,&gotonbuf,"go to next buffer in chain"},
- {0,©dir,"insert copy of DOS directory"},
- {0,&delbuf,"remove current buffer (not its file)"},
- {0,&insertfile,"insert text of a file"},
- {0,&mergefile,"merge a file into region in ascii order."},
- {0,&openfile,"go to file"},
- {0,&prbuffers,"list buffers with bindings, in form obeyable by readmacros"},
- {0,&renamebuffer,"change filename of buffer"},
- {0,&restorebuf,"re-read buffer from its file"},
- {0,&showinfo,"show information about buffer"},
- {0,&writebuffer,"copy buffer to a file"},
- {0,&savebuffer,"copy buffer to its file"}};
- static menuline*buf=_buf;
- static menuline _c[]={{3,0,0},
- {0,&cbrackets,"check region for C bracket matching"},
- {0,&cchrstr,"convert \\sequence to literal char"},
- {0,&cstrchr,"convert char to \\sequence if needed in C string"}};
- static menuline*c=_c;
- static menuline _Case[]={{5,0,0},
- {0,&capitalize,"capitalize word"},
- {0,&lwcasewords,"lowercase word"},
- {0,&upcasewords,"uppercase word"},
- {0,&lwcaseregion,"lowercase region"},
- {0,&upcaseregion,"uppercase region"}};
- static menuline*Case=_Case;
- static menuline _crlf[]={{3,0,0},
- {0,&finalcr,"add CR marker in all lines in region"},
- {0,&nofinalcr,"remove CR marker in all lines in region"},
- {0,&linefeed,"insert LF without CR"}};
- static menuline*crlf=_crlf;
- static menuline _del[]={{13,0,0},
- {0,&backspace,"delete char \033"},
- {0,&delet,"delete char \032"},
- {0,&killwordb,"kill word \033"},
- {0,&killwordf,"kill word \032"},
- {0,&killsent,"kill sentence \032"},
- {0,&kill_to_eol,"kill (to) EOL"},
- {0,&killregion,"kill region"},
- {0,©kill,"copy region to kill ring"},
- {0,&delblanklines,"delete blank lines round cursor"},
- {0,&deletewhite,"delete all spaces & tabs round cursor"},
- {0,&leaveonewhite,"delete blanks, leave 1 space"},
- {0,&replyank,"replace yank by previous kill"},
- {0,&yank,"yank last kill"}};
- static menuline*del=_del;
- static menuline _insert[]={{6,0,0},
- {0,&insertspaces,"insert space"},
- {0,&literalchar,"insert any char literally"},
- {0,&newline,"insert EOL"},
- {0,&openline,"insert EOL after cursor"},
- {0,&insert,"insert text"},
- {0,&overlay,"overlay text"}};
- static menuline*Insert=_insert;
- static menuline _Macro[]={{8,0,0},
- {0,&beginmacro,"start recording macro"},
- {0,&endmacro,"stop recording macro"},
- {0,&namemacro,"give macro a name"},
- {0,&obey,"obey current macro"},
- {0,¯omenu,"menu of current macros"},
- {0,&prmacro,"insert copy of current macro"},
- {0,&prmacros,"insert copy of all macros"},
- {0,&readmacros,"read macros & obey buffer bindings from a buffer"}};
- static menuline*macro=_Macro;
- static menuline _mark[]={{7,0,0},
- {0,&popmark,"popmark"},
- {0,&pushmark,"pushmark"},
- {0,&remmark,"remove top mark from stack"},
- {0,&setmark,"set mark"},
- {0,&swopmark,"swop mark with cursor"},
- {0,&markbof,"set mark to start of buffer"},
- {0,&markeof,"set mark to end of buffer"}};
- static menuline*mark=_mark;
- static menuline _misc[]={{20,0,0},
- {0,&refresh_display,"cursor line becomes Nth/middle of screen"},
- {0,&prkeynames,"insert list of names of all alt and special keys"},
- {0,&prsubrnames,"insert list of all subroutine names"},
- {0,&accentedletters,"stop/start treating PC accented letters as alphanumeric"},
- {0,&calldos,"call DOS command"},
- {0,&cccmode,"whether or not to counterchange at cursor"},
- {0,&checkhelp,"insert report re any bound keys not listed in file HELP"},
- {0,&dis_play,"display text on the mode line in cyan"},
- {0,&displayhex,"display from cursor as hexadecimal"},
- {0,&movetext,"move (text between mark N and mark N+1) to cursor"},
- {0,©text,"copy (text between mark N and mark N+1) to cursor"},
- {0,&repeat,"obey last instruction again"},
- {0,&setrightmargin,"find/set right margin for auto eol"},
- {0,&setsortcol,"find/set left margin for sortlines"},
- {0,&showregion,"show region, or from mark 1 to mark 2"},
- {0,&sortlines,"sort lines in region into alphabetical order"},
- {0,×4,"multiply current N by 4"},
- {0,&version,"display date of this version of AAEMACS"},
- {0,&whoa,"discard arg typed"},
- {0,&menu,"this subroutine (menu of subroutine descriptions)"}};
- static menuline*misc=_misc;
- static menuline _move[]={{20,0,0},
- {0,&goleft,"\033 a char"},
- {0,&goright,"\032 a char"},
- {0,&gotocol,"go to Nth char in line"},
- {0,&gouppart,"\030 a line-fold"},
- {0,&godownpart,"\031 a line-fold"},
- {0,&goup,"\030 a line"},
- {0,&godown,"\031 a line"},
- {0,&gotobol,"go to start of line"},
- {0,&gotoeol,"go to end of line"},
- {0,&gotoline,"go to line N"},
- {0,&skipwordb,"\033 a word"},
- {0,&skipwordf,"\032 a word"},
- {0,&skipsentb,"\033 a sentence"},
- {0,&skipsentf,"\032 a sentence"},
- {0,&skipparab,"\030 a paragraph"},
- {0,&skipparaf,"\031 a paragraph"},
- {0,&page_down,"\031 a screenful"},
- {0,&page_up,"\030 a screenful"},
- {0,&gotobof,"go to top of buffer"},
- {0,&gotoeof,"go to end of buffer"}};
- static menuline*move=_move;
- static menuline _reformat[]={{3,0,0},
- {0,&formatpara,"reformat paragraph"},
- {0,&formatregion,"reformat region"},
- {0,&formatinsetregion,"reformat region and keep its left inset chars"}};
- static menuline*reformat=_reformat;
- static menuline _Repl[]={{4,0,0},
- {0,&repl,"replace"},
- {0,&replask,"replace, asking"},
- {0,&replword,"replace, whole words only"},
- {0,&replwordask,"replace, whole words only, asking"}};
- static menuline*Repl=_Repl;
- static menuline _Search[]={{6,0,0},
- {0,&findb,"search \033"},
- {0,&findf,"search \032"},
- {0,&findwordb,"search \033, whole word only"},
- {0,&findwordf,"search \032, whole word only"},
- {0,&incrfindb,"incremental search \033"},
- {0,&incrfindf,"incremental search \032"}};
- static menuline*Search=_Search;
- static menuline _spelling[]={{4,0,0},
- {0,&checkspelling,"check spelling of next word or all region"},
- {0,&emptyappendix,"empty the dictionary's appendix"},
- {0,&getappendix,"load dictionary's appendix from region"},
- {0,&putappendix,"copy dictionary's appendix into a buffer"}};
- static menuline*spelling=_spelling;
- static menuline _tab[]={{3,0,0},
- {0,&expandtabs,"expand all tabs to spaces in region"},
- {0,&maketabs,"convert spaces to tabs in region"},
- {0,&tabulate,"insert or overlay tab char"}};
- static menuline*tab=_tab;
- static menuline _Twiddle[]={{3,0,0},
- {0,&twiddle,"twiddle: move this char \032"},
- {0,&twiddlewords,"twiddle: move this word \032"},
- {0,&twiddlelines,"twiddle: move this line \031"}};
- static menuline*Twiddle=_Twiddle;
- static menuline _windows[]={{4,0,0},
- {0,&splitwindow,"split this window"},
- {0,&onewindow,"back to one-window mode"},
- {0,&nextwindow,"go to next window in ring of windows"},
- {0,&prevwindow,"go to previous window in ring of windows"}};
- static menuline*windows=_windows;
- static menuline _topmenu[]={{23,0,0},
- {1,(subr*)bindmenu,"KEY BINDINGS"},
- {1,(subr*)buf,"FILES AND BUFFERS"},
- {1,(subr*)c,"C LANGUAGE FEATURES"},
- {0,&callsubr,"call subr or macro"},
- {1,(subr*)Case,"CASE OF LETTERS"},
- {0,&char_from_menu,"character from menu"},
- {1,(subr*)crlf,"CR AND LF"},
- {1,(subr*)del,"DELETING"},
- {0,&help,"get help"},
- {1,(subr*)Insert,"INSERTING"},
- {1,(subr*)macro,"MACROS"},
- {1,(subr*)mark,"MARKS"},
- {1,(subr*)misc,"MISCELLANEOUS"},
- {0,&modemenu,"find & reset buffer's modes by a menu"},
- {1,(subr*)move,"MOVE CURSOR"},
- {1,(subr*)Twiddle,"MOVING A CHAR/WORD/LINE"},
- {1,(subr*)reformat,"REFORMAT TEXT"},
- {1,(subr*)Repl,"REPLACING"},
- {1,(subr*)Search,"SEARCHING"},
- {1,(subr*)spelling,"SPELLING CHECKER"},
- {1,(subr*)tab,"TABULATING"},
- {1,(subr*)windows,"SPLIT SCREEN MODE"},
- {0,&finish,"exit from AAEMACS"}};
- static menuline*topmenu=_topmenu,*M[4];
- if(fromKF==2)if(Jerry.mc) {char*MN[]={"Move","Copy","Delete","Exit","mainmenU"};
- MK=B->Mark(1); (MK-B->Mark(2)).color(White,Magenta); B->display();
- B->dotcc=B->dotcc2=-1; /* stop dotty() from playing with the cursor */
- switch(bottommenu("",4,"MCDEU",MN,8)) {
- case 0: movetext(); return 0;
- case 1: copytext(); return 0;
- case 2: (B->Mark(1)-B->Mark(2)).kill(); return 0;
- case 3: return 0;
- case 4:;}}
- char mp[4]; mp[0]=0; M[0]=&topmenu[0]; int Z=0,m=0; val A(1,0); mousestate MS;
- MS=Jerry; c_get(scrsave,screen,ss); thisstep.f=kf(_idle);
- if(prompt) display(prompt,gp_Rows-2,0,Cyan);
- display("\030\031\033\032 to move pointer, RET to choose, END to back out,\
- ctrl_ for help",gp_Rows-1,0,Cyan); Jerry.bd=0;
- MENU: Jerry.mc=1; n=M[m][0].submenu; Jerry.range(n,80); Jerry.move(k=mp[m],0);
- for(i=n*gp_Cols-1;i>=0;i--) screen[i]=256*White; j=1;
- for(i=0;i<n;i++) c_put_color(screen+(i*gp_Cols+1),M[m][i+1].text,-1,Green);
- screen[k*gp_Cols]+=2;
- CHAR: j=k; if(Z!=-mousemove) Jerry.move(k,0); switch(Z=getkey()){
- case -mousemove: k=Jerry.y; break;
- case -uparrow: k--; break; case -downarrow: k++; break;
- case -rightarrow: k+=5; break; case -leftarrow: k-=5; break;
- case CR: goto CHOSEN;
- case -end_: case -mbutton: case -rbutton: Jerry.mc=0; goto BACKOUT;
- case -lbutton: if(M[m][k+1].submenu?:!(keysdown()&k_ctrl)) goto CHOSEN;
- case '_'-64: case -clickboth: if(M[m][k+1].submenu) {beep(); goto CHAR;}
- s=kf(M[m][k+1].sub).Subrname(); if(!(z=Subrhelp(s))) {beep(); goto CHAR;}
- j=0; display(*z++,j++,0,Orange);
- while(*z?**z!='{':0) display(*z++,j++,0,Orange); getkey(); goto MENU;
- default: goto CHAR;}
- while(k<0) k+=n; while(k>=n) k-=n; mp[m]=k;
- if(j!=k) {screen[j*gp_Cols].Char()=' '; screen[k*gp_Cols].Char()=2;} goto CHAR;
- BACKOUT: c_put(screen,scrsave,ss); if(m--) goto MENU; Jerry=MS; return 0;
- CHOSEN: sb=M[m][k+1].sub;
- if(M[m][k+1].submenu) if(m>=3) {MOAN("BUG: menus too deep");}
- else{mp[m]=k;M[++m]=(menuline*)sb; c_put(screen,scrsave,ss); mp[m]=0;goto MENU;}
- if(fromKF) {
- for(i=0;i<gp_Cols;i++) CW[i]=' ';
- strcpy(CW,kf(sb).Subrname()); strcat(CW,": numerical argument?");
- i=strlen(CW); r=screen+(gp_Rows-1)*gp_Cols;
- Jerry.mc=0; c_put_color(r,CW,gp_Cols,Orange); p=r+i; q=p+1; u=1; v=0;
- Z: switch(i=getkey()) {
- case -pagedown: case -lbutton: if(p+1<q) A=val(u*v); break;
- case '0'...'9': if(q<p+30){v=v*10+i-'0';q.push(i+256*Cyan);} else beep();
- goto Z;
- case '+': u=1; *p=256*Cyan; goto Z;
- case '-': u=-1; *p='-'+256*Cyan; goto Z;
- case 8: if(p+1<q) {*q=256*Cyan; q+=(-1); v/=10;} goto Z;
- case -alt_end: case -end_: case -mbutton: case -rbutton:
- c_put(screen,scrsave,ss); goto MENU;
- default: beep(); goto Z;}}
- c_put(screen,scrsave,ss);
- if(fromKF) {thisstep.f=kf(sb); thisstep.N=A; sb(A,val(0,0),val(0,0));}
- Jerry=MS; return kf(sb).Subrinfo();}
- /*-----*/
- KF(menu){subrmenu(T1.s,1);}
- /*-----*/
- KF(menu2){subrmenu(T1.s,2);}
-