//---------------------------------------------------------------------- // e3.c v0.92 Copyright (C) 2000 Albrecht Kleine // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // adapted to mipsel (fritz box fon): 2005-08 C.O. (Christian Ostheimer) //--------------------------------------------------------------------- #ifndef __GNUC__ #error "Sorry, but I need GNU C." #endif #ifndef MAX_TEXTSIZE #define MAX_TEXTSIZE 10240000 // x86 pc #endif #define CURSORMGNT #define LESSWRITEOPS #ifdef LESSWRITEOPS #define LESSWRITEOPS_OR_CURSORMGNT #endif #ifdef CURSORMGNT #define LESSWRITEOPS_OR_CURSORMGNT #endif #include #include #include #include #include #include #include #include #include struct termios termios,orig; //--------------------------------------------------------------------- // // CONSTANT DATA AREA // #define lowest 0x3b unsigned char Ktable[]={ 0x45 - lowest, // ^K@ xlatb table for making pseudo-scancode 0x45 - lowest, // ^ka 45h points to an an offset in jumptab1 0x41 - lowest, // ^kb 41h for example points to KeyCtrlKB function offset 0x43 - lowest, // ^kc 0x5d - lowest, // ^kd 0x45 - lowest, // ^ke 45h means SimpleRet i.e. 'do nothing' 0x45 - lowest, // ^kf 0x45 - lowest, // ^kg 0x57 - lowest, // ^kh 0x45 - lowest, // ^ki 0x45 - lowest, // ^kj 0x42 - lowest, // ^kk 0x45 - lowest, // ^kl 0x45 - lowest, // ^km 0x45 - lowest, // ^kn 0x45 - lowest, // ^ko 0x45 - lowest, // ^kp 0x46 - lowest, // ^kq 0x3d - lowest, // ^kr 0x5c - lowest, // ^ks 0x45 - lowest, // ^kt 0x45 - lowest, // ^ku 0x3b - lowest, // ^kv 0x3e - lowest, // ^kw 0x44 - lowest, // ^kx 0x4e - lowest, // ^ky 0x45 - lowest}; // ^kz unsigned char Qtable[]={ 0x45 - lowest, // ^q@ ditto for ^Q menu 0x54 - lowest, // ^qa 0x5a - lowest, // ^qb 0x61 - lowest, // ^qc former 76h ctrl-PageDown 0x4f - lowest, // ^qd 0x58 - lowest, // ^qe 0x55 - lowest, // ^qf 0x45 - lowest, // ^qg 0x4a - lowest, // ^qh, ^qDEL 0x62 - lowest, // ^qi 0x45 - lowest, // ^qj 0x5b - lowest, // ^qk 0x45 - lowest, // ^ql 0x45 - lowest, // ^qm 0x45 - lowest, // ^qn 0x45 - lowest, // ^qo 0x4c - lowest, // ^qp 0x45 - lowest, // ^qq 0x63 - lowest, // ^qr former ctrl-PageUp 0x47 - lowest, // ^qs 0x45 - lowest, // ^qt 0x45 - lowest, // ^qu 0x56 - lowest, // ^qv 0x5e - lowest, // ^qw former 73h ctrl-left 0x59 - lowest, // ^qx 0x40 - lowest, // ^qy 0x5f - lowest}; // ^qz former 74h ctrl-right // Using terminals the F-keys are not yet supported (was DOS only). //------ char filename[] =" NAME:"; char filesave[] =" SAVE:"; char asksave[] ="SAVE? Y/N"; char block[] ="BLK NAME:"; char askfind[] ="^QF FIND:"; char askreplace1[] ="^QA REPL:"; char askreplace2[] ="^QA WITH:"; char asklineno[] ="^QI LINE:"; char optiontext[] ="OPT? C/B"; #define stdtxtlen 10 char screencolors0[]={27,'[','4','0','m',27,'[','3','7','m',27,'[','0','m'}; // pointer pbold0 instead of array bold0[] to avoid alignment issue on mipsel // (content of bold0[] is now appended to screencolors0, C.O.) char * pbold0=screencolors0 + 10; // reset to b/w; char screencolors1[]={27,'[','4',/*'4'*/'1','m',27,'[','3','3','m',27,'[','1','m',27,'[','7','m'}; // yellow on red /*blue*/ char * pbold1=screencolors1 + 10; // bold #define preversevideoX pbold1 // good for "linux" terminal on /dev/tty (but not xterm,kvt) #define scolorslen 14 #define boldlen 4 // take care length of bold0 == length of bold1 //#define O_WRONLY_CREAT_TRUNC 01101 #define O_WRONLY_CREAT_TRUNC (O_WRONLY | O_CREAT | O_TRUNC) #define PERMS 0644 char resfile[]=LIBDIR"/e3.res"; char helpfile[]=LIBDIR"/e3ws.hlp"; #define TAB 8 #define TABCHAR 0x9 // ^I #define SPACECHAR ' ' #define CHANGED '*' #define UNCHANGED SPACECHAR #define LINEFEED 0xa #define NEWLINE LINEFEED //--------------------------------------------------------------------- unsigned char screenbuffer [62*(160+32)]; // estimated 62 lines 160 columns, 32 byte ESC seq (ca.12k) #define screenbuffer_end screenbuffer[62*(160+32)] // If you really have higher screen resolution, // ...no problem, except some useless redrawing happens. #define winsize_size 8 unsigned char winsize [winsize_size]; #define setkplen 10 unsigned char setkp [setkplen]; // to store cursor ESC seq like db 27,'[000;000H' long revvoff; long lines; // equ 24 or similar i.e. screen lines-1 (1 for statusline) long columns; // equ 80 or similar dword (using only LSB) long columne; // helper for display of current column long zloffst; // helper: chars scrolled out at left border long fileptr; // helper for temp storage of current pos in file long kurspos; // cursor position set by DispNewScreen() long kurspos2; // cursor position set by other functions long tabcnt; // longernal helper byte in DispNewScreen() only long changed; // status byte: (UN)CHANGED long oldQFpos; long bereitsges; // byte used for ^L long blockbegin; long blockende; long endeedit; // byte controls program exit long old; // helper for ^QP long veryold; // ditto long linenr; // current line long showblock; // helper for ^KH long suchlaenge; // helper for ^QA,^QF long repllaenge; long vorwarts; long grossklein; // helper byte for ^QF,^QA long ch2linebeg; // helper keeping cursor pos max at EOL (up/dn keys) long numeriere; // byte controls re-numeration long read_b; // buffer for getchar long isbold; // control of bold display of ws-blocks long inverse; long insstat; #define errlen 100 unsigned char error [errlen]; // reserved space for string: 'ERROR xxx:tttteeeexxxxtttt',0 long maxlen; #define maxfilenamelen 255 unsigned char filepath [maxfilenamelen+1]; unsigned char bakpath [maxfilenamelen+1]; unsigned char blockpath [maxfilenamelen+1]; unsigned char replacetext [maxfilenamelen+1]; unsigned char suchtext [maxfilenamelen+1]; #define optslen 8 unsigned char optbuffer [optslen]; // buffer for search/replace options and for ^QI long uid; long gid; long perms; struct stat fstatbuf; unsigned char screenline [256+4*scolorslen]; // max possible columns + 4 color ESC seq per line // (buffer for displaying a text line) #define errbufsize 4000 unsigned char errmsgs [errbufsize]; //------ #define max MAX_TEXTSIZE unsigned char text [max]; #define sot (text+1) // start-of-text //--------------------------- END OF DATA SECTION --------------------- long stack[100]; #define RETURN goto *(*esp--) #define CALL(calladr,retadr) *++esp=(long)&&_loc##retadr; goto calladr; _loc##retadr: #define PUSH(arg) *++esp=arg #define POP(arg) (long*)arg=*esp-- int main(int argc,char**argv,char **envp) { long eax=0,ecx=0,edx=0,ebx=0,edi=0,esi=0,extra=0,extra2=0,parm; long *esp=stack; unsigned char *ebp=0; #define jumps1 0x29 static void* jarray[]={ &&KeyCtrlKV, // 3bh ^KV F1 (DOS only) &&KeyCtrlL, // 3ch ^L F2 (ditto) &&KeyCtrlKR, // 3dh ^KR F3 (etc) &&KeyCtrlKW, // 3eh ^KW &&KeyCtrlT, // 3fh ^T &&KeyCtrlQY, // 40h ^QY &&KeyCtrlKB, // 41h ^KB &&KeyCtrlKK, // 42h ^KK &&KeyCtrlKC, // 43h ^KC &&KeyCtrlKX, // 44h ^KX F10 &&SimpleRet, // 45h F11 &&KeyCtrlKQ, // 46h F12 &&KeyHome, // 47h &&KeyUp, // 48h &&KeyPgUp, // 49h &&KeyCtrlQDel, // 4ah ^QDel &&KeyLeft, // 4bh &&KeyCtrlQP, // (5 no num lock) &&KeyRight, // 4dh &&KeyCtrlKY, // (+) ^KY &&KeyEnd, // 4fh &&KeyDown, // 50H &&KeyPgDn, // 51h &&KeyIns, // 52H &&KeyDel, // 53H &&KeyCtrlQA, // 54h ^QA sF1 &&KeyCtrlQF, // 55h ^QF sf1 &&KeyCtrlQV, // 56h &&KeyCtrlKH, // 57h &&KeyCtrlQE, // 58h &&KeyCtrlQX, // 59h &&KeyCtrlQB, // 5Ah ^QB &&KeyCtrlQK, // 5Bh ^QK sF8 &&KeyCtrlKS, // 5ch ^KS sF9 &&KeyCtrlKD, // 5dh ^KD sF10 &&KeyCtrlLeft, // 5eh ^Left was 73h (compare notes above) &&KeyCtrlRight, // 5fh ^Right (was 74h) &&SimpleRet, // 60h ^End (was 75h) &&KeyCtrlQC, // 61h ^PageDown (was 76h) &&KeyCtrlQI, // 62h ^Home (was 77h) &&KeyCtrlQR, // 63h ^PageUp (was 84h) // jumps1......= 29h &&SimpleRet, // ^@ (only former DOS version has a "jumptab2") &&KeyHome, // ^a (compare notes above) &&SimpleRet, // ^b &&KeyPgDn, // ^c &&KeyRight, // ^d &&KeyUp, // ^e &&KeyEnd, // ^f &&KeyDel, // ^g 7 &&KeyDell, // ^h 8 DEL (7fh is translated to this) &&NormChar, // ^i 9 &&KeyRet, // ^j = 0ah &&CtrlKMenu, // ^k b &&KeyCtrlL, // ^l c &&SimpleRet, // ^m 0dh &&SimpleRet, // ^n e &&SimpleRet, // ^o f &&SimpleRet, // ^p 10 &&CtrlQMenu, // ^q 11 &&KeyPgUp, // ^r 12 &&KeyLeft, // ^s 13 &&KeyCtrlT, // ^t 14 &&SimpleRet, // ^u 15 &&KeyIns, // ^v 16 &&SimpleRet, // ^w 17 &&KeyDown, // ^x 18 &&KeyCtrlY, // ^y 19 &&SimpleRet, // ^z &&SimpleRet // esc }; CALL(SetTermStruc,0); CALL(ReadResource,1); esi=(long)*++argv; #ifdef CURSORMGNT if (!strcmp(getenv("TERM"),"linux")) revvoff+=boldlen; // special inverse cursor on linux terminals #endif //------ do { CALL(NewFile,2); if (extra) break; do { CALL(DispNewScreen,3); CALL(RestoreStatusLine,4); CALL(HandleChar,5); } while (!endeedit); esi=0; // just like if no arg is present } while (endeedit==2); // ^KD repeat edit using another file //------ CALL(KursorStatusLine,6); ecx = (long)&text; // enter next line on terminal NEWLINE is @ byte [text] edx=1; CALL(WriteFile0,7); eax = (long)&orig; CALL(SetTermStruc2,8); // restore termios settings goto Exit; //--------------------------------------------------------------------- // MAIN function for processing keys // HandleChar:CALL(ReadChar,9); if (!eax) goto CompJump2; // eax=0 for cursor keys if (eax>=0x1c) goto NormChar; ebx = eax+jumps1; goto CompJump2; NormChar:CALL(CheckMode,10); if (!extra) goto OverWriteChar; PUSH(eax); eax=1; CALL(InsertByte,11); POP(eax); if (extra) goto InsWriteEnd; // error: text buffer full OverWriteChar:*(unsigned char*)edi++=eax; changed = CHANGED; InsWriteEnd:RETURN; //------ // // helper for HandleChar // CtrlKMenu:ebx = (long)&Ktable; ecx = 0x20204b5e; // ^K goto Menu; CtrlQMenu:ebx = (long)&Qtable; ecx = 0x2020515e; // ^Q Menu: CALL(MakeScanCode,12); if (eax>=27) goto EndeRet; // if no valid scancode CompJump2:ebx=(long)jarray[(int)ebx]; //------ CALL(*ebx,13); // the general code jump dispatcher //------ if (numeriere) { PUSH(edi); esi=edi; edi = (long)(sot); linenr=0; do { linenr++; CALL(LookForward,14); ++edi; // point to start of next line } while ((unsigned long)edi<=(unsigned long)esi); POP(edi); } numeriere = 0; RETURN; //------ MakeScanCode:CALL(WriteTwo,15); // ebx expects xlat-table PUSH(ebx); CALL(GetChar,16); POP(ebx); eax&=0x1f; if (eax>=27) goto EndeRet; ebx=*((unsigned char*)(ebx+eax)); // returns pseudo "scancode" in ebx EndeRet:RETURN; // exception: ok=cy here //--------------------------------------------------------------------- // // processing special keys: cursor, ins, del // KeyRet: CALL(CheckMode,17); if (!extra) goto OvrRet; CALL(CountToLineBegin,18); // set esi / returns eax ++esi; ++esi; if (!eax) goto KeyRetNoIndent; eax=-1; KeyRetSrch:++eax; // search non (SPACE or TABCHAR) if (*(unsigned char*)(esi+eax)==SPACECHAR) goto KeyRetSrch; if (*(unsigned char*)(esi+eax)==TABCHAR) goto KeyRetSrch; KeyRetNoIndent: PUSH(esi); PUSH(eax); // eax is 0 or =indented chars CALL(GoDown,19); POP(eax); PUSH(eax); ++eax; // 1 extra for 0ah CALL(InsertByte,20); POP(ecx); // # blanks POP(esi); // where to copy if (extra) goto SimpleRet; ++linenr; *(unsigned char*)edi++=NEWLINE; if (ecx) do { *(unsigned char*)edi++=*(unsigned char*)esi++; } while (--ecx); // copy upper line i.e. SPACES,TABS into next SimpleRet:RETURN; OvrRet: eax=0; ch2linebeg = eax; goto DownRet; //------ KeyDown:CALL(CountColToLineBeginVis,21); DownRet:CALL(GoDown,22); CALL(LookLineDown,23); goto SetColumn; //------ KeyUp: CALL(GoUp,24); CALL(CountColToLineBeginVis,25); CALL(LookLineUp,26); goto SetColumn; //------ KeyPgUp:CALL(CountColToLineBeginVis,27); CALL(LookPageUp,28); goto SetColumn; //------ KeyPgDn:CALL(CountColToLineBeginVis,29); CALL(LookPgDown,30); // 1st char last line //------ SetColumn:ecx = ch2linebeg; // maximal columns edx=0; // counts visible columns i.e. expand TABs --edi; SCloop: ++edi; if (edx>=ecx) goto SCret; if (*(unsigned char*)edi==NEWLINE) goto SCret; // don't go beyond line earlier line end if (*(unsigned char*)edi==TABCHAR) goto SCtab; ++edx; // count columns goto SCloop; SCtab: edx+= (TAB - edx % TAB); // spaces for Tab: if (edx<=ecx) goto SCloop; // this tab to far away right? no SCret: RETURN; //------ KeyHome:CALL(CountToLineBegin,32); edi-=eax; RETURN; //------ KeyEnd: CALL(CountToLineEnd,33); edi+=eax; // points to a 0ah char RETURN; //------ KeyIns: insstat = !insstat; RETURN; //------ KeyDell:CALL(KeyLeft,34); if (extra) goto KeyDell2; KeyDel: if ((unsigned long)edi>=(unsigned long)ebp) goto KeyLeftEnd; eax=1; // delete one @ cursor goto DeleteByte; KeyDell2:if ((unsigned long)edi<=(unsigned long)sot) goto KeyLeftEnd; --linenr; --edi; goto KeyCtrlT1; //------ KeyLeft:if ((((unsigned char*)edi)[-1]) != NEWLINE) { --edi; extra=0; } else extra=1; KeyLeftEnd:RETURN; //------ KeyRight:if (*(unsigned char*)edi != NEWLINE) { ++edi; extra=0; } else extra=1; RETURN; //------ KeyCLeft3:if ((unsigned long)edi<=(unsigned long)(sot)) goto KeyCLEnd; --edi; KeyCtrlLeft:CALL(KeyLeft,35); if (extra) goto KeyCLeft3; if (*(unsigned char*)edi <= 0x2f) goto KeyCtrlLeft; if (((unsigned char*)edi)[-1] > 0x2f) goto KeyCtrlLeft; KeyCLEnd:RETURN; //------ KeyCRight3:CALL(CheckEof,36); if (extra) goto KeyCREnd; ++edi; KeyCtrlRight:CALL(KeyRight,37); if (extra) goto KeyCRight3; if (*(unsigned char*)edi <= 0x2f) goto KeyCtrlRight; if (((unsigned char*)edi)[-1] > 0x2f) goto KeyCtrlRight; KeyCREnd:RETURN; //--------------------------------------------------------------------- // // processing special keys from the Ctrl-Q menu // KeyCtrlQE:CALL(LookPgBegin,38); // goto top left on screen CALL(KursorFirstLine,39); goto CQFNum; //------ KeyCtrlQX:CALL(LookPgEnd,40); // 1st goto last line on screen CALL(KeyEnd,41); // 2nd goto line end CALL(KursorLastLine,42); goto CQFNum; //------ KeyCtrlQV:if (!bereitsges) goto CtrlQFEnd; // goto last ^QA,^QF pos edi = oldQFpos; goto CQFNum; //------ KeyCtrlQA:bereitsges = 2; CALL(AskForReplace,43); if (extra) goto CtrlQFEnd; CQACtrlL:PUSH(edi); CALL(FindText,44); if (!extra) goto CtrlQFNotFound; eax = suchlaenge; CALL(DeleteByte,45); eax = repllaenge; CALL(InsertByte,46); esi = (long)&replacetext; CALL(MoveBlock,47); goto CQFFound; //------ KeyCtrlQF:bereitsges = 1; CALL(AskForFind,48); if (extra) goto CtrlQFEnd; CQFCtrlL:PUSH(edi); CALL(FindText,49); if (!extra) goto CtrlQFNotFound; CQFFound:oldQFpos = edi; POP(esi); // dummy CQFNum: numeriere = 1; RETURN; CtrlQFNotFound:POP(edi); CtrlQFEnd:RETURN; //------ KeyCtrlQC:edi = (long)ebp; goto CQFNum; //------ KeyCtrlQR:edi = (long)sot; goto CQFNum; //------ KeyCtrlQP:ecx = veryold; if ((unsigned long)ecx>(unsigned long)ebp) goto SimpleRet4; edi=ecx; //------ KeyCtrlL:if (bereitsges==2) goto CQACtrlL; if (bereitsges==1) goto CQFCtrlL; SimpleRet4:RETURN; //------ KeyCtrlQB:eax=edi; edi = blockbegin; CtrlQB2:if (edi) goto CQFNum; edi=eax; // exit if no marker set RETURN; //------ KeyCtrlQK:eax=edi; edi = blockende; goto CtrlQB2; //------ KeyCtrlQI:CALL(GetAsciiToInteger,50); if (!ecx) goto SimpleRet4; edi = (long)sot; CALL(LookPD2,51); JmpCQFN:goto CQFNum; //------ KeyCtrlQDel:CALL(KeyLeft,52); // delete all left of cursor CALL(CountToLineBegin,53); edi-=eax; CALL(DeleteByteCheckMarker,54); goto KeyCtrlT1; //------ KeyCtrlQY:CALL(CountToLineEnd,55); goto CtrlTEnd1; //------ KeyCtrlY:CALL(CountToLineBegin,56); edi-=eax; // edi at begin CALL(CountToLineEnd,57); CALL(DeleteByteCheckMarker,58); goto KeyCtrlT1; //------ KeyCtrlT:CALL(CountToWordBegin,59); if (*(unsigned char*)edi != NEWLINE) goto CtrlTEnd1; KeyCtrlT1:CALL(CheckEof,60); if (extra) goto SimpleRet4; eax=1; // 1 for 0ah CtrlTEnd1:goto DeleteByteCheckMarker; //--------------------------------------------------------------------- // // processing special Keys from Ctrl-K menu // KeyCtrlKY:CALL(CheckBlock,61); if (extra) goto SimpleRet3; // no block: no action eax = blockende; edi = esi; // esi is blockbegin (side effect in CheckBlock) eax-=esi; // block length CALL(DeleteByte,62); // out ecx:=0 blockende = ecx; // i.e. NO block valid now blockbegin = ecx; goto JmpCQFN; //------ KeyCtrlKH:showblock^=1; // flip flop SimpleRet3:RETURN; //------ KeyCtrlKK:blockende = edi; goto KCKB; //------ KeyCtrlKW:CALL(CheckBlock,63); if (extra) goto SimpleRet2; // no action CALL(SaveBlock,64); goto CtrlKREnd; //------ KeyCtrlKC:CALL(CopyBlock,65); if (extra) goto SimpleRet2; CtrlKC2:blockbegin = edi; blockende = eax+edi; RETURN; //------ KeyCtrlKV:CALL(CopyBlock,66); if (extra) goto SimpleRet2; PUSH(edi); extra=0; if ((unsigned long)edi<(unsigned long)blockbegin) extra++; PUSH(extra); edi = blockbegin; CALL(DeleteByte,67); eax = -eax; // (for optimizing eax is negated there) POP(extra); POP(edi); if (extra) goto CtrlKC2; blockende = edi; edi-=eax; KeyCtrlKB:blockbegin = edi; KCKB: showblock = 1; SimpleRet2:RETURN; //------ KeyCtrlKR:CALL(ReadBlock,68) if (extra) goto CtrlKREnd; CALL(KeyCtrlKB,69); ecx+=edi; blockende = ecx; CtrlKREnd:goto RestKursPos; //------ KeyCtrlKS:CALL(SaveFile,70); // (called by ^kd) PUSH(extra); CALL(RestKursPos,71); POP(extra); if (extra) goto CtrlKSEnd; changed = UNCHANGED; CtrlKSEnd:RETURN; //------ KeyCtrlKQ:if (changed==UNCHANGED) goto KCKXend; esi = (long)&asksave; CALL(DE1,72); CALL(RestKursPos,73); eax&=0xdf; if (eax !='Y') goto KCKXend; // Y for request SAVE changes KeyCtrlKX:CALL(KeyCtrlKS,74); if (extra) goto CtrlKSEnd; KCKXend:++endeedit; KeyKXend:RETURN; KeyCtrlKD:CALL(KeyCtrlKS,75); if (extra) goto CtrlKSEnd; endeedit = 2; RETURN; //-------------------------------------------------------------------- // // the general PAGE DISPLAY function: called after any pressed key // // side effect: sets 'columne' for RestoreStatusLine function (displays columne) // variable kurspos: for placing the cursor at new position // register extra2 counts lines // register ebx counts columns visible on screen (w/o left scrolled) // register edx counts columns in text lines // register ecx screen line counter and helper for rep stos // register esi text index // register edi screen line buffer index // DispNewScreen:CALL(GetEditScreenSize,76); // check changed tty size isbold = 0; inverse = 0; zloffst = 0; columne = 0; fileptr = edi; // for seeking current cursor pos CALL(CountColToLineBeginVis,77);// i.e. expanding TABs ebx = columns; if (eax