2020-07-12 21:34:11 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
2020-08-03 03:47:28 +00:00
|
|
|
// Simple text editor
|
2020-08-03 02:49:53 +00:00
|
|
|
// Bobbi July 2020
|
2020-07-12 21:34:11 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2020-08-01 04:25:08 +00:00
|
|
|
// Note: Use my fork of cc65 to get a flashing cursor!!
|
2020-07-19 16:25:55 +00:00
|
|
|
|
2020-08-04 18:51:11 +00:00
|
|
|
// TODO: Maybe rework load_file() again to avoid memmove()
|
2020-08-04 02:22:18 +00:00
|
|
|
// TODO: Adjust beep() sound
|
2020-08-04 23:54:38 +00:00
|
|
|
// TODO: Redrawing selection on cursor_up()
|
2020-07-19 15:15:57 +00:00
|
|
|
// TODO: Make use of aux mem
|
2020-07-12 21:34:11 +00:00
|
|
|
|
2020-08-01 06:29:33 +00:00
|
|
|
#include <conio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdint.h>
|
2020-07-12 21:34:11 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2020-07-15 21:21:59 +00:00
|
|
|
#include <string.h>
|
2020-07-15 22:51:46 +00:00
|
|
|
#include <unistd.h>
|
2020-07-12 21:34:11 +00:00
|
|
|
|
2020-07-16 21:38:37 +00:00
|
|
|
#define NCOLS 80 // Width of editing screen
|
|
|
|
#define NROWS 22 // Height of editing screen
|
|
|
|
#define CURSORROW 10 // Row cursor is initially shown on (if enough text)
|
2020-07-19 21:53:49 +00:00
|
|
|
#define PROMPT_ROW NROWS + 1 // Row where input prompt is shown
|
2020-08-04 02:22:18 +00:00
|
|
|
#define RDSZ 1024 // Size of chunks to use when loading file
|
|
|
|
#define WRTSZ 1024 // Size of chunks to use when saving file
|
2020-07-12 21:34:11 +00:00
|
|
|
|
2020-07-18 04:03:27 +00:00
|
|
|
#define EOL '\r' // For ProDOS
|
|
|
|
|
|
|
|
#define BELL 0x07
|
|
|
|
#define BACKSPACE 0x08
|
|
|
|
#define RETURN 0x0d
|
2020-07-19 15:15:57 +00:00
|
|
|
#define ESC 0x1b
|
2020-07-18 04:03:27 +00:00
|
|
|
#define DELETE 0x7f
|
2020-07-12 21:34:11 +00:00
|
|
|
|
2020-08-04 23:54:38 +00:00
|
|
|
#define BUFSZ (20480 - 1024) // 19KB
|
2020-08-04 02:22:18 +00:00
|
|
|
|
2020-07-12 21:34:11 +00:00
|
|
|
char gapbuf[BUFSZ];
|
2020-08-01 04:25:08 +00:00
|
|
|
char padding = 0; // To null terminate for strstr()
|
2020-07-12 21:34:11 +00:00
|
|
|
uint16_t gapbegin = 0;
|
|
|
|
uint16_t gapend = BUFSZ - 1;
|
|
|
|
|
2020-08-01 04:25:08 +00:00
|
|
|
uint8_t rowlen[NROWS]; // Number of chars on each row of screen
|
2020-07-12 21:34:11 +00:00
|
|
|
|
2020-07-18 05:22:33 +00:00
|
|
|
char filename[80] = "";
|
|
|
|
char userentry[80] = "";
|
|
|
|
char search[80] = "";
|
2020-07-19 05:25:29 +00:00
|
|
|
char replace[80] = "";
|
2020-07-16 21:38:37 +00:00
|
|
|
|
2020-07-12 21:34:11 +00:00
|
|
|
// Interface to read_char_update_pos()
|
2020-07-18 05:45:36 +00:00
|
|
|
uint8_t do_print, modified;
|
2020-07-17 21:30:16 +00:00
|
|
|
uint16_t pos, startsel, endsel;
|
2020-07-12 21:34:11 +00:00
|
|
|
uint8_t row, col;
|
|
|
|
|
|
|
|
uint8_t cursrow, curscol; // Cursor position is kept here by draw_screen()
|
|
|
|
|
2020-07-18 04:03:27 +00:00
|
|
|
uint8_t quit_to_email; // If 1, launch EMAIL.SYSTEM on quit
|
|
|
|
uint8_t modified; // If 1, file contents have been modified
|
2020-07-16 21:38:37 +00:00
|
|
|
|
2020-08-02 00:29:19 +00:00
|
|
|
// The order of the cases matters! SRCH1/2/3 are not really a selection modes.
|
|
|
|
enum selmode {SEL_NONE, SEL_COPY2, SEL_MOVE2, SEL_DEL, SEL_MOVE, SEL_COPY,
|
|
|
|
SRCH1, SRCH2, SRCH3};
|
2020-07-17 21:30:16 +00:00
|
|
|
enum selmode mode;
|
|
|
|
|
2020-07-19 04:21:03 +00:00
|
|
|
// Mousetext Open-Apple
|
2020-07-18 04:03:27 +00:00
|
|
|
char openapple[] = "\x0f\x1b""A\x18\x0e";
|
|
|
|
|
2020-07-12 21:34:11 +00:00
|
|
|
/*
|
|
|
|
* Return number of bytes of freespace in gapbuf
|
|
|
|
*/
|
|
|
|
#define FREESPACE() (gapend - gapbegin + 1)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return number of bytes of data in gapbuf
|
|
|
|
*/
|
|
|
|
#define DATASIZE() (gapbegin + (BUFSZ - 1 - gapend))
|
2020-07-18 02:33:25 +00:00
|
|
|
|
2020-07-12 21:34:11 +00:00
|
|
|
/*
|
|
|
|
* Obtain current position in gapbuf
|
|
|
|
* This is the positon where the next character will be inserted
|
|
|
|
*/
|
|
|
|
#define GETPOS() (gapbegin)
|
|
|
|
|
2020-08-01 04:25:08 +00:00
|
|
|
/*
|
|
|
|
* Annoying beep
|
|
|
|
*/
|
|
|
|
void beep(void) {
|
2020-08-04 02:22:18 +00:00
|
|
|
uint8_t *p = (uint8_t*)0xc030; // Speaker
|
2020-08-03 03:20:19 +00:00
|
|
|
uint8_t junk;
|
|
|
|
uint16_t i;
|
2020-08-04 21:32:17 +00:00
|
|
|
for (i = 0; i < 1000; ++i) {
|
2020-08-03 03:20:19 +00:00
|
|
|
junk = *p;
|
2020-08-04 21:32:17 +00:00
|
|
|
for (junk = 0; junk < 10; ++junk); // Reduce pitch
|
|
|
|
}
|
2020-08-01 04:25:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clear to EOL
|
|
|
|
*/
|
|
|
|
void clreol(void) {
|
|
|
|
uint8_t x = wherex(), y = wherey();
|
|
|
|
cclear(80 - x);
|
|
|
|
gotoxy(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clear to EOL, wrap to next line
|
|
|
|
*/
|
|
|
|
void clreol_wrap(void) {
|
|
|
|
uint8_t x = wherex();
|
|
|
|
cclear(80 - x);
|
|
|
|
gotox(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clear line
|
|
|
|
*/
|
|
|
|
void clrline(void) {
|
|
|
|
uint8_t x = wherex();
|
|
|
|
gotox(0);
|
|
|
|
cclear(80);
|
|
|
|
gotox(x);
|
|
|
|
}
|
|
|
|
|
2020-07-16 21:38:37 +00:00
|
|
|
/*
|
|
|
|
* Put cursor at beginning of PROMPT_ROW
|
|
|
|
*/
|
|
|
|
void goto_prompt_row(void) {
|
2020-08-01 04:25:08 +00:00
|
|
|
gotoxy(0, PROMPT_ROW);
|
2020-07-16 21:38:37 +00:00
|
|
|
}
|
|
|
|
|
2020-08-02 00:29:19 +00:00
|
|
|
/*
|
|
|
|
* Refresh the status line at the bottom of the screen
|
|
|
|
*/
|
|
|
|
void update_status_line(void) {
|
|
|
|
uint8_t nofile = 0;
|
|
|
|
uint8_t i, l;
|
|
|
|
|
|
|
|
static char selmsg1[] = ": Go to end of selection, then [Return]";
|
|
|
|
static char selmsg2[] = ": Go to target, then [Return] to ";
|
|
|
|
|
|
|
|
goto_prompt_row();
|
|
|
|
|
|
|
|
if (strlen(filename) == 0) {
|
|
|
|
strcpy(filename, "<scratch>");
|
|
|
|
nofile = 1;
|
|
|
|
}
|
|
|
|
revers(1);
|
|
|
|
switch (mode) {
|
|
|
|
case SEL_NONE:
|
|
|
|
cprintf("OA-? Help | %c File:%s %2uKB free",
|
|
|
|
modified ? '*' : ' ', filename, (FREESPACE() + 512) / 1024);
|
|
|
|
l = 50 - strlen(filename);
|
|
|
|
break;
|
|
|
|
case SEL_DEL:
|
|
|
|
cprintf("Del%s", selmsg1);
|
|
|
|
l = 80 - 42;
|
|
|
|
break;
|
|
|
|
case SEL_COPY:
|
|
|
|
cprintf("Copy%s", selmsg1);
|
|
|
|
l = 80 - 43;
|
|
|
|
break;
|
|
|
|
case SEL_MOVE:
|
|
|
|
cprintf("Move%s", selmsg1);
|
|
|
|
l = 80 - 43;
|
|
|
|
break;
|
|
|
|
case SEL_COPY2:
|
|
|
|
cprintf("Copy%scopy", selmsg2);
|
|
|
|
l = 80 - 41;
|
|
|
|
break;
|
|
|
|
case SEL_MOVE2:
|
|
|
|
cprintf("Move%smove", selmsg2);
|
|
|
|
l = 80 - 41;
|
|
|
|
break;
|
|
|
|
case SRCH1:
|
|
|
|
cprintf("Searching ...");
|
|
|
|
l = 80 - 13;
|
|
|
|
break;
|
|
|
|
case SRCH2:
|
|
|
|
cprintf("Searching - wrapped ...");
|
|
|
|
l = 80 - 23;
|
|
|
|
break;
|
|
|
|
case SRCH3:
|
|
|
|
cprintf("OA-? Help | %c File:%s %2uKB free | Not Found",
|
|
|
|
modified ? '*' : ' ', filename, (FREESPACE() + 512) / 1024);
|
|
|
|
l = 50 - 12 - strlen(filename);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (i = 0; i < l; ++i)
|
|
|
|
cputc(' ');
|
|
|
|
revers(0);
|
|
|
|
|
|
|
|
if (nofile)
|
|
|
|
strcpy(filename, "");
|
|
|
|
|
|
|
|
gotoxy(curscol, cursrow);
|
|
|
|
cursor(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set modified status
|
|
|
|
*/
|
|
|
|
void set_modified(uint8_t mod) {
|
|
|
|
if (modified == mod)
|
|
|
|
return;
|
|
|
|
modified = mod;
|
|
|
|
update_status_line();
|
|
|
|
}
|
|
|
|
|
2020-07-16 21:38:37 +00:00
|
|
|
/*
|
|
|
|
* Prompt for a name in the bottom line of the screen
|
|
|
|
* Returns number of chars read.
|
|
|
|
* prompt - Message to display before > prompt
|
|
|
|
* is_file - if 1, restrict chars to those allowed in ProDOS filename
|
2020-07-19 15:15:57 +00:00
|
|
|
* Returns number of chars read, or 255 if ESC pressed
|
2020-07-16 21:38:37 +00:00
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-16 21:38:37 +00:00
|
|
|
uint8_t prompt_for_name(char *prompt, uint8_t is_file) {
|
|
|
|
uint16_t i;
|
|
|
|
char c;
|
|
|
|
cursor(0);
|
|
|
|
goto_prompt_row();
|
2020-08-01 04:25:08 +00:00
|
|
|
clreol();
|
|
|
|
revers(1);
|
|
|
|
cprintf("%s>", prompt);
|
|
|
|
revers(0);
|
2020-07-19 21:53:49 +00:00
|
|
|
gotox(2 + strlen(prompt));
|
2020-07-16 21:38:37 +00:00
|
|
|
i = 0;
|
|
|
|
while (1) {
|
|
|
|
c = cgetc();
|
|
|
|
if (is_file && !isalnum(c) && (c != RETURN) && (c != BACKSPACE) &&
|
2020-07-19 15:15:57 +00:00
|
|
|
(c != DELETE) && (c != ESC) && (c != '.') && (c != '/')) {
|
2020-08-01 04:25:08 +00:00
|
|
|
beep();
|
2020-07-16 21:38:37 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
switch (c) {
|
|
|
|
case RETURN:
|
|
|
|
goto done;
|
|
|
|
case BACKSPACE:
|
|
|
|
case DELETE:
|
|
|
|
if (i > 0) {
|
2020-07-19 21:53:49 +00:00
|
|
|
gotox(wherex() - 1);
|
|
|
|
cputc(' ');
|
|
|
|
gotox(wherex() - 1);
|
2020-07-16 21:38:37 +00:00
|
|
|
--i;
|
|
|
|
} else
|
2020-08-01 04:25:08 +00:00
|
|
|
beep();
|
2020-07-16 21:38:37 +00:00
|
|
|
break;
|
2020-07-19 15:15:57 +00:00
|
|
|
case ESC:
|
|
|
|
userentry[0] = '\0';
|
|
|
|
i = 255;
|
|
|
|
goto esc_pressed;
|
2020-07-16 21:38:37 +00:00
|
|
|
default:
|
2020-07-19 21:53:49 +00:00
|
|
|
cputc(c);
|
2020-07-16 21:38:37 +00:00
|
|
|
userentry[i++] = c;
|
|
|
|
}
|
|
|
|
if (i == 79)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
userentry[i] = '\0';
|
2020-07-19 15:15:57 +00:00
|
|
|
esc_pressed:
|
2020-08-01 04:25:08 +00:00
|
|
|
clrline();
|
2020-07-16 21:38:37 +00:00
|
|
|
gotoxy(curscol, cursrow);
|
|
|
|
cursor(1);
|
|
|
|
return i;
|
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-16 21:38:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Prompt ok?
|
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-16 21:38:37 +00:00
|
|
|
char prompt_okay(char *msg) {
|
|
|
|
char c;
|
2020-07-16 23:16:59 +00:00
|
|
|
cursor(0);
|
2020-07-16 21:38:37 +00:00
|
|
|
goto_prompt_row();
|
2020-08-01 04:25:08 +00:00
|
|
|
clreol();
|
|
|
|
revers(1);
|
|
|
|
cprintf("%sSure? (y/n)", msg);
|
|
|
|
revers(0);
|
2020-07-16 21:38:37 +00:00
|
|
|
while (1) {
|
|
|
|
c = cgetc();
|
|
|
|
if ((c == 'y') || (c == 'Y') || (c == 'n') || (c == 'N'))
|
|
|
|
break;
|
2020-08-01 04:25:08 +00:00
|
|
|
beep();
|
2020-07-16 21:38:37 +00:00
|
|
|
}
|
|
|
|
if ((c == 'y') || (c == 'Y'))
|
|
|
|
c = 1;
|
|
|
|
else
|
|
|
|
c = 0;
|
2020-08-02 00:29:19 +00:00
|
|
|
update_status_line();
|
2020-07-16 21:38:37 +00:00
|
|
|
return c;
|
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-16 21:38:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Error message
|
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-16 21:38:37 +00:00
|
|
|
void show_error(char *msg) {
|
2020-07-16 23:16:59 +00:00
|
|
|
cursor(0);
|
2020-07-16 21:38:37 +00:00
|
|
|
goto_prompt_row();
|
2020-08-02 03:18:13 +00:00
|
|
|
clreol();
|
2020-08-01 04:25:08 +00:00
|
|
|
beep();
|
|
|
|
revers(1);
|
2020-08-02 00:29:19 +00:00
|
|
|
cprintf("%s [Press Any Key]", msg);
|
2020-08-01 04:25:08 +00:00
|
|
|
revers(0);
|
2020-07-16 21:38:37 +00:00
|
|
|
cgetc();
|
2020-08-02 00:29:19 +00:00
|
|
|
update_status_line();
|
2020-07-18 02:33:25 +00:00
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-18 02:33:25 +00:00
|
|
|
|
2020-07-12 21:34:11 +00:00
|
|
|
/*
|
|
|
|
* Insert a character into gapbuf at current position
|
|
|
|
* c - character to insert
|
|
|
|
*/
|
2020-08-03 02:28:01 +00:00
|
|
|
void insert_char(char c) {
|
2020-07-12 21:34:11 +00:00
|
|
|
if (FREESPACE()) {
|
|
|
|
gapbuf[gapbegin++] = c;
|
2020-08-03 02:28:01 +00:00
|
|
|
return;
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
2020-08-03 02:28:01 +00:00
|
|
|
beep();
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete the character to the left of the current position
|
|
|
|
*/
|
2020-08-01 04:25:08 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-08-03 02:28:01 +00:00
|
|
|
void delete_char(void) {
|
|
|
|
if (gapbegin == 0) {
|
|
|
|
beep();
|
|
|
|
return;
|
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
--gapbegin;
|
|
|
|
}
|
2020-08-01 04:25:08 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete the character to the right of the current position
|
|
|
|
*/
|
2020-08-01 04:25:08 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-08-03 02:28:01 +00:00
|
|
|
void delete_char_right(void) {
|
|
|
|
if (gapend == BUFSZ - 1) {
|
|
|
|
beep();
|
|
|
|
return;
|
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
++gapend;
|
|
|
|
}
|
2020-08-01 04:25:08 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Move the current position
|
|
|
|
* pos - position to which to move
|
|
|
|
*/
|
2020-08-03 02:28:01 +00:00
|
|
|
void jump_pos(uint16_t pos) {
|
2020-08-04 18:51:11 +00:00
|
|
|
uint16_t l;
|
2020-08-03 02:28:01 +00:00
|
|
|
if (pos > BUFSZ - 1) {
|
|
|
|
beep();
|
|
|
|
return;
|
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
if (pos == GETPOS())
|
2020-08-03 02:28:01 +00:00
|
|
|
return;
|
2020-08-04 18:51:11 +00:00
|
|
|
if (pos > GETPOS()) {
|
|
|
|
l = pos - gapbegin;
|
|
|
|
memmove(gapbuf + gapbegin, gapbuf + gapend + 1, l);
|
|
|
|
gapbegin += l;
|
|
|
|
gapend += l;
|
|
|
|
} else {
|
|
|
|
l = gapbegin - pos;
|
|
|
|
memmove(gapbuf + gapend - l + 1, gapbuf + gapbegin - l, l);
|
|
|
|
gapbegin -= l;
|
|
|
|
gapend -= l;
|
|
|
|
}
|
2020-08-03 02:28:01 +00:00
|
|
|
return;
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
|
|
|
|
2020-07-13 03:12:01 +00:00
|
|
|
/*
|
|
|
|
* Go to next tabstop
|
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-13 03:12:01 +00:00
|
|
|
uint8_t next_tabstop(uint8_t col) {
|
|
|
|
return (col / 8) * 8 + 8;
|
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-13 03:12:01 +00:00
|
|
|
|
2020-07-12 21:34:11 +00:00
|
|
|
/*
|
|
|
|
* Load a file from disk into the gapbuf
|
|
|
|
* filename - name of file to load
|
2020-07-25 01:30:16 +00:00
|
|
|
* replace - if 1, replace old file.
|
2020-08-04 02:22:18 +00:00
|
|
|
* initialcol - initial screen column
|
2020-07-12 21:34:11 +00:00
|
|
|
* Returns 0 on success
|
|
|
|
* 1 if file can't be opened
|
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-25 01:30:16 +00:00
|
|
|
uint8_t load_file(char *filename, uint8_t replace) {
|
2020-08-04 02:22:18 +00:00
|
|
|
uint8_t col;
|
|
|
|
char *p;
|
|
|
|
uint16_t i, j, s;
|
|
|
|
uint8_t c, cont;
|
2020-07-12 21:34:11 +00:00
|
|
|
FILE *fp = fopen(filename, "r");
|
|
|
|
if (!fp)
|
|
|
|
return 1;
|
2020-08-04 02:22:18 +00:00
|
|
|
if (!replace)
|
|
|
|
col = curscol;
|
2020-07-19 21:53:49 +00:00
|
|
|
goto_prompt_row();
|
2020-07-25 01:30:16 +00:00
|
|
|
if (replace) {
|
|
|
|
gapbegin = 0;
|
|
|
|
gapend = BUFSZ - 1;
|
|
|
|
col = 0;
|
|
|
|
}
|
2020-08-04 02:22:18 +00:00
|
|
|
p = gapbuf + gapbegin;
|
|
|
|
do {
|
|
|
|
if (FREESPACE() < RDSZ * 2) {
|
2020-07-16 21:38:37 +00:00
|
|
|
show_error("File truncated");
|
2020-08-04 02:22:18 +00:00
|
|
|
goto done;
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
2020-08-04 02:22:18 +00:00
|
|
|
cputc('.');
|
|
|
|
s = fread(p, 1, RDSZ, fp);
|
|
|
|
cont = (s == RDSZ ? 1 : 0);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (i < s) {
|
|
|
|
switch (*(p + i)) {
|
|
|
|
case '\r': // Native Apple2 files
|
|
|
|
case '\n': // UNIX files
|
|
|
|
col = 0;
|
|
|
|
*(p + i) = '\r';
|
|
|
|
++i;
|
|
|
|
break;
|
|
|
|
case '\t':
|
|
|
|
c = next_tabstop(col) - col;
|
|
|
|
memmove(p + i + c - 1, p + i, s - i);
|
|
|
|
for (j = 0; j < c; ++j)
|
|
|
|
*(p + i + j) = ' ';
|
|
|
|
col += c;
|
|
|
|
i += c;
|
|
|
|
s += c - 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
++col;
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p += s;
|
|
|
|
gapbegin += s;
|
|
|
|
} while (cont);
|
2020-07-12 21:34:11 +00:00
|
|
|
--gapbegin; // Eat EOF character
|
2020-08-04 02:22:18 +00:00
|
|
|
done:
|
2020-07-12 21:34:11 +00:00
|
|
|
fclose(fp);
|
2020-07-25 01:30:16 +00:00
|
|
|
if (replace) {
|
|
|
|
jump_pos(0);
|
|
|
|
pos = 0;
|
2020-08-02 00:29:19 +00:00
|
|
|
set_modified(0);
|
2020-07-25 01:30:16 +00:00
|
|
|
startsel = endsel = 65535U;
|
|
|
|
mode = SEL_NONE;
|
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Save gapbuf to file
|
|
|
|
* filename - name of file to load
|
|
|
|
* Returns 0 on success
|
|
|
|
* 1 if file can't be opened
|
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-12 21:34:11 +00:00
|
|
|
uint8_t save_file(char *filename) {
|
2020-08-04 02:22:18 +00:00
|
|
|
uint16_t pos = gapbegin;
|
|
|
|
uint8_t retval = 1;
|
|
|
|
char *p;
|
|
|
|
uint8_t i;
|
2020-08-03 02:28:01 +00:00
|
|
|
FILE *fp;
|
|
|
|
_filetype = PRODOS_T_TXT;
|
|
|
|
_auxtype = 0;
|
|
|
|
fp = fopen(filename, "w");
|
2020-07-12 21:34:11 +00:00
|
|
|
if (!fp)
|
2020-08-04 02:22:18 +00:00
|
|
|
goto done;
|
2020-07-19 21:53:49 +00:00
|
|
|
jump_pos(0);
|
|
|
|
goto_prompt_row();
|
2020-08-04 02:22:18 +00:00
|
|
|
p = gapbuf + gapend + 1;
|
|
|
|
for (i = 0; i < DATASIZE() / WRTSZ; ++i) {
|
|
|
|
cputc('.');
|
|
|
|
if (fwrite(p, WRTSZ, 1, fp) != 1)
|
|
|
|
goto done;
|
|
|
|
p += WRTSZ;
|
2020-07-19 21:53:49 +00:00
|
|
|
}
|
2020-08-04 02:22:18 +00:00
|
|
|
cputc('.');
|
|
|
|
if (fwrite(p, DATASIZE() - (WRTSZ * i), 1, fp) != 1)
|
|
|
|
goto done;
|
|
|
|
retval = 0;
|
|
|
|
done:
|
2020-07-12 21:34:11 +00:00
|
|
|
fclose(fp);
|
2020-08-04 02:22:18 +00:00
|
|
|
jump_pos(pos);
|
2020-07-12 21:34:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Read next char from gapbuf[] and update state.
|
|
|
|
* Returns 1 on EOL, 0 otherwise
|
|
|
|
* If do_print is set, print char on the screen.
|
|
|
|
* Interface is via the following globals:
|
|
|
|
* do_print - if 1, update screen
|
|
|
|
* pos - position in buffer, advanced by one
|
|
|
|
* row, col - position on screen
|
|
|
|
* rowlen[] - length of each screen row in chars
|
|
|
|
*/
|
|
|
|
uint8_t read_char_update_pos(void) {
|
2020-08-04 23:14:52 +00:00
|
|
|
uint16_t delta = gapend - gapbegin;
|
2020-07-12 21:34:11 +00:00
|
|
|
char c;
|
2020-07-12 23:05:25 +00:00
|
|
|
if ((c = gapbuf[pos++]) == EOL) {
|
2020-07-12 21:34:11 +00:00
|
|
|
if (do_print) {
|
|
|
|
rowlen[row] = col + 1;
|
2020-08-01 04:25:08 +00:00
|
|
|
clreol_wrap();
|
|
|
|
gotox(0);
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
|
|
|
++row;
|
|
|
|
col = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
2020-08-04 23:14:52 +00:00
|
|
|
if (((pos > startsel) && (pos <= endsel)) || // Left of cursor
|
|
|
|
((pos - delta > endsel) && (pos - delta <= startsel + 1))) // Right of cursor
|
2020-08-02 00:35:34 +00:00
|
|
|
revers(1);
|
|
|
|
else
|
|
|
|
revers(0);
|
2020-08-01 05:53:56 +00:00
|
|
|
if (do_print)
|
2020-07-19 21:53:49 +00:00
|
|
|
cputc(c);
|
2020-08-01 05:53:56 +00:00
|
|
|
revers(0);
|
2020-07-12 23:05:25 +00:00
|
|
|
++col;
|
2020-07-16 04:00:34 +00:00
|
|
|
if (do_print)
|
|
|
|
rowlen[row] = col;
|
2020-07-13 03:12:01 +00:00
|
|
|
if (col == NCOLS) {
|
2020-07-12 21:34:11 +00:00
|
|
|
++row;
|
|
|
|
col = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Draw screenful of text
|
|
|
|
*/
|
|
|
|
void draw_screen(void) {
|
|
|
|
uint16_t startpos;
|
|
|
|
uint8_t rowsabove, cursorrow;
|
|
|
|
|
2020-07-16 04:33:48 +00:00
|
|
|
// Initialize all rows to length 0 to cover those rows that may have
|
2020-07-13 04:05:15 +00:00
|
|
|
// no text and would otherwise be unitialized.
|
|
|
|
for (rowsabove = 0; rowsabove < NROWS; ++rowsabove)
|
2020-07-16 04:33:48 +00:00
|
|
|
rowlen[rowsabove] = 0;
|
2020-07-13 04:05:15 +00:00
|
|
|
|
2020-07-12 21:34:11 +00:00
|
|
|
// First we have to scan back to work out where in the buffer to
|
|
|
|
// start drawing on the screen at the top left. This is at most
|
2020-07-16 04:00:34 +00:00
|
|
|
// NROWS * NCOLS chars.
|
2020-07-12 21:34:11 +00:00
|
|
|
startpos = gapbegin;
|
|
|
|
if (startpos > NROWS * NCOLS)
|
|
|
|
startpos -= NROWS * NCOLS;
|
|
|
|
else
|
|
|
|
startpos = 0;
|
|
|
|
|
|
|
|
// Format the text and work out the number of rows it takes up
|
|
|
|
pos = startpos;
|
|
|
|
row = col = 0;
|
|
|
|
do_print = 0;
|
|
|
|
while (pos < gapbegin)
|
|
|
|
read_char_update_pos();
|
|
|
|
rowsabove = row; // Number of complete rows above cursor
|
|
|
|
|
|
|
|
if (rowsabove <= CURSORROW) {
|
|
|
|
pos = 0;
|
|
|
|
cursorrow = rowsabove;
|
|
|
|
} else {
|
|
|
|
cursorrow = CURSORROW;
|
|
|
|
|
|
|
|
// Now repeat the formatting of the text, eating the first
|
|
|
|
// (rowsabove - cursorrow) lines
|
|
|
|
pos = startpos;
|
|
|
|
row = col = 0;
|
|
|
|
while (row < (rowsabove - cursorrow))
|
|
|
|
read_char_update_pos();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally actually write the text to the screen!
|
|
|
|
videomode(VIDEOMODE_80COL);
|
|
|
|
clrscr();
|
2020-08-01 04:25:08 +00:00
|
|
|
revers(0);
|
2020-07-12 21:34:11 +00:00
|
|
|
row = col = 0;
|
|
|
|
do_print = 1;
|
|
|
|
while (pos < gapbegin)
|
|
|
|
read_char_update_pos();
|
|
|
|
|
|
|
|
curscol = col;
|
|
|
|
cursrow = row;
|
|
|
|
|
|
|
|
// Now write the text after the cursor up to the end of the screen
|
|
|
|
pos = gapend + 1;
|
|
|
|
while ((pos < BUFSZ) && (row < NROWS))
|
|
|
|
read_char_update_pos();
|
|
|
|
|
2020-08-02 00:29:19 +00:00
|
|
|
update_status_line();
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scroll screen up and update rowlen[]
|
|
|
|
*/
|
|
|
|
void scroll_up() {
|
|
|
|
draw_screen();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scroll screen down and update rowlen[]
|
|
|
|
*/
|
|
|
|
void scroll_down() {
|
|
|
|
draw_screen();
|
|
|
|
}
|
|
|
|
|
2020-07-31 04:16:12 +00:00
|
|
|
/*
|
|
|
|
* Returns 1 if current position in gap buffer is on the last line of
|
|
|
|
* the file (ie: no following CR), 0 otherwise
|
|
|
|
*/
|
|
|
|
uint8_t is_last_line(void) {
|
|
|
|
uint16_t p = gapend + 1;
|
|
|
|
while (p < BUFSZ) {
|
|
|
|
if (gapbuf[p++] == '\r')
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-07-12 21:34:11 +00:00
|
|
|
/*
|
|
|
|
* Update screen after delete_char_right()
|
|
|
|
*/
|
|
|
|
void update_after_delete_char_right(void) {
|
|
|
|
uint8_t eol = 0;
|
2020-07-16 21:38:37 +00:00
|
|
|
uint8_t i;
|
2020-07-12 21:34:11 +00:00
|
|
|
col = curscol;
|
|
|
|
row = cursrow;
|
|
|
|
do_print = 1;
|
|
|
|
|
|
|
|
// Print rest of line up to EOL
|
|
|
|
pos = gapend + 1;
|
|
|
|
while (!eol && (pos < BUFSZ) && (row < NROWS)) {
|
2020-07-16 21:38:37 +00:00
|
|
|
i = col;
|
2020-07-12 21:34:11 +00:00
|
|
|
eol = read_char_update_pos();
|
|
|
|
}
|
2020-07-31 04:16:12 +00:00
|
|
|
if (is_last_line())
|
2020-08-01 04:25:08 +00:00
|
|
|
clreol_wrap();
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
// If necessary, print rest of screen
|
2020-07-16 23:16:59 +00:00
|
|
|
if ((gapbuf[gapend] == EOL) || (i == NCOLS - 1)) {
|
2020-07-12 21:34:11 +00:00
|
|
|
while ((pos < BUFSZ) && (row < NROWS))
|
|
|
|
read_char_update_pos();
|
|
|
|
|
2020-08-01 04:25:08 +00:00
|
|
|
clreol_wrap();
|
2020-07-17 21:30:16 +00:00
|
|
|
|
2020-07-16 23:16:59 +00:00
|
|
|
// Erase the rest of the screen (if any)
|
2020-07-17 21:30:16 +00:00
|
|
|
for (i = row + 1; i < NROWS; ++i) {
|
2020-07-16 23:16:59 +00:00
|
|
|
gotoxy(0, i);
|
2020-08-01 04:25:08 +00:00
|
|
|
clrline();
|
2020-07-16 23:16:59 +00:00
|
|
|
}
|
2020-07-16 21:38:37 +00:00
|
|
|
}
|
|
|
|
|
2020-07-12 21:34:11 +00:00
|
|
|
gotoxy(curscol, cursrow);
|
|
|
|
cursor(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update screen after delete_char()
|
|
|
|
*/
|
|
|
|
void update_after_delete_char(void) {
|
|
|
|
uint8_t eol = 0;
|
2020-07-16 21:38:37 +00:00
|
|
|
uint8_t i;
|
2020-07-12 21:34:11 +00:00
|
|
|
col = curscol;
|
|
|
|
row = cursrow;
|
|
|
|
|
|
|
|
if (gapbuf[gapbegin] == EOL) {
|
|
|
|
// Special handling if we deleted an EOL
|
|
|
|
if (row > 0)
|
|
|
|
col = rowlen[--row] - 1;
|
|
|
|
else {
|
|
|
|
scroll_up();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Erase char to left of cursor & update row, col
|
2020-07-19 21:53:49 +00:00
|
|
|
gotox(wherex() - 1);
|
|
|
|
cputc(' ');
|
|
|
|
gotox(wherex() - 1);
|
2020-07-12 21:34:11 +00:00
|
|
|
if (col > 0)
|
|
|
|
--col;
|
|
|
|
else {
|
2020-08-02 21:28:42 +00:00
|
|
|
col = NCOLS - 1;
|
2020-07-12 21:34:11 +00:00
|
|
|
if (row > 0)
|
|
|
|
--row;
|
|
|
|
else {
|
|
|
|
scroll_up();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
curscol = col;
|
|
|
|
cursrow = row;
|
|
|
|
gotoxy(curscol, cursrow);
|
|
|
|
|
|
|
|
do_print = 1;
|
|
|
|
|
|
|
|
// Print rest of line up to EOL
|
|
|
|
pos = gapend + 1;
|
|
|
|
while (!eol && (pos < BUFSZ) && (row < NROWS)) {
|
2020-07-16 21:38:37 +00:00
|
|
|
i = col;
|
2020-07-12 21:34:11 +00:00
|
|
|
eol = read_char_update_pos();
|
|
|
|
}
|
2020-07-31 04:16:12 +00:00
|
|
|
if (is_last_line())
|
2020-08-01 04:25:08 +00:00
|
|
|
clreol_wrap();
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
// If necessary, print rest of screen
|
2020-07-16 23:16:59 +00:00
|
|
|
if ((gapbuf[gapbegin] == EOL) || (i == NCOLS - 1)) {
|
2020-07-12 21:34:11 +00:00
|
|
|
while ((pos < BUFSZ) && (row < NROWS))
|
|
|
|
read_char_update_pos();
|
|
|
|
|
2020-08-01 04:25:08 +00:00
|
|
|
clreol_wrap();
|
2020-07-17 21:30:16 +00:00
|
|
|
|
2020-07-16 23:16:59 +00:00
|
|
|
// Erase the rest of the screen (if any)
|
2020-07-17 21:30:16 +00:00
|
|
|
for (i = row + 1; i < NROWS; ++i) {
|
2020-07-16 23:16:59 +00:00
|
|
|
gotoxy(0, i);
|
2020-08-01 04:25:08 +00:00
|
|
|
clrline();
|
2020-07-16 23:16:59 +00:00
|
|
|
}
|
2020-07-16 21:38:37 +00:00
|
|
|
}
|
|
|
|
|
2020-07-12 21:34:11 +00:00
|
|
|
gotoxy(curscol, cursrow);
|
|
|
|
cursor(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update screen after insert_char()
|
|
|
|
*/
|
|
|
|
void update_after_insert_char(void) {
|
|
|
|
uint8_t eol = 0;
|
|
|
|
uint8_t prevcol;
|
|
|
|
col = curscol;
|
|
|
|
row = cursrow;
|
|
|
|
|
|
|
|
// Print character just inserted
|
|
|
|
pos = gapbegin - 1;
|
|
|
|
do_print = 1;
|
|
|
|
read_char_update_pos();
|
|
|
|
|
|
|
|
curscol = col;
|
|
|
|
cursrow = row;
|
2020-07-19 21:53:49 +00:00
|
|
|
gotoxy(curscol, cursrow);
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
if (cursrow == NROWS) {
|
|
|
|
scroll_down();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print rest of line up to EOL
|
|
|
|
pos = gapend + 1;
|
|
|
|
while (!eol && (pos < BUFSZ) && (row < NROWS)) {
|
|
|
|
prevcol = col;
|
|
|
|
eol = read_char_update_pos();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If necessary, print rest of screen
|
|
|
|
if ((gapbuf[gapbegin - 1] == EOL) || (prevcol == 0))
|
|
|
|
while ((pos < BUFSZ) && (row < NROWS))
|
|
|
|
read_char_update_pos();
|
|
|
|
|
|
|
|
gotoxy(curscol, cursrow);
|
|
|
|
cursor(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Move the cursor left
|
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-12 21:34:11 +00:00
|
|
|
void cursor_left(void) {
|
|
|
|
if (gapbegin > 0)
|
|
|
|
gapbuf[gapend--] = gapbuf[--gapbegin];
|
|
|
|
else {
|
2020-08-01 04:25:08 +00:00
|
|
|
beep();
|
2020-07-17 01:10:27 +00:00
|
|
|
gotoxy(curscol, cursrow);
|
2020-07-12 21:34:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (curscol == 0) {
|
2020-07-13 03:12:01 +00:00
|
|
|
if (cursrow == 0) {
|
2020-07-12 21:34:11 +00:00
|
|
|
scroll_up();
|
2020-07-13 03:12:01 +00:00
|
|
|
if (cursrow == 0) {
|
2020-08-01 04:25:08 +00:00
|
|
|
beep();
|
2020-07-13 03:12:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
--cursrow;
|
2020-08-01 19:32:58 +00:00
|
|
|
curscol = rowlen[cursrow] - 1;
|
2020-07-12 21:34:11 +00:00
|
|
|
} else
|
|
|
|
--curscol;
|
|
|
|
gotoxy(curscol, cursrow);
|
2020-08-04 23:14:52 +00:00
|
|
|
if (mode > SEL_MOVE2) {
|
|
|
|
endsel = gapbegin;
|
|
|
|
revers(gapbegin < startsel ? 1 : 0);
|
|
|
|
cputc(gapbuf[gapbegin]);
|
|
|
|
revers(0);
|
|
|
|
}
|
|
|
|
gotoxy(curscol, cursrow);
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Move the cursor right
|
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-12 21:34:11 +00:00
|
|
|
void cursor_right(void) {
|
2020-07-17 01:10:27 +00:00
|
|
|
if (gapend < BUFSZ - 1)
|
2020-07-12 21:34:11 +00:00
|
|
|
gapbuf[gapbegin++] = gapbuf[++gapend];
|
|
|
|
else {
|
2020-08-01 04:25:08 +00:00
|
|
|
beep();
|
2020-08-04 21:49:27 +00:00
|
|
|
goto done;
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
|
|
|
++curscol;
|
2020-08-04 21:49:27 +00:00
|
|
|
if (gapend == BUFSZ - 1)
|
|
|
|
goto done;
|
2020-08-03 02:49:53 +00:00
|
|
|
if (curscol == rowlen[cursrow]) {
|
2020-08-02 04:13:32 +00:00
|
|
|
if (cursrow == NROWS - 1)
|
|
|
|
scroll_down();
|
|
|
|
++cursrow;
|
|
|
|
curscol = 0;
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
2020-08-04 21:49:27 +00:00
|
|
|
done:
|
|
|
|
if (mode > SEL_MOVE2) {
|
|
|
|
endsel = gapbegin;
|
2020-08-04 23:14:52 +00:00
|
|
|
revers(gapbegin > startsel ? 1 : 0);
|
2020-08-04 21:49:27 +00:00
|
|
|
cputc(gapbuf[gapbegin - 1]);
|
|
|
|
revers(0);
|
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
gotoxy(curscol, cursrow);
|
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Move the cursor up
|
2020-07-16 04:00:34 +00:00
|
|
|
* Returns 1 if at top, 0 otherwise
|
2020-07-12 21:34:11 +00:00
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-16 04:00:34 +00:00
|
|
|
uint8_t cursor_up(void) {
|
2020-07-12 21:34:11 +00:00
|
|
|
uint8_t i;
|
2020-07-13 03:12:01 +00:00
|
|
|
if (cursrow == 0) {
|
2020-07-12 21:34:11 +00:00
|
|
|
scroll_up();
|
2020-07-13 03:12:01 +00:00
|
|
|
if (cursrow == 0) {
|
2020-08-01 04:25:08 +00:00
|
|
|
beep();
|
2020-07-13 03:12:01 +00:00
|
|
|
gotoxy(curscol, cursrow);
|
2020-07-16 04:00:34 +00:00
|
|
|
return 1;
|
2020-07-13 03:12:01 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
for (i = 0; i < curscol; ++i)
|
|
|
|
gapbuf[gapend--] = gapbuf[--gapbegin];
|
|
|
|
--cursrow;
|
|
|
|
// Short line ...
|
2020-07-16 04:33:48 +00:00
|
|
|
if (curscol > rowlen[cursrow] - 1)
|
2020-07-12 21:34:11 +00:00
|
|
|
curscol = rowlen[cursrow] - 1;
|
|
|
|
for (i = 0; i < rowlen[cursrow] - curscol; ++i)
|
2020-07-16 04:33:48 +00:00
|
|
|
if (gapbegin > 0)
|
|
|
|
gapbuf[gapend--] = gapbuf[--gapbegin];
|
2020-08-04 23:54:38 +00:00
|
|
|
if (mode > SEL_MOVE2) {
|
|
|
|
endsel = gapbegin;
|
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
gotoxy(curscol, cursrow);
|
2020-07-16 04:00:34 +00:00
|
|
|
return 0;
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Move the cursor down
|
2020-07-16 04:00:34 +00:00
|
|
|
* Returns 1 if at bottom, 0 otherwise
|
2020-07-12 21:34:11 +00:00
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-16 04:00:34 +00:00
|
|
|
uint8_t cursor_down(void) {
|
2020-07-12 21:34:11 +00:00
|
|
|
uint8_t i;
|
2020-07-17 01:10:27 +00:00
|
|
|
if (cursrow == NROWS - 1)
|
2020-07-12 21:34:11 +00:00
|
|
|
scroll_down();
|
2020-07-17 01:10:27 +00:00
|
|
|
if ((gapbuf[gapend + rowlen[cursrow] - curscol] != EOL) &&
|
|
|
|
(rowlen[cursrow] != NCOLS))
|
|
|
|
return 1; // Last line
|
|
|
|
|
|
|
|
for (i = 0; i < rowlen[cursrow] - curscol; ++i) {
|
2020-08-04 23:54:38 +00:00
|
|
|
if (gapend < BUFSZ - 1) {
|
2020-07-17 01:10:27 +00:00
|
|
|
gapbuf[gapbegin++] = gapbuf[++gapend];
|
2020-08-04 23:54:38 +00:00
|
|
|
revers(gapbegin > startsel ? 1 : 0);
|
|
|
|
cputc(gapbuf[gapbegin - 1]);
|
|
|
|
revers(0);
|
|
|
|
}
|
2020-07-17 01:10:27 +00:00
|
|
|
else {
|
2020-08-01 04:25:08 +00:00
|
|
|
beep();
|
2020-07-16 04:00:34 +00:00
|
|
|
return 1;
|
2020-07-13 03:12:01 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-17 01:10:27 +00:00
|
|
|
++cursrow;
|
2020-07-12 21:34:11 +00:00
|
|
|
// Short line ...
|
2020-07-16 04:33:48 +00:00
|
|
|
if (curscol > rowlen[cursrow] - 1)
|
2020-07-12 21:34:11 +00:00
|
|
|
curscol = rowlen[cursrow] - 1;
|
2020-08-04 23:54:38 +00:00
|
|
|
gotoxy(0, cursrow);
|
|
|
|
for (i = 0; i < curscol; ++i) {
|
|
|
|
if (gapend < BUFSZ - 1) {
|
2020-07-13 04:05:15 +00:00
|
|
|
gapbuf[gapbegin++] = gapbuf[++gapend];
|
2020-08-04 23:54:38 +00:00
|
|
|
revers(gapbegin > startsel ? 1 : 0);
|
|
|
|
cputc(gapbuf[gapbegin - 1]);
|
|
|
|
revers(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mode > SEL_MOVE2) {
|
|
|
|
endsel = gapbegin;
|
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
gotoxy(curscol, cursrow);
|
2020-07-16 04:00:34 +00:00
|
|
|
return 0;
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Goto beginning of line
|
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-12 21:34:11 +00:00
|
|
|
void goto_bol(void) {
|
|
|
|
while (curscol > 0)
|
|
|
|
cursor_left();
|
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-12 21:34:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Goto end of line
|
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-12 21:34:11 +00:00
|
|
|
void goto_eol(void) {
|
|
|
|
while (curscol < rowlen[cursrow] - 1)
|
|
|
|
cursor_right();
|
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-12 21:34:11 +00:00
|
|
|
|
2020-07-18 02:33:25 +00:00
|
|
|
/*
|
|
|
|
* Word left
|
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-18 02:33:25 +00:00
|
|
|
void word_left(void) {
|
|
|
|
do {
|
|
|
|
cursor_left();
|
|
|
|
} while ((gapbuf[gapbegin] != ' ') && (gapbuf[gapbegin] != EOL) &&
|
|
|
|
(gapbegin > 0));
|
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-18 02:33:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Word right
|
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-18 02:33:25 +00:00
|
|
|
void word_right(void) {
|
|
|
|
do {
|
|
|
|
cursor_right();
|
|
|
|
} while ((gapbuf[gapbegin] != ' ') && (gapbuf[gapbegin] != EOL) &&
|
|
|
|
(gapend < BUFSZ - 1));
|
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-18 02:33:25 +00:00
|
|
|
|
2020-07-12 21:34:11 +00:00
|
|
|
/*
|
|
|
|
* Jump forward 15 screen lines
|
|
|
|
*/
|
|
|
|
void page_down(void) {
|
|
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < 15; ++i)
|
2020-07-16 04:00:34 +00:00
|
|
|
if (cursor_down() == 1)
|
|
|
|
break;
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Jump back 15 screen lines
|
|
|
|
*/
|
|
|
|
void page_up(void) {
|
|
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < 15; ++i)
|
2020-07-16 04:00:34 +00:00
|
|
|
if (cursor_up() == 1)
|
|
|
|
break;
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
|
|
|
|
2020-08-01 05:53:56 +00:00
|
|
|
/*
|
|
|
|
* Perform word-wrapping on current paragraph
|
2020-08-01 19:38:56 +00:00
|
|
|
* addbreaks - if 1, add breaks to do word wrap, otherwise it 'unwraps'
|
|
|
|
* (ie: removes all carriage returns in paragraph)
|
2020-08-01 05:53:56 +00:00
|
|
|
*/
|
2020-08-01 19:38:56 +00:00
|
|
|
void word_wrap_para(uint8_t addbreaks) {
|
2020-08-01 06:29:33 +00:00
|
|
|
uint16_t i = gapbegin;
|
|
|
|
uint8_t rets = 0, col = 0;
|
|
|
|
uint16_t startpara = 0;
|
|
|
|
// Find start of paragraph ("\r\r" delimiter)
|
|
|
|
while (i > 0) {
|
|
|
|
--i;
|
|
|
|
if (gapbuf[i] == '\r')
|
|
|
|
++rets;
|
|
|
|
else
|
|
|
|
rets = 0;
|
|
|
|
if (rets == 2) {
|
|
|
|
startpara = i + 2;
|
|
|
|
break;
|
|
|
|
}
|
2020-08-01 05:53:56 +00:00
|
|
|
}
|
2020-08-01 06:29:33 +00:00
|
|
|
// Iterate through para, up to the cursor
|
|
|
|
i = startpara;
|
|
|
|
while (i < gapbegin) {
|
|
|
|
if (gapbuf[i] == '\r')
|
|
|
|
gapbuf[i] = ' ';
|
2020-08-01 05:53:56 +00:00
|
|
|
++col;
|
2020-08-01 19:38:56 +00:00
|
|
|
if (addbreaks && (col == 76)) {
|
2020-08-01 06:29:33 +00:00
|
|
|
// Backtrack to find a space
|
|
|
|
while ((gapbuf[i] != ' ') && (i > startpara))
|
|
|
|
--i;
|
|
|
|
if (i == startpara) {
|
|
|
|
beep();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gapbuf[i] = '\r'; // Break line
|
|
|
|
col = 0;
|
|
|
|
}
|
|
|
|
++i;
|
2020-08-01 05:53:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-18 04:03:27 +00:00
|
|
|
/*
|
|
|
|
* Help screen
|
2020-08-01 04:25:08 +00:00
|
|
|
* EDITHELP.TXT is expected to contain lines of exactly 80 chars
|
2020-07-18 04:03:27 +00:00
|
|
|
*/
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (push, "LC")
|
2020-07-18 04:03:27 +00:00
|
|
|
void help(void) {
|
2020-08-01 04:25:08 +00:00
|
|
|
FILE *fp = fopen("EDITHELP.TXT", "rb");
|
|
|
|
char c;
|
2020-07-19 21:53:49 +00:00
|
|
|
revers(0);
|
2020-07-18 04:03:27 +00:00
|
|
|
cursor(0);
|
|
|
|
clrscr();
|
2020-08-01 04:25:08 +00:00
|
|
|
if (!fp) {
|
|
|
|
printf("Can't open EDITHELP.TXT\n\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
c = fgetc(fp);
|
|
|
|
while (!feof(fp)) {
|
2020-08-01 05:14:49 +00:00
|
|
|
if (c == '@')
|
|
|
|
printf("%s", openapple);
|
|
|
|
else if ((c != '\r') && (c != '\n'))
|
|
|
|
putchar(c);
|
2020-08-01 04:25:08 +00:00
|
|
|
c = fgetc(fp);
|
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
done:
|
|
|
|
printf("[Press Any Key]");
|
2020-07-18 04:03:27 +00:00
|
|
|
cgetc();
|
2020-08-01 04:25:08 +00:00
|
|
|
clrscr();
|
2020-07-18 04:03:27 +00:00
|
|
|
}
|
2020-07-19 04:21:03 +00:00
|
|
|
#pragma code-name (pop)
|
2020-07-18 04:03:27 +00:00
|
|
|
|
2020-07-15 21:21:59 +00:00
|
|
|
/*
|
|
|
|
* Load EMAIL.SYSTEM to $2000 and jump to it
|
2020-07-15 22:51:46 +00:00
|
|
|
* (This code is in language card space so it can't possibly be trashed)
|
2020-07-15 21:21:59 +00:00
|
|
|
*/
|
|
|
|
#pragma code-name (push, "LC")
|
|
|
|
void load_email(void) {
|
2020-07-16 21:38:37 +00:00
|
|
|
revers(0);
|
|
|
|
clrscr();
|
2020-07-24 05:19:52 +00:00
|
|
|
exec("EMAIL.SYSTEM", NULL); // Assume it is in current directory
|
2020-07-15 21:21:59 +00:00
|
|
|
}
|
|
|
|
#pragma code-name (pop)
|
2020-07-12 21:34:11 +00:00
|
|
|
|
2020-07-28 21:14:43 +00:00
|
|
|
/*
|
|
|
|
* Load ATTACHER.SYSTEM to $2000 and jump to it
|
|
|
|
* (This code is in language card space so it can't possibly be trashed)
|
|
|
|
*/
|
|
|
|
#pragma code-name (push, "LC")
|
|
|
|
void load_attacher(void) {
|
|
|
|
revers(0);
|
|
|
|
clrscr();
|
|
|
|
exec("ATTACHER.SYSTEM", filename); // Assume it is in current directory
|
|
|
|
}
|
|
|
|
#pragma code-name (pop)
|
|
|
|
|
2020-07-18 05:45:36 +00:00
|
|
|
/*
|
|
|
|
* Save file to disk, handle user interface
|
|
|
|
*/
|
|
|
|
void save(void) {
|
2020-07-19 04:01:59 +00:00
|
|
|
if (strlen(filename) == 0) {
|
2020-08-01 04:25:08 +00:00
|
|
|
if (prompt_for_name("File to save", 1) == 255)
|
2020-07-19 15:15:57 +00:00
|
|
|
return; // If ESC pressed
|
|
|
|
if (strlen(userentry) == 0)
|
|
|
|
return;
|
2020-07-19 04:01:59 +00:00
|
|
|
strcpy(filename, userentry);
|
|
|
|
}
|
|
|
|
sprintf(userentry, "Save to %s - ", filename);
|
|
|
|
if (prompt_okay(userentry)) {
|
|
|
|
if (save_file(filename)) {
|
|
|
|
sprintf(userentry, "%cCan't save %s", filename);
|
|
|
|
show_error(userentry);
|
|
|
|
draw_screen();
|
|
|
|
} else {
|
2020-08-02 00:29:19 +00:00
|
|
|
set_modified(0);
|
2020-07-19 04:01:59 +00:00
|
|
|
}
|
2020-07-18 05:45:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-15 21:21:59 +00:00
|
|
|
/*
|
|
|
|
* Main editor routine
|
|
|
|
*/
|
2020-07-16 23:16:59 +00:00
|
|
|
int edit(char *fname) {
|
2020-07-18 04:59:35 +00:00
|
|
|
char c, *p;
|
2020-07-18 02:33:25 +00:00
|
|
|
uint16_t pos, tmp;
|
2020-07-12 23:05:25 +00:00
|
|
|
uint8_t i;
|
2020-07-12 21:34:11 +00:00
|
|
|
videomode(VIDEOMODE_80COL);
|
2020-07-16 23:16:59 +00:00
|
|
|
if (fname) {
|
|
|
|
strcpy(filename, fname);
|
2020-07-19 21:53:49 +00:00
|
|
|
cprintf("Loading file %s ", filename);
|
2020-07-25 01:30:16 +00:00
|
|
|
if (load_file(filename, 1)) {
|
2020-07-19 04:01:59 +00:00
|
|
|
sprintf(userentry, "Can't load %s", filename);
|
2020-07-16 21:38:37 +00:00
|
|
|
show_error(userentry);
|
2020-07-19 05:25:29 +00:00
|
|
|
strcpy(filename, "");
|
2020-07-16 04:00:34 +00:00
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
2020-07-16 04:00:34 +00:00
|
|
|
jump_pos(0);
|
2020-07-18 05:27:23 +00:00
|
|
|
pos = 0;
|
2020-08-02 00:29:19 +00:00
|
|
|
set_modified(0);
|
2020-07-18 05:27:23 +00:00
|
|
|
startsel = endsel = 65535U;
|
2020-07-17 21:30:16 +00:00
|
|
|
mode = SEL_NONE;
|
2020-07-12 21:34:11 +00:00
|
|
|
draw_screen();
|
|
|
|
while (1) {
|
2020-07-16 04:00:34 +00:00
|
|
|
cursor(1);
|
2020-07-12 21:34:11 +00:00
|
|
|
c = cgetc();
|
2020-08-02 00:29:19 +00:00
|
|
|
if (mode == SRCH3) // Reset 'Not found'
|
|
|
|
mode = SEL_NONE;
|
2020-07-12 21:34:11 +00:00
|
|
|
switch (c) {
|
2020-08-04 23:54:38 +00:00
|
|
|
case ESC: // Escape from block mode operations
|
|
|
|
startsel = endsel = 65535U;
|
|
|
|
mode = SEL_NONE;
|
|
|
|
draw_screen();
|
|
|
|
break;
|
2020-07-18 02:33:25 +00:00
|
|
|
case 0x80 + '1': // Top
|
|
|
|
jump_pos(0);
|
|
|
|
draw_screen();
|
|
|
|
break;
|
|
|
|
case 0x80 + '2':
|
|
|
|
jump_pos(DATASIZE() / 8);
|
|
|
|
draw_screen();
|
|
|
|
break;
|
|
|
|
case 0x80 + '3':
|
|
|
|
jump_pos(2 * DATASIZE() / 8);
|
|
|
|
draw_screen();
|
|
|
|
break;
|
|
|
|
case 0x80 + '4':
|
|
|
|
jump_pos(3 * DATASIZE() / 8);
|
|
|
|
draw_screen();
|
|
|
|
break;
|
|
|
|
case 0x80 + '5':
|
|
|
|
jump_pos(4 * DATASIZE() / 8);
|
|
|
|
draw_screen();
|
|
|
|
break;
|
|
|
|
case 0x80 + '6':
|
|
|
|
jump_pos(5 * DATASIZE() / 8);
|
|
|
|
draw_screen();
|
|
|
|
break;
|
|
|
|
case 0x80 + '7':
|
|
|
|
jump_pos(6 * DATASIZE() / 8);
|
|
|
|
draw_screen();
|
|
|
|
break;
|
|
|
|
case 0x80 + '8':
|
|
|
|
jump_pos(7 * DATASIZE() / 8);
|
|
|
|
draw_screen();
|
|
|
|
break;
|
|
|
|
case 0x80 + '9': // Bottom
|
|
|
|
jump_pos(DATASIZE());
|
|
|
|
draw_screen();
|
|
|
|
break;
|
|
|
|
case 0x80 + 0x08: // OA-Left "Word left"
|
|
|
|
word_left();
|
2020-07-12 21:34:11 +00:00
|
|
|
break;
|
2020-07-18 02:33:25 +00:00
|
|
|
case 0x80 + 0x15: // OA-Right "Word right"
|
|
|
|
word_right();
|
|
|
|
break;
|
|
|
|
case 0x80 + ',': // OA-< "Home"
|
|
|
|
case 0x80 + '<':
|
|
|
|
goto_bol();
|
2020-07-12 21:34:11 +00:00
|
|
|
break;
|
2020-07-18 02:33:25 +00:00
|
|
|
case 0x80 + '.': // OA-> "End"
|
|
|
|
case 0x80 + '>':
|
2020-07-12 21:34:11 +00:00
|
|
|
goto_eol();
|
2020-07-18 02:33:25 +00:00
|
|
|
break;
|
|
|
|
case 0x8b: // OA-Up "Page Up"
|
|
|
|
page_up();
|
2020-08-04 23:54:38 +00:00
|
|
|
if (mode > SEL_MOVE2)
|
2020-07-18 00:08:26 +00:00
|
|
|
draw_screen();
|
2020-07-12 21:34:11 +00:00
|
|
|
break;
|
2020-07-16 04:00:34 +00:00
|
|
|
case 0x8a: // OA-Down "Page Down"
|
2020-07-12 21:34:11 +00:00
|
|
|
page_down();
|
2020-07-18 00:08:26 +00:00
|
|
|
break;
|
|
|
|
case 0x80 + 'C': // OA-C "Copy"
|
|
|
|
case 0x80 + 'c': // OA-c
|
|
|
|
mode = SEL_COPY;
|
2020-08-04 23:54:38 +00:00
|
|
|
tmp = (startsel == 65535U ? 0 : 1); // Prev selection active?
|
2020-07-18 00:08:26 +00:00
|
|
|
endsel = startsel = gapbegin;
|
2020-08-04 23:54:38 +00:00
|
|
|
if (tmp)
|
|
|
|
draw_screen();
|
2020-07-18 00:08:26 +00:00
|
|
|
break;
|
|
|
|
case 0x80 + 'D': // OA-D "Delete"
|
|
|
|
case 0x80 + 'd': // OA-d
|
|
|
|
mode = SEL_DEL;
|
2020-08-04 23:54:38 +00:00
|
|
|
tmp = (startsel == 65535U ? 0 : 1); // Prev selection active?
|
2020-07-18 00:08:26 +00:00
|
|
|
endsel = startsel = gapbegin;
|
2020-08-04 23:54:38 +00:00
|
|
|
if (tmp)
|
|
|
|
draw_screen();
|
2020-07-12 21:34:11 +00:00
|
|
|
break;
|
2020-07-18 06:09:14 +00:00
|
|
|
case 0x80 + 'R': // OA-R "Replace"
|
|
|
|
case 0x80 + 'r': // OA-r
|
|
|
|
tmp = 65535U;
|
2020-07-18 04:59:35 +00:00
|
|
|
case 0x80 + 'F': // OA-F "Find"
|
|
|
|
case 0x80 + 'f': // OA-F "Find"
|
2020-07-18 06:09:14 +00:00
|
|
|
++tmp;
|
2020-07-19 15:15:57 +00:00
|
|
|
sprintf(userentry, "Find (%s)", search);
|
|
|
|
if (prompt_for_name(userentry, 0) == 255)
|
|
|
|
break; // ESC pressed
|
|
|
|
if (strlen(userentry) > 0)
|
2020-07-18 05:22:33 +00:00
|
|
|
strcpy(search, userentry);
|
|
|
|
else {
|
|
|
|
if (strlen(search) == 0)
|
|
|
|
break;
|
2020-07-19 05:25:29 +00:00
|
|
|
sprintf(userentry, "Search for '%s' - ", search);
|
|
|
|
if (!prompt_okay(userentry))
|
2020-07-18 05:22:33 +00:00
|
|
|
break;
|
2020-07-18 05:45:36 +00:00
|
|
|
cursor_right();
|
2020-07-18 05:22:33 +00:00
|
|
|
}
|
2020-07-19 05:25:29 +00:00
|
|
|
if (tmp == 0) { // Replace mode
|
|
|
|
sprintf(userentry, "Replace (%s)", replace);
|
2020-07-19 15:15:57 +00:00
|
|
|
if (prompt_for_name(userentry, 0) == 255)
|
|
|
|
break; // ESC pressed
|
|
|
|
if (strlen(userentry) > 0)
|
2020-07-19 05:25:29 +00:00
|
|
|
strcpy(replace, userentry);
|
|
|
|
else {
|
|
|
|
if (strlen(replace) == 0)
|
|
|
|
break;
|
|
|
|
sprintf(userentry, "Replace with '%s' - ", replace);
|
|
|
|
if (!prompt_okay(userentry))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-08-02 00:29:19 +00:00
|
|
|
mode = SRCH1;
|
|
|
|
update_status_line();
|
2020-07-18 05:22:33 +00:00
|
|
|
p = strstr(gapbuf + gapend + 1, search);
|
|
|
|
if (!p) {
|
2020-08-02 00:29:19 +00:00
|
|
|
mode = SRCH2;
|
|
|
|
update_status_line();
|
2020-07-18 05:22:33 +00:00
|
|
|
gapbuf[gapbegin] = '\0';
|
2020-07-18 06:09:14 +00:00
|
|
|
p = strstr(gapbuf, search);
|
2020-08-02 00:29:19 +00:00
|
|
|
mode = SEL_NONE;
|
2020-07-18 04:59:35 +00:00
|
|
|
if (!p) {
|
2020-08-02 00:29:19 +00:00
|
|
|
mode = SRCH3;
|
|
|
|
update_status_line();
|
2020-07-18 04:59:35 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-07-18 05:22:33 +00:00
|
|
|
jump_pos(p - gapbuf);
|
2020-07-18 06:09:14 +00:00
|
|
|
if (tmp == 0) { // Replace mode
|
|
|
|
for (i = 0; i < strlen(search); ++i)
|
|
|
|
delete_char_right();
|
2020-07-19 05:25:29 +00:00
|
|
|
memcpy(gapbuf + gapbegin, replace, strlen(userentry));
|
|
|
|
gapbegin += strlen(replace);
|
2020-07-18 06:09:14 +00:00
|
|
|
}
|
2020-07-18 04:59:35 +00:00
|
|
|
draw_screen();
|
2020-07-18 05:22:33 +00:00
|
|
|
break;
|
2020-07-18 04:59:35 +00:00
|
|
|
}
|
2020-08-02 00:29:19 +00:00
|
|
|
mode = SEL_NONE;
|
2020-07-18 05:22:33 +00:00
|
|
|
jump_pos(gapbegin + p - (gapbuf + gapend + 1));
|
2020-07-18 06:09:14 +00:00
|
|
|
if (tmp == 0) { // Replace mode
|
|
|
|
for (i = 0; i < strlen(search); ++i)
|
|
|
|
delete_char_right();
|
2020-07-19 05:25:29 +00:00
|
|
|
memcpy(gapbuf + gapbegin, replace, strlen(userentry));
|
|
|
|
gapbegin += strlen(replace);
|
2020-07-18 06:09:14 +00:00
|
|
|
}
|
2020-07-18 05:22:33 +00:00
|
|
|
draw_screen();
|
2020-07-18 04:59:35 +00:00
|
|
|
break;
|
2020-07-25 01:30:16 +00:00
|
|
|
case 0x80 + 'I': // OA-I "Insert file"
|
|
|
|
case 0x80 + 'i':
|
2020-08-01 05:24:38 +00:00
|
|
|
if (prompt_for_name("File to insert", 1) == 255)
|
|
|
|
break; // ESC pressed
|
|
|
|
if (strlen(userentry) == 0)
|
|
|
|
break;
|
2020-08-02 00:29:19 +00:00
|
|
|
if (load_file(userentry, 0))
|
2020-08-01 05:24:38 +00:00
|
|
|
show_error("Can't open");
|
|
|
|
draw_screen();
|
|
|
|
break;
|
2020-07-16 21:38:37 +00:00
|
|
|
case 0x80 + 'L': // OA-L "Load"
|
|
|
|
case 0x80 + 'l':
|
2020-08-01 19:32:58 +00:00
|
|
|
if (prompt_for_name("File to load", 1) == 255)
|
2020-07-19 15:15:57 +00:00
|
|
|
break; // ESC pressed
|
|
|
|
if (strlen(userentry) == 0)
|
|
|
|
break;
|
2020-08-01 19:32:58 +00:00
|
|
|
jump_pos(0);
|
|
|
|
pos = 0;
|
2020-08-02 00:29:19 +00:00
|
|
|
set_modified(0);
|
2020-08-01 19:32:58 +00:00
|
|
|
startsel = endsel = 65535U;
|
|
|
|
mode = SEL_NONE;
|
|
|
|
gapbegin = 0;
|
|
|
|
gapend = BUFSZ - 1;
|
2020-07-16 21:38:37 +00:00
|
|
|
strcpy(filename, userentry);
|
2020-08-02 00:29:19 +00:00
|
|
|
if (load_file(filename, 1)) {
|
2020-07-19 04:01:59 +00:00
|
|
|
sprintf(userentry, "Can't load %s", filename);
|
2020-07-16 21:38:37 +00:00
|
|
|
show_error(userentry);
|
2020-07-19 16:25:55 +00:00
|
|
|
strcpy(filename, "");
|
2020-07-16 21:38:37 +00:00
|
|
|
}
|
2020-07-17 21:30:16 +00:00
|
|
|
draw_screen();
|
|
|
|
break;
|
|
|
|
case 0x80 + 'M': // OA-M "Move"
|
|
|
|
case 0x80 + 'm': // OA-m
|
|
|
|
mode = SEL_MOVE;
|
2020-08-04 23:54:38 +00:00
|
|
|
tmp = (startsel == 65535U ? 0 : 1); // Prev selection active?
|
2020-07-18 00:08:26 +00:00
|
|
|
endsel = startsel = gapbegin;
|
2020-08-04 23:54:38 +00:00
|
|
|
if (tmp)
|
|
|
|
draw_screen();
|
2020-07-16 04:00:34 +00:00
|
|
|
break;
|
2020-07-19 04:01:59 +00:00
|
|
|
case 0x80 + 'N': // OA-N "Name"
|
2020-07-16 21:38:37 +00:00
|
|
|
case 0x80 + 'n': // OA-n
|
2020-07-19 15:15:57 +00:00
|
|
|
if (prompt_for_name("New filename", 1) == 255)
|
|
|
|
break; // ESC pressed
|
|
|
|
if (strlen(userentry) == 0)
|
|
|
|
break;
|
|
|
|
strcpy(filename, userentry);
|
2020-08-02 00:29:19 +00:00
|
|
|
update_status_line();
|
2020-07-16 21:38:37 +00:00
|
|
|
break;
|
|
|
|
case 0x80 + 'Q': // OA-Q "Quit"
|
|
|
|
case 0x80 + 'q': // OA-q
|
2020-07-19 05:03:27 +00:00
|
|
|
if (modified)
|
|
|
|
save();
|
2020-07-16 21:38:37 +00:00
|
|
|
if (quit_to_email) {
|
2020-07-28 21:14:43 +00:00
|
|
|
if (prompt_okay("Add attachments - "))
|
|
|
|
load_attacher();
|
2020-07-16 21:38:37 +00:00
|
|
|
if (prompt_okay("Quit to EMAIL - "))
|
|
|
|
load_email();
|
|
|
|
} else {
|
|
|
|
if (prompt_okay("Quit to ProDOS - ")) {
|
|
|
|
revers(0);
|
|
|
|
clrscr();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
break;
|
2020-08-01 19:38:56 +00:00
|
|
|
case 0x80 + 'U': // OA-U "Unwrap"
|
|
|
|
case 0x80 + 'u': // OA-w
|
|
|
|
word_wrap_para(0);
|
|
|
|
draw_screen();
|
|
|
|
break;
|
2020-08-01 05:53:56 +00:00
|
|
|
case 0x80 + 'W': // OA-W "Wrap"
|
|
|
|
case 0x80 + 'w': // OA-w
|
2020-08-01 19:38:56 +00:00
|
|
|
word_wrap_para(1);
|
2020-08-01 05:53:56 +00:00
|
|
|
draw_screen();
|
|
|
|
break;
|
2020-07-16 21:38:37 +00:00
|
|
|
case 0x80 + 'S': // OA-S "Save"
|
|
|
|
case 0x80 + 's': // OA-s
|
2020-07-18 05:45:36 +00:00
|
|
|
save();
|
2020-07-19 21:53:49 +00:00
|
|
|
draw_screen();
|
2020-07-15 21:56:40 +00:00
|
|
|
break;
|
2020-07-16 21:38:37 +00:00
|
|
|
case 0x80 + DELETE: // OA-Backspace
|
2020-07-16 04:00:34 +00:00
|
|
|
case 0x04: // Ctrl-D "DELETE"
|
2020-07-18 00:08:26 +00:00
|
|
|
if (mode == SEL_NONE) {
|
|
|
|
delete_char_right();
|
|
|
|
update_after_delete_char_right();
|
2020-08-02 00:29:19 +00:00
|
|
|
set_modified(1);
|
2020-07-18 00:08:26 +00:00
|
|
|
}
|
2020-07-16 00:46:43 +00:00
|
|
|
break;
|
2020-07-18 04:03:27 +00:00
|
|
|
case 0x80 + '?': // OA-? "Help"
|
|
|
|
help();
|
|
|
|
draw_screen();
|
|
|
|
break;
|
2020-07-16 04:00:34 +00:00
|
|
|
case 0x0c: // Ctrl-L "REFRESH"
|
|
|
|
draw_screen();
|
2020-07-12 21:34:11 +00:00
|
|
|
break;
|
2020-07-16 21:38:37 +00:00
|
|
|
case DELETE: // DEL "BACKSPACE"
|
2020-07-18 00:08:26 +00:00
|
|
|
if (mode == SEL_NONE) {
|
|
|
|
delete_char();
|
|
|
|
update_after_delete_char();
|
2020-08-02 00:29:19 +00:00
|
|
|
set_modified(1);
|
2020-07-18 00:08:26 +00:00
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
break;
|
2020-07-12 23:05:25 +00:00
|
|
|
case 0x09: // Tab
|
2020-07-18 00:08:26 +00:00
|
|
|
if (mode == SEL_NONE) {
|
|
|
|
c = next_tabstop(curscol) - curscol;
|
|
|
|
for (i = 0; i < c; ++i) {
|
|
|
|
insert_char(' ');
|
|
|
|
update_after_insert_char();
|
|
|
|
}
|
2020-08-02 00:29:19 +00:00
|
|
|
set_modified(1);
|
2020-07-12 23:05:25 +00:00
|
|
|
}
|
|
|
|
break;
|
2020-07-16 04:00:34 +00:00
|
|
|
case 0x08: // Left
|
|
|
|
cursor_left();
|
|
|
|
break;
|
2020-07-12 21:34:11 +00:00
|
|
|
case 0x15: // Right
|
|
|
|
cursor_right();
|
|
|
|
break;
|
|
|
|
case 0x0b: // Up
|
|
|
|
cursor_up();
|
2020-08-04 23:54:38 +00:00
|
|
|
if (mode > SEL_MOVE2)
|
2020-07-18 00:08:26 +00:00
|
|
|
draw_screen();
|
2020-07-12 21:34:11 +00:00
|
|
|
break;
|
|
|
|
case 0x0a: // Down
|
|
|
|
cursor_down();
|
|
|
|
break;
|
2020-07-17 21:30:16 +00:00
|
|
|
case EOL: // Return
|
2020-07-18 00:08:26 +00:00
|
|
|
if (mode == SEL_NONE) {
|
|
|
|
insert_char(c);
|
|
|
|
update_after_insert_char();
|
2020-08-02 00:29:19 +00:00
|
|
|
set_modified(1);
|
2020-07-18 00:08:26 +00:00
|
|
|
} else {
|
2020-07-18 02:33:25 +00:00
|
|
|
if (startsel > endsel) {
|
|
|
|
tmp = endsel;
|
|
|
|
endsel = startsel;
|
|
|
|
startsel = tmp;
|
|
|
|
}
|
2020-07-18 00:08:26 +00:00
|
|
|
switch (mode) {
|
|
|
|
case SEL_DEL:
|
2020-07-18 02:33:25 +00:00
|
|
|
if (prompt_okay("Delete selection - ")) {
|
|
|
|
jump_pos(startsel);
|
|
|
|
gapend += (endsel - startsel);
|
|
|
|
}
|
2020-07-18 05:27:23 +00:00
|
|
|
startsel = endsel = 65535U;
|
2020-07-18 00:08:26 +00:00
|
|
|
mode = SEL_NONE;
|
2020-08-02 00:29:19 +00:00
|
|
|
set_modified(1);
|
2020-07-18 00:08:26 +00:00
|
|
|
draw_screen();
|
|
|
|
break;
|
|
|
|
case SEL_COPY:
|
2020-07-18 02:33:25 +00:00
|
|
|
mode = SEL_COPY2;
|
2020-08-02 00:29:19 +00:00
|
|
|
update_status_line();
|
2020-07-18 00:08:26 +00:00
|
|
|
break;
|
|
|
|
case SEL_MOVE:
|
2020-07-18 02:33:25 +00:00
|
|
|
mode = SEL_MOVE2;
|
2020-08-02 00:29:19 +00:00
|
|
|
update_status_line();
|
2020-07-18 02:33:25 +00:00
|
|
|
break;
|
|
|
|
case SEL_COPY2:
|
|
|
|
case SEL_MOVE2:
|
|
|
|
if ((gapbegin > startsel) && (gapbegin < endsel)) {
|
|
|
|
show_error("Bad destination");
|
|
|
|
goto copymove2_cleanup;
|
|
|
|
}
|
|
|
|
if ((endsel - startsel) > FREESPACE()) {
|
|
|
|
show_error("No space");
|
|
|
|
goto copymove2_cleanup;
|
|
|
|
}
|
|
|
|
sprintf(userentry, "%s selection - ", mode == SEL_COPY2 ? "Copy" : "Move");
|
|
|
|
if (prompt_okay(userentry)) {
|
|
|
|
if (gapbegin >= endsel)
|
|
|
|
memcpy(gapbuf + gapbegin, gapbuf + startsel, endsel - startsel);
|
|
|
|
else
|
|
|
|
memcpy(gapbuf + gapbegin,
|
|
|
|
gapbuf + gapend + startsel - gapbegin + 1, endsel - startsel);
|
|
|
|
gapbegin += (endsel - startsel);
|
|
|
|
if (mode == SEL_MOVE2) {
|
2020-07-19 05:03:27 +00:00
|
|
|
jump_pos((gapbegin >= endsel) ? startsel : endsel);
|
2020-07-18 02:33:25 +00:00
|
|
|
gapend += (endsel - startsel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
copymove2_cleanup:
|
2020-07-18 05:27:23 +00:00
|
|
|
startsel = endsel = 65535U;
|
2020-07-18 02:33:25 +00:00
|
|
|
mode = SEL_NONE;
|
2020-08-02 00:29:19 +00:00
|
|
|
set_modified(1);
|
2020-07-18 02:33:25 +00:00
|
|
|
draw_screen();
|
2020-07-18 00:08:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-07-17 21:30:16 +00:00
|
|
|
break;
|
2020-07-12 21:34:11 +00:00
|
|
|
default:
|
2020-07-12 23:05:25 +00:00
|
|
|
//printf("**%02x**", c);
|
2020-08-02 00:29:19 +00:00
|
|
|
if ((c >= 0x20) && (c < 0x80) && (mode == SEL_NONE)) {
|
2020-07-13 04:05:15 +00:00
|
|
|
insert_char(c);
|
|
|
|
update_after_insert_char();
|
2020-08-02 00:29:19 +00:00
|
|
|
set_modified(1);
|
2020-07-13 04:05:15 +00:00
|
|
|
}
|
2020-07-12 21:34:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-20 00:25:49 +00:00
|
|
|
void main(int argc, char *argv[]) {
|
2020-07-16 00:15:57 +00:00
|
|
|
if (argc == 2) {
|
2020-07-16 21:38:37 +00:00
|
|
|
quit_to_email = 1;
|
2020-07-16 00:15:57 +00:00
|
|
|
edit(argv[1]);
|
2020-07-16 21:38:37 +00:00
|
|
|
} else {
|
|
|
|
quit_to_email = 0;
|
2020-07-16 00:15:57 +00:00
|
|
|
edit(NULL);
|
2020-07-16 21:38:37 +00:00
|
|
|
}
|
2020-07-15 21:21:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|