Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>main
| @@ -0,0 +1,71 @@ | |||||
| @echo off | |||||
| setlocal | |||||
| REM ------------------------------------------------------------------ | |||||
| REM Build the vim editor with Spinnaker Power C on a private copy of | |||||
| REM the system disk at ..\reference\POWERc.d81. | |||||
| REM | |||||
| REM The editor is two source files because Power C's compiler reports | |||||
| REM "program too big" when the whole thing is one unit; both objects | |||||
| REM are linked into vim. | |||||
| REM | |||||
| REM Power C is interactive: "cc" asks for the source, compiler and | |||||
| REM object disks, and "link" prompts for object files, the "^" library | |||||
| REM line and the output file name. -keybuf answers all of it; the runs | |||||
| REM of \n are those prompts. -keybuf-delay spaces the answers out: fed | |||||
| REM all at once they land before the later disk prompts appear and are | |||||
| REM lost, which leaves cc waiting for the object disk. | |||||
| REM ------------------------------------------------------------------ | |||||
| set "VICE=C:\Program Files\GTK3VICE-3.10-win64\bin" | |||||
| set "HERE=%~dp0" | |||||
| set "BASE=%HERE%..\reference\POWERc.d81" | |||||
| set "IMG=%HERE%vim.d81" | |||||
| if not exist "%VICE%\x64sc.exe" goto novice | |||||
| if not exist "%BASE%" goto nobody | |||||
| echo === fresh work disk | |||||
| copy /y "%BASE%" "%IMG%" >nul | |||||
| echo === ASCII source -^> PETSCII | |||||
| powershell -NoProfile -ExecutionPolicy Bypass -File "%HERE%to-petscii.ps1" "%HERE%vim.c" "%HERE%vim.pet" | |||||
| if errorlevel 1 goto bad | |||||
| powershell -NoProfile -ExecutionPolicy Bypass -File "%HERE%to-petscii.ps1" "%HERE%vscreen.c" "%HERE%vscreen.pet" | |||||
| if errorlevel 1 goto bad | |||||
| echo === write both sources to the disk | |||||
| for %%f in (vim.c vim.o vscreen.c vscreen.o vim) do "%VICE%\c1541.exe" "%IMG%" -delete %%f >nul 2>&1 | |||||
| "%VICE%\c1541.exe" "%IMG%" -write "%HERE%vim.pet" "vim.c,s" >nul | |||||
| if errorlevel 1 goto bad | |||||
| "%VICE%\c1541.exe" "%IMG%" -write "%HERE%vscreen.pet" "vscreen.c,s" >nul | |||||
| if errorlevel 1 goto bad | |||||
| echo === cc vim.c (a minute or so in warp mode) | |||||
| "%VICE%\x64sc.exe" -8 "%IMG%" -autostart "%IMG%:shell" -autostart-warp -warp -sounddev dummy -keybuf-delay 300 -keybuf "cc vim.c\n\n\n\n\n\n\n\n\n\n\n\n" -limitcycles 600000000 | |||||
| echo === cc vscreen.c | |||||
| "%VICE%\x64sc.exe" -8 "%IMG%" -autostart "%IMG%:shell" -autostart-warp -warp -sounddev dummy -keybuf-delay 300 -keybuf "cc vscreen.c\n\n\n\n\n\n\n\n\n\n\n\n" -limitcycles 600000000 | |||||
| echo === link -s -^> vim | |||||
| "%VICE%\x64sc.exe" -8 "%IMG%" -autostart "%IMG%:shell" -autostart-warp -warp -sounddev dummy -keybuf-delay 300 -keybuf "link -s\nvim.o\nvscreen.o\n^\n\nvim\n\n\n" -limitcycles 600000000 | |||||
| del "%HERE%vim.pet" >nul 2>&1 | |||||
| del "%HERE%vscreen.pet" >nul 2>&1 | |||||
| echo === disk contents | |||||
| "%VICE%\c1541.exe" "%IMG%" -list | findstr /i "vim vscreen" | |||||
| echo. | |||||
| echo Run it with: | |||||
| echo x64sc -autostart "%IMG%:vim" | |||||
| exit /b 0 | |||||
| :novice | |||||
| echo x64sc.exe not found in "%VICE%" | |||||
| exit /b 1 | |||||
| :nobody | |||||
| echo %BASE% not found - is the repository complete? | |||||
| exit /b 1 | |||||
| :bad | |||||
| echo BUILD FAILED | |||||
| exit /b 1 | |||||
| @@ -0,0 +1,31 @@ | |||||
| # to-petscii.ps1 - convert an ASCII C source file into the PETSCII form | |||||
| # Power C expects on a C64 disk: uppercase letters shifted into $C1-$DA, | |||||
| # lowercase into $41-$5A, { } into $DB/$DD, and CR ($0D) line endings. | |||||
| # | |||||
| # Usage: | |||||
| # powershell -NoProfile -File to-petscii.ps1 vim.c vim.pet | |||||
| param( | |||||
| [Parameter(Mandatory = $true)][string]$InFile, | |||||
| [Parameter(Mandatory = $true)][string]$OutFile | |||||
| ) | |||||
| $bytes = [System.IO.File]::ReadAllBytes($InFile) | |||||
| $start = 0 | |||||
| if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) { | |||||
| $start = 3 # skip a UTF-8 BOM if an editor added one | |||||
| } | |||||
| $out = New-Object System.Collections.Generic.List[byte] | |||||
| for ($i = $start; $i -lt $bytes.Length; $i++) { | |||||
| $b = $bytes[$i] | |||||
| if ($b -eq 13) { continue } # CRLF -> single CR | |||||
| if ($b -eq 10) { $out.Add([byte]13); continue } | |||||
| if ($b -ge 0x61 -and $b -le 0x7A) { $out.Add([byte]($b - 0x20)); continue } # a-z | |||||
| if ($b -ge 0x41 -and $b -le 0x5A) { $out.Add([byte]($b + 0x80)); continue } # A-Z | |||||
| if ($b -ge 0x7B -and $b -le 0x7F) { $out.Add([byte]($b + 0x60)); continue } # { | } ~ -> $DB-$DF | |||||
| $out.Add([byte]$b) | |||||
| } | |||||
| [System.IO.File]::WriteAllBytes($OutFile, $out.ToArray()) | |||||
| Write-Host ("wrote {0} PETSCII bytes to {1}" -f $out.Count, $OutFile) | |||||
| @@ -0,0 +1,420 @@ | |||||
| /* vim.c - a small vi/vim-style screen editor for the Commodore 64 | |||||
| * | |||||
| * Core half of the program: text buffer, cursor motion, key handling | |||||
| * and saving. Drawing lives in vscreen.c because Power C's compiler | |||||
| * reports "program too big" when the whole editor is one unit. The two | |||||
| * halves share functions only - every piece of state stays private to | |||||
| * this file and is handed to draw() as arguments - because sharing | |||||
| * variables across Power C object files proved unreliable. | |||||
| * | |||||
| * Modal editing, like vi: | |||||
| * | |||||
| * COMMAND mode INSERT mode | |||||
| * i insert here any key type text | |||||
| * a append after char RETURN split the line | |||||
| * o open line below DEL backspace | |||||
| * O open line above RUN/STOP back to COMMAND mode | |||||
| * x delete character cursor keys move | |||||
| * h j k l or cursor keys CLR/HOME start of line | |||||
| * 0 start of line | |||||
| * $ end of line | |||||
| * : command line | |||||
| * | |||||
| * : commands | |||||
| * :w write "notes" to disk (SEQ file, drive 8) | |||||
| * :wq write and quit | |||||
| * :q quit | |||||
| * | |||||
| * Special C characters, on the same keys the Power C manual gives for ced: | |||||
| * | |||||
| * { SHIFT + } SHIFT - \ English pound key | |||||
| * ~ C= (logo) P _ C= (logo) @ | C= (logo) * | |||||
| * | |||||
| * The Kernal already produces the codes Power C expects for these | |||||
| * ($DB, $DD, $5C, $AF, $A4, $DF - read from the key tables at $EB81), | |||||
| * so insert mode only has to accept them. The character ROM has no | |||||
| * brace or bar glyphs, so on screen they appear as the nearest glyph. | |||||
| * | |||||
| * ESCAPE is the C64 RUN/STOP key, which the Kernal reports in the | |||||
| * zero-page STOP flag at $91. | |||||
| * | |||||
| * The text buffer holds 2000 bytes with 13 ($0D) as the line break. | |||||
| * Keys come from the Kernal keyboard buffer at $0277, count at $c6. | |||||
| * | |||||
| * Build with build.bat in this folder: | |||||
| * | |||||
| * cc vim.c -> vim.o | |||||
| * cc vscreen.c -> vscreen.o | |||||
| * link -s | |||||
| * > vim.o | |||||
| * > vscreen.o | |||||
| * > ^ (stdlib.l + syslib.l) | |||||
| * > | |||||
| * output file name: vim | |||||
| * | |||||
| * Then run with: x64sc -autostart "vim.d81:vim" | |||||
| * or from BASIC: LOAD"VIM",8,1 : RUN | |||||
| * | |||||
| * Note: this Power C build rejects both $7C and $DC as "illegal | |||||
| * character" for the | operator, so nested tests are used instead of ||. | |||||
| */ | |||||
| #include <stdio.h> | |||||
| static char text[2000]; /* document, 13 = line break */ | |||||
| static int tlen; /* bytes in use */ | |||||
| static int pos; /* cursor, byte offset into text */ | |||||
| static int mode; /* 0 command, 1 insert, 2 : prompt */ | |||||
| static char fname[17]; /* file name used by :w */ | |||||
| static char cmd[9]; /* text after the ':' */ | |||||
| static int cmdlen; | |||||
| static int quit; | |||||
| static int msgcode; /* message for draw(): 0 none, 1-4 */ | |||||
| static char *defnam = "notes"; | |||||
| /* ---------- provided by vscreen.c ---------- */ | |||||
| int draw(); | |||||
| int clrscr(); | |||||
| /* ---------- buffer helpers ---------- */ | |||||
| static lstart(n) /* offset of the first byte of line n */ | |||||
| int n; | |||||
| { | |||||
| int i; | |||||
| int c; | |||||
| if (n <= 0) return 0; | |||||
| c = 0; | |||||
| i = 0; | |||||
| while (i < tlen) { | |||||
| if (text[i] == 13) { | |||||
| c = c + 1; | |||||
| if (c == n) return i + 1; | |||||
| } | |||||
| i = i + 1; | |||||
| } | |||||
| return tlen; | |||||
| } | |||||
| static lcount() /* number of line breaks */ | |||||
| { | |||||
| int i; | |||||
| int c; | |||||
| c = 0; | |||||
| for (i = 0; i < tlen; i++) | |||||
| if (text[i] == 13) c = c + 1; | |||||
| return c; | |||||
| } | |||||
| static lnof() /* line holding the cursor */ | |||||
| { | |||||
| int i; | |||||
| int c; | |||||
| c = 0; | |||||
| for (i = 0; i < pos && i < tlen; i++) | |||||
| if (text[i] == 13) c = c + 1; | |||||
| return c; | |||||
| } | |||||
| static intend(o) /* offset of the line end */ | |||||
| int o; | |||||
| { | |||||
| int e; | |||||
| e = o; | |||||
| while (e < tlen && text[e] != 13) e = e + 1; | |||||
| return e; | |||||
| } | |||||
| static inschr(ch) | |||||
| int ch; | |||||
| { | |||||
| int i; | |||||
| if (tlen >= 1999) { | |||||
| msgcode = 1; | |||||
| return; | |||||
| } | |||||
| for (i = tlen; i > pos; i--) | |||||
| text[i] = text[i - 1]; | |||||
| text[pos] = ch; | |||||
| tlen = tlen + 1; | |||||
| pos = pos + 1; | |||||
| } | |||||
| static delat() | |||||
| { | |||||
| int i; | |||||
| if (pos >= tlen) return; | |||||
| for (i = pos; i < tlen - 1; i++) | |||||
| text[i] = text[i + 1]; | |||||
| tlen = tlen - 1; | |||||
| } | |||||
| static backsp() | |||||
| { | |||||
| if (pos <= 0) return; | |||||
| pos = pos - 1; | |||||
| delat(); | |||||
| } | |||||
| /* ---------- cursor motion ---------- */ | |||||
| static movleft() | |||||
| { | |||||
| if (pos > 0) pos = pos - 1; | |||||
| } | |||||
| static movright() | |||||
| { | |||||
| if (pos < tlen) pos = pos + 1; | |||||
| } | |||||
| static movdown() | |||||
| { | |||||
| int ln; | |||||
| int cs; | |||||
| int o; | |||||
| int e; | |||||
| ln = lnof(); | |||||
| if (ln + 1 > lcount()) return; | |||||
| cs = pos - lstart(ln); | |||||
| o = lstart(ln + 1); | |||||
| e = intend(o); | |||||
| pos = o + cs; | |||||
| if (pos > e) pos = e; | |||||
| } | |||||
| static movup() | |||||
| { | |||||
| int ln; | |||||
| int cs; | |||||
| int o; | |||||
| int e; | |||||
| ln = lnof(); | |||||
| if (ln <= 0) return; | |||||
| cs = pos - lstart(ln); | |||||
| o = lstart(ln - 1); | |||||
| e = intend(o); | |||||
| pos = o + cs; | |||||
| if (pos > e) pos = e; | |||||
| } | |||||
| static linehome() | |||||
| { | |||||
| pos = lstart(lnof()); | |||||
| } | |||||
| static lineend() | |||||
| { | |||||
| pos = intend(lstart(lnof())); | |||||
| } | |||||
| /* ---------- saving ---------- */ | |||||
| static savfil() | |||||
| { | |||||
| FILE *f; | |||||
| int i; | |||||
| f = fopen(fname, "w"); | |||||
| if (!f) { | |||||
| msgcode = 2; | |||||
| return; | |||||
| } | |||||
| if (ferror(f)) { | |||||
| msgcode = 2; | |||||
| fclose(f); | |||||
| return; | |||||
| } | |||||
| for (i = 0; i < tlen; i++) fputc(text[i], f); | |||||
| fclose(f); | |||||
| msgcode = 3; | |||||
| } | |||||
| /* ---------- : command line ---------- */ | |||||
| static docmd() | |||||
| { | |||||
| if (cmdlen == 0) return; | |||||
| if (cmd[0] == 'w') { | |||||
| if (cmdlen > 1 && cmd[1] == 'q') { | |||||
| savfil(); | |||||
| quit = 1; | |||||
| return; | |||||
| } | |||||
| savfil(); | |||||
| return; | |||||
| } | |||||
| if (cmd[0] == 'q') { | |||||
| quit = 1; | |||||
| return; | |||||
| } | |||||
| msgcode = 4; | |||||
| } | |||||
| /* ---------- key handlers ---------- */ | |||||
| static insk(k) | |||||
| int k; | |||||
| { | |||||
| if (k == 3) { /* ESC: leave insert mode */ | |||||
| mode = 0; | |||||
| if (pos > 0) pos = pos - 1; | |||||
| return; | |||||
| } | |||||
| if (k == 13) { inschr(13); return; } | |||||
| if (k == 20) { backsp(); return; } | |||||
| if (k == 157) { movleft(); return; } | |||||
| if (k == 29) { movright(); return; } | |||||
| if (k == 145) { movup(); return; } | |||||
| if (k == 17) { movdown(); return; } | |||||
| if (k == 19) { linehome(); return; } | |||||
| if (k >= 32 && k < 128) { inschr(k); return; } | |||||
| if (k == 219) { inschr(k); return; } /* SHIFT + : { */ | |||||
| if (k == 221) { inschr(k); return; } /* SHIFT - : } */ | |||||
| if (k == 223) { inschr(k); return; } /* logo * : | */ | |||||
| if (k == 175) { inschr(k); return; } /* logo P : ~ */ | |||||
| if (k == 164) { inschr(k); return; } /* logo @ : _ */ | |||||
| } | |||||
| static cmdk(k) | |||||
| int k; | |||||
| { | |||||
| if (k >= 65 && k <= 90) k = k + 32; /* letters arrive as PETSCII $41-$5A */ | |||||
| if (k == ':') { | |||||
| mode = 2; | |||||
| cmdlen = 0; | |||||
| cmd[0] = 0; | |||||
| return; | |||||
| } | |||||
| if (k == 'i') { mode = 1; return; } | |||||
| if (k == 'a') { | |||||
| if (pos < tlen && text[pos] != 13) pos = pos + 1; | |||||
| mode = 1; | |||||
| return; | |||||
| } | |||||
| if (k == 'o') { | |||||
| pos = intend(lstart(lnof())); | |||||
| inschr(13); | |||||
| mode = 1; | |||||
| return; | |||||
| } | |||||
| if (k == 'O') { | |||||
| pos = lstart(lnof()); | |||||
| inschr(13); | |||||
| pos = pos - 1; | |||||
| mode = 1; | |||||
| return; | |||||
| } | |||||
| if (k == 'x') { delat(); return; } | |||||
| if (k == 'h') { movleft(); return; } | |||||
| if (k == 157) { movleft(); return; } | |||||
| if (k == 'l') { movright(); return; } | |||||
| if (k == 29) { movright(); return; } | |||||
| if (k == 'j') { movdown(); return; } | |||||
| if (k == 17) { movdown(); return; } | |||||
| if (k == 'k') { movup(); return; } | |||||
| if (k == 145) { movup(); return; } | |||||
| if (k == '0') { linehome(); return; } | |||||
| if (k == 19) { linehome(); return; } | |||||
| if (k == '$') { lineend(); return; } | |||||
| } | |||||
| /* ---------- keyboard ---------- */ | |||||
| static getkey() /* one byte from the Kernal keyboard | |||||
| buffer, $0277, count at $c6 */ | |||||
| { | |||||
| char *cnt; | |||||
| char *buf; | |||||
| int i; | |||||
| int k; | |||||
| cnt = (char *) 198; | |||||
| buf = (char *) 631; | |||||
| if (*cnt == 0) return 0; | |||||
| if (*cnt > 10) { | |||||
| *cnt = 0; | |||||
| return 0; | |||||
| } | |||||
| k = buf[0]; | |||||
| for (i = 0; i < 9; i++) buf[i] = buf[i + 1]; | |||||
| *cnt = *cnt - 1; | |||||
| return k; | |||||
| } | |||||
| static waitkey() | |||||
| { | |||||
| char *stop; | |||||
| int k; | |||||
| for (;;) { | |||||
| stop = (char *) 145; /* $91: RUN/STOP flag */ | |||||
| if (*stop) { | |||||
| *stop = 0; | |||||
| return 3; | |||||
| } | |||||
| k = getkey(); | |||||
| if (k) return k; | |||||
| } | |||||
| } | |||||
| /* ---------- main loop ---------- */ | |||||
| main() | |||||
| { | |||||
| int k; | |||||
| int i; | |||||
| tlen = 0; | |||||
| pos = 0; | |||||
| mode = 0; | |||||
| cmdlen = 0; | |||||
| quit = 0; | |||||
| msgcode = 0; | |||||
| i = 0; | |||||
| while (defnam[i]) { | |||||
| fname[i] = defnam[i]; | |||||
| i = i + 1; | |||||
| } | |||||
| fname[i] = 0; | |||||
| while (!quit) { | |||||
| draw(text, tlen, pos, mode, fname, cmd, cmdlen, msgcode); | |||||
| msgcode = 0; | |||||
| k = waitkey(); | |||||
| if (mode == 2) { | |||||
| if (k == 13) { | |||||
| mode = 0; | |||||
| docmd(); | |||||
| } | |||||
| else if (k == 20) { | |||||
| if (cmdlen > 0) cmdlen = cmdlen - 1; | |||||
| } | |||||
| else if (k >= 32 && cmdlen < 8) { | |||||
| if (k >= 65 && k <= 90) k = k + 32; | |||||
| cmd[cmdlen] = k; | |||||
| cmdlen = cmdlen + 1; | |||||
| } | |||||
| continue; | |||||
| } | |||||
| if (mode == 1) { | |||||
| insk(k); | |||||
| continue; | |||||
| } | |||||
| cmdk(k); | |||||
| } | |||||
| clrscr(); | |||||
| printf("bye\n"); | |||||
| } | |||||
| @@ -0,0 +1,248 @@ | |||||
| /* vscreen.c - screen half of the vim editor for the C64 (Power C) | |||||
| * | |||||
| * Draws the text window, the status line and the cursor straight into | |||||
| * the screen matrix at $0400 and colour RAM at $d800. Kept in its own | |||||
| * file because Power C overflows its compiler when the whole editor is | |||||
| * one source. | |||||
| * | |||||
| * This module owns no program state: draw() receives everything it | |||||
| * needs from vim.c as arguments. Sharing variables between Power C | |||||
| * object files proved unreliable, so only functions cross the boundary. | |||||
| */ | |||||
| static char stat[40]; /* status line build buffer */ | |||||
| static int slen; | |||||
| /* ---------- status line text ---------- */ | |||||
| static sclr() | |||||
| { | |||||
| slen = 0; | |||||
| stat[0] = 0; | |||||
| } | |||||
| static sadd(c) | |||||
| char c; | |||||
| { | |||||
| if (slen < 39) { | |||||
| stat[slen] = c; | |||||
| slen = slen + 1; | |||||
| stat[slen] = 0; | |||||
| } | |||||
| } | |||||
| static sstr(s) | |||||
| char *s; | |||||
| { | |||||
| while (*s) { | |||||
| sadd(*s); | |||||
| s = s + 1; | |||||
| } | |||||
| } | |||||
| static snum(n) | |||||
| int n; | |||||
| { | |||||
| char b[6]; | |||||
| int i; | |||||
| if (n < 0) { | |||||
| sadd('-'); | |||||
| n = -n; | |||||
| } | |||||
| if (n == 0) { | |||||
| sadd('0'); | |||||
| return; | |||||
| } | |||||
| i = 0; | |||||
| while (n > 0) { | |||||
| b[i] = '0' + (n % 10); | |||||
| i = i + 1; | |||||
| n = n / 10; | |||||
| } | |||||
| while (i > 0) { | |||||
| i = i - 1; | |||||
| sadd(b[i]); | |||||
| } | |||||
| } | |||||
| /* ---------- PETSCII byte -> screen code ---------- */ | |||||
| static sccode(c) | |||||
| int c; | |||||
| { | |||||
| if (c >= 193 && c <= 218) return c - 192; /* shifted letters $C1-$DA */ | |||||
| if (c >= 96 && c <= 127) return c - 32; | |||||
| if (c >= 64 && c <= 95) return c - 64; | |||||
| /* the C-only characters have no glyph of their own in the ROM */ | |||||
| if (c == 219) return 91; /* { -> [ */ | |||||
| if (c == 221) return 93; /* } -> ] */ | |||||
| if (c == 223) return 94; /* | -> up arrow */ | |||||
| if (c == 175) return 126; /* ~ -> its graphics glyph */ | |||||
| if (c == 164) return 95; /* _ -> left arrow */ | |||||
| return c; | |||||
| } | |||||
| /* ---------- screen output ---------- */ | |||||
| clrscr() | |||||
| { | |||||
| char *s; | |||||
| char *m; | |||||
| int i; | |||||
| s = (char *) 1024; | |||||
| m = (char *) 55296; | |||||
| for (i = 0; i < 1000; i++) { | |||||
| s[i] = 32; | |||||
| m[i] = 1; | |||||
| } | |||||
| } | |||||
| static putchr(x, y, ch, c) | |||||
| int x; | |||||
| int y; | |||||
| int ch; | |||||
| int c; | |||||
| { | |||||
| char *s; | |||||
| char *m; | |||||
| int o; | |||||
| if (x < 0) return; | |||||
| if (x > 39) return; | |||||
| if (y < 0) return; | |||||
| if (y > 24) return; | |||||
| o = y * 40 + x; | |||||
| s = (char *) 1024; | |||||
| m = (char *) 55296; | |||||
| s[o] = ch; | |||||
| m[o] = c; | |||||
| } | |||||
| static putstr(x, y, s, c) | |||||
| int x; | |||||
| int y; | |||||
| char *s; | |||||
| int c; | |||||
| { | |||||
| while (*s && x < 40) { | |||||
| putchr(x, y, sccode(*s), c); | |||||
| x = x + 1; | |||||
| s = s + 1; | |||||
| } | |||||
| } | |||||
| static revchr(o) /* reverse the character in a cell */ | |||||
| int o; | |||||
| { | |||||
| char *s; | |||||
| s = (char *) 1024; | |||||
| if (s[o] < 128) s[o] = s[o] + 128; | |||||
| } | |||||
| /* ---------- buffer scans over the caller's text ---------- */ | |||||
| static lstartx(tp, len, n) /* offset of the first byte of line n */ | |||||
| char *tp; | |||||
| int len; | |||||
| int n; | |||||
| { | |||||
| int i; | |||||
| int c; | |||||
| if (n <= 0) return 0; | |||||
| c = 0; | |||||
| i = 0; | |||||
| while (i < len) { | |||||
| if (tp[i] == 13) { | |||||
| c = c + 1; | |||||
| if (c == n) return i + 1; | |||||
| } | |||||
| i = i + 1; | |||||
| } | |||||
| return len; | |||||
| } | |||||
| static lnofx(tp, cur) /* line holding the cursor */ | |||||
| char *tp; | |||||
| int cur; | |||||
| { | |||||
| int i; | |||||
| int c; | |||||
| c = 0; | |||||
| for (i = 0; i < cur; i++) | |||||
| if (tp[i] == 13) c = c + 1; | |||||
| return c; | |||||
| } | |||||
| /* ---------- full redraw ---------- */ | |||||
| draw(tp, len, cur, md, name, cp, cl, mc) | |||||
| char *tp; | |||||
| int len; | |||||
| int cur; | |||||
| int md; | |||||
| char *name; | |||||
| char *cp; | |||||
| int cl; | |||||
| int mc; | |||||
| { | |||||
| int ln; | |||||
| int top; | |||||
| int r; | |||||
| int i; | |||||
| int to; | |||||
| int c; | |||||
| int cs; | |||||
| int cr; | |||||
| ln = lnofx(tp, cur); | |||||
| top = ln - 11; | |||||
| if (top < 0) top = 0; | |||||
| clrscr(); | |||||
| to = lstartx(tp, len, top); | |||||
| for (r = 0; r < 23; r++) { | |||||
| i = 0; | |||||
| while (to < len && i < 40) { | |||||
| c = tp[to]; | |||||
| if (c == 13) break; | |||||
| putchr(i, r, sccode(c), 1); | |||||
| i = i + 1; | |||||
| to = to + 1; | |||||
| } | |||||
| while (to < len && tp[to] != 13) to = to + 1; | |||||
| if (to < len) to = to + 1; | |||||
| } | |||||
| for (i = 0; i < 40; i++) putchr(i, 24, 32, 11); | |||||
| sclr(); | |||||
| if (md == 1) sstr("INSERT"); | |||||
| else if (md == 2) sstr(": "); | |||||
| else sstr("COMMAND"); | |||||
| sstr(" line "); | |||||
| snum(ln + 1); | |||||
| sstr(" "); | |||||
| sstr(name); | |||||
| if (mc == 1) sstr(" full"); | |||||
| else if (mc == 2) sstr(" save err"); | |||||
| else if (mc == 3) sstr(" saved"); | |||||
| else if (mc == 4) sstr(" ?cmd"); | |||||
| putstr(0, 24, stat, 11); | |||||
| if (md == 2) { | |||||
| putchr(0, 23, sccode(':'), 1); | |||||
| for (i = 0; i < cl; i++) putchr(i + 1, 23, sccode(cp[i]), 1); | |||||
| } | |||||
| cs = cur - lstartx(tp, len, ln); | |||||
| if (cs > 39) cs = 39; | |||||
| if (cs < 0) cs = 0; | |||||
| cr = ln - top; | |||||
| if (cr >= 0 && cr < 23) revchr(cr * 40 + cs); | |||||
| } | |||||
Powered by TurnKey Linux.