Quellcode durchsuchen

Add vim sources and updates

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
main
Daniel Covington vor 1 Woche
Ursprung
Commit
7fe0e3f5d6
5 geänderte Dateien mit 770 neuen und 0 gelöschten Zeilen
  1. +71
    -0
      vim/build.bat
  2. +31
    -0
      vim/to-petscii.ps1
  3. +420
    -0
      vim/vim.c
  4. BIN
      vim/vim.d81
  5. +248
    -0
      vim/vscreen.c

+ 71
- 0
vim/build.bat Datei anzeigen

@@ -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

+ 31
- 0
vim/to-petscii.ps1 Datei anzeigen

@@ -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)

+ 420
- 0
vim/vim.c Datei anzeigen

@@ -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");
}

BIN
vim/vim.d81 Datei anzeigen


+ 248
- 0
vim/vscreen.c Datei anzeigen

@@ -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);
}

Laden…
Abbrechen
Speichern

Powered by TurnKey Linux.