|
- /* VIM.C - A SMALL MODAL EDITOR FOR THE COMMODORE 64, WRITTEN FOR POWER C.
*
* ÉNCREMENT 2 EDITS: IT READS A PETSCII ÓÅÑ FILE INTO ONE BUFFER, KEEPS A LINE
* INDEX, SHOWS 24 LINES PLUS A STATUS ROW, AND SUPPORTS
* MOVE H J K L / ARROWS, 0 $ GG Ç
* INSERT I A Á É O Ï (ÒÕÎ/ÓÔÏÐ LEAVES INSERT MODE, ÄÅÌ BACKSPACES)
* CHANGE X DD P
* COLON :W :W NAME :WQ :X :Q :Q!
*
* ÔHE BUFFER HOLDS THE FILE EXACTLY AS IT SITS ON DISK: PETSCII BYTES WITH $0D
* BETWEEN LINES. ËEYS ARE COMPARED AS NUMBERS, NEVER AS CHARACTER CONSTANTS,
* SO NOTHING DEPENDS ON HOW THE COMPILER TREATS LITERALS. (ÕNSHIFTED LETTERS
* ARRIVE AS $41-$5A, SO H = 72; SHIFTED ONES AS $C1-$DA, SO Ç = 199.)
*/
CHAR *MALLOC();
CHAR *BFR; /* FILE TEXT, $0D SEPARATED */
UNSIGNED BLEN; /* BYTES USED */
UNSIGNED LPTR[600]; /* OFFSET OF EACH LINE START */
INT NLINES;
INT CY, CX; /* CURSOR LINE AND COLUMN */
INT TOP; /* FIRST LINE ON SCREEN */
INT LEFTCOL; /* HORIZONTAL SCROLL */
CHAR FNAME[24];
INT MODE; /* 0 NORMAL, 1 INSERT */
INT DIRTY; /* BUFFER CHANGED SINCE THE LAST SAVE */
INT PEND; /* FIRST KEY OF A TWO KEY COMMAND: D OR G */
CHAR *NOTE; /* ONE-SHOT MESSAGE FOR THE STATUS ROW */
CHAR YBUF[160]; /* THE YANKED LINE */
INT YLEN, YOK;
INT REDRAW; /* 1 CURSOR ROW, 2 WHOLE SCREEN */
/* SCREEN ROWS ARE 0..23, THE STATUS ROW IS 24 */
/* SHORTEN FNAME TO WHAT FITS */
SHORTN(N)
INT N;
Û
INT I;
I = 0;
WHILE (FNAME[I] && I < N) I++;
FNAME[I] = 0;
RETURN 0;
Ý
/* A MESSAGE THAT WAITS FOR A KEY */
MSG(S)
CHAR *S;
Û
SCLR(24, 0, 40);
SPS(24, 0, S);
SKEY();
RETURN 0;
Ý
/* READ A LINE OF LOWERCASE PETSCII INTO S, ECHOED FROM COLUMN C OF ROW 24 */
GETLN(C, S, MAX)
INT C, MAX;
CHAR *S;
Û
INT N, K;
N = 0;
S[0] = 0;
FOR (;;) Û
K = SKEY();
IF (K == 13) BREAK;
IF (K == 3) Û
N = 0;
S[0] = 0;
BREAK;
Ý
IF (K == 20) Û
IF (N > 0) Û
N--;
S[N] = 0;
Ý
Ý ELSE Û
IF (K >= 0XC1 && K <= 0XDA) K = K - 0X80;
IF (K >= 32 && K != 127 && N < MAX) Û
S[N] = K;
N++;
S[N] = 0;
Ý
Ý
SCLR(24, C, MAX);
SPS(24, C, S);
Ý
RETURN N;
Ý
/* A YES/NO QUESTION ON THE STATUS ROW: 1 FOR Y, 0 FOR N OR RUN/STOP */
ASKYN(Q)
CHAR *Q;
Û
INT K;
SCLR(24, 0, 40);
SPS(24, 0, Q);
FOR (;;) Û
K = SKEY();
IF (K == 89) RETURN 1; /* Y */
IF (K == 217) RETURN 1; /* Ù */
IF (K == 78) RETURN 0; /* N */
IF (K == 206) RETURN 0; /* Î */
IF (K == 3) RETURN 0;
Ý
Ý
/* ASK WHICH FILE TO OPEN */
ASKNAME()
Û
SCLR(24, 0, 40);
SPS(24, 0, "FILE: ");
IF (GETLN(6, FNAME, 20) == 0) FNAME[0] = 0;
RETURN 0;
Ý
/* THE DRIVE'S ERROR CHANNEL (ALREADY OPEN AS FILE 15): THE TWO DIGIT CODE OF
THE LAST COMMAND. 0-19 ARE FINE ("00, OK"), 62 IS FILE NOT FOUND. OPEN() OF
A MISSING FILE SUCCEEDS ON A CBM DRIVE - ONLY THE ERROR CHANNEL TELLS.
DO NOT CLOSE 15 WHILE ANOTHER FILE IS OPEN: CLOSING THE COMMAND CHANNEL
CLOSES EVERY FILE ON THE DRIVE. */
DOSST()
Û
INT CH, N, D;
N = 0;
D = 0;
FOR (;;) Û
CH = GETC(15);
IF (CH < 0) BREAK;
IF (CH == 13) BREAK;
IF (D < 2) Û
IF (CH >= 48 && CH <= 57) Û
N = N * 10 + CH - 48;
D++;
Ý
Ý
Ý
IF (D < 2) RETURN 99;
RETURN N;
Ý
INT SPLIT; /* A LONG LINE WAS SPLIT ON LOAD */
/* READ FNAME INTO BFR. 1 ON SUCCESS, 0 IF THE FILE IS NOT THERE.
LINES LONGER THAN 80 ARE SPLIT - THE EDITOR'S LINE LIMIT */
LOADF()
Û
INT F, CH, PREV, C, COL;
CHAR ON[28];
INT I;
IF (FNAME[0] == 0) RETURN 1;
I = 0;
WHILE (FNAME[I] && I < 20) Û
ON[I] = FNAME[I];
I++;
Ý
ON[I++] = 44; /* , */
ON[I++] = 83; /* Ó (PETSCII, NOT ASCII) */
ON[I++] = 44; /* , */
ON[I++] = 82; /* Ò */
ON[I] = 0;
IF (OPEN(15, 8, 15, "") == 0) RETURN 0; /* STATUS CHANNEL FIRST */
F = OPEN(5, 8, 2, ON);
IF (F == 0) Û
CLOSE(15);
RETURN 0;
Ý
IF (DOSST() >= 20) Û
CLOSE(5);
CLOSE(15);
RETURN 0;
Ý
BLEN = 0;
PREV = 0;
COL = 0;
SPLIT = 0;
FOR (;;) Û
CH = GETC(5);
IF (CH < 0) BREAK; /* END OF FILE */
IF (CH == 26) BREAK;
IF (CH == 10 && PREV == 13) Û /* CRLF SEEN AS TWO BYTES */
PREV = CH;
CONTINUE;
Ý
IF (CH == 13) C = 13;
ELSE IF (CH == 10) C = 13;
ELSE C = CH;
IF (C != 13 && COL >= 80) Û /* 80 COLUMNS AT MOST */
IF (BLEN < 18999) BFR[BLEN++] = 13;
COL = 0;
SPLIT = 1;
Ý
IF (BLEN < 18999) BFR[BLEN++] = C;
IF (C == 13) COL = 0;
ELSE COL++;
PREV = CH;
Ý
CLOSE(5);
CLOSE(15); /* LAST: IT CLOSES EVERYTHING */
RETURN 1;
Ý
/* FIND THE START OF EVERY LINE */
BUILDIDX()
Û
UNSIGNED I;
NLINES = 1;
LPTR[0] = 0;
FOR (I = 0; I < BLEN; I++) Û
IF (BFR[I] == 13) Û
IF (NLINES < 599) Û
LPTR[NLINES] = I + 1;
NLINES++;
Ý
Ý
Ý
RETURN 0;
Ý
/* THE ":" COMMAND LINE. RETURNS 1 WHEN THE EDITOR SHOULD QUIT */
DOSCMD()
Û
INT N, P, OK, QF;
CHAR CMD[24];
SCLR(24, 0, 40);
SPC(24, 0, 58); /* : */
N = GETLN(1, CMD, 20);
SCLR(24, 0, 40);
IF (N == 0) RETURN 0;
IF (CMD[0] == 81) Û /* Q, Q! */
IF (CMD[1] == 33) RETURN 1;
IF (DIRTY) Û
NOTE = "UNSAVED - :Q! QUITS";
RETURN 0;
Ý
RETURN 1;
Ý
OK = 0;
QF = 0;
P = 1;
IF (CMD[0] == 87) OK = 1; /* W, WQ, W NAME */
IF (CMD[0] == 88) Û /* X */
OK = 1;
QF = 1;
Ý
IF (OK == 0) Û
NOTE = "UNKNOWN COMMAND";
RETURN 0;
Ý
IF (CMD[0] == 87 && CMD[1] == 81) Û
QF = 1;
P = 2;
Ý
WHILE (CMD[P] == 32) P++;
IF (CMD[P]) Û
N = 0;
WHILE (CMD[P] && N < 20) FNAME[N++] = CMD[P++];
FNAME[N] = 0;
Ý
IF (FNAME[0] == 0) Û
NOTE = "NO FILE NAME";
RETURN 0;
Ý
IF (SAVEF()) Û
DIRTY = 0;
NOTE = "WRITTEN";
RETURN QF;
Ý
NOTE = "CANNOT WRITE";
RETURN 0;
Ý
MAIN()
Û
INT K, OK, P;
SINIT();
MLINIT(); /* ÍÌ HELPERS TO $C000: BEFORE MALLOC */
BFR = MALLOC(19000);
IF (BFR == 0) Û
SPS(0, 0, "OUT OF MEMORY");
SKEY();
RETURN;
Ý
BLEN = 0;
NLINES = 1;
LPTR[0] = 0;
CY = 0;
CX = 0;
TOP = 0;
LEFTCOL = 0;
FNAME[0] = 0;
MODE = 0;
DIRTY = 0;
PEND = 0;
NOTE = 0;
YLEN = 0;
YOK = 0;
SPLIT = 0;
REDRAW = 2;
FOR (;;) Û /* A FILE TO EDIT */
ASKNAME();
SHORTN(20);
IF (FNAME[0] == 0) Û /* NO NAME: AN EMPTY BUFFER */
OK = 1;
BREAK;
Ý
OK = LOADF();
IF (OK) BREAK;
IF (ASKYN("NOT FOUND - CREATE IT? (Y/N) ")) BREAK;
Ý
BUILDIDX();
IF (OK == 0) Û /* KEEP THE NAME: :W CREATES IT */
NLINES = 1;
BLEN = 0;
NOTE = "NEW FILE";
Ý
IF (SPLIT) NOTE = "LONG LINES SPLIT AT 80";
FOR (;;) Û
SCROLL();
DALL();
K = SKEY();
NOTE = 0;
IF (MODE) Û /* ---- INSERT MODE */
IF (K == 3) Û /* ÒÕÎ/ÓÔÏÐ = ÅSC */
MODE = 0;
IF (CX > 0) CX--;
Ý ELSE IF (K == 13) Û
NEWLINE();
Ý ELSE IF (K == 20) Û
BKSPACE();
Ý ELSE IF (ARROW(K)) Û
CX = CX;
Ý ELSE IF (K >= 32 && K < 128) Û
INSCHAR(K);
Ý ELSE IF (K >= 161) Û
INSCHAR(K);
Ý
CONTINUE;
Ý
IF (PEND) Û /* ---- SECOND KEY OF DD / GG */
P = PEND;
PEND = 0;
IF (P == 68 && K == 68) DELLINE();
IF (P == 71 && K == 71) Û
CY = 0;
CX = 0;
Ý
CLAMPX();
CONTINUE;
Ý
IF (ARROW(K)) Û
CX = CX;
Ý ELSE IF (K == 72) Û /* H */
IF (CX > 0) CX--;
Ý ELSE IF (K == 76) Û /* L */
CX++;
CLAMPX();
Ý ELSE IF (K == 74) Û /* J */
ARROW(17);
Ý ELSE IF (K == 75) Û /* K */
ARROW(145);
Ý ELSE IF (K == 48) Û /* 0 */
CX = 0;
Ý ELSE IF (K == 36) Û /* $ */
CX = LINEND(CY) - LPTR[CY];
Ý ELSE IF (K == 199) Û /* Ç */
CY = NLINES - 1;
CX = 0;
Ý ELSE IF (K == 68) Û /* D.. */
PEND = 68;
Ý ELSE IF (K == 71) Û /* G.. */
PEND = 71;
Ý ELSE IF (K == 88) Û /* X */
DELCHAR();
CLAMPX();
Ý ELSE IF (K == 80) Û /* P */
PASTE();
Ý ELSE IF (K == 73) Û /* I */
MODE = 1;
Ý ELSE IF (K == 65) Û /* A */
CX++;
CLAMPX();
MODE = 1;
Ý ELSE IF (K == 193) Û /* Á */
CX = LINEND(CY) - LPTR[CY];
MODE = 1;
Ý ELSE IF (K == 201) Û /* É */
CX = 0;
MODE = 1;
Ý ELSE IF (K == 79) Û /* O */
CX = LINEND(CY) - LPTR[CY];
NEWLINE();
MODE = 1;
Ý ELSE IF (K == 207) Û /* Ï */
CX = 0;
NEWLINE();
CY--;
MODE = 1;
Ý ELSE IF (K == 58) Û /* : */
IF (DOSCMD() == 1) Û
SDONE();
RETURN;
Ý
Ý
Ý
Ý
|