EDIT: buffer list, save all, check overwrite, experimental big file support

This commit is contained in:
Bobbi Webber-Manners 2020-08-11 16:29:26 -04:00
parent 5df64e08c0
commit 3ece13ef5e

View File

@ -4,7 +4,6 @@
// Bobbi July-Aug 2020
/////////////////////////////////////////////////////////////////////////////
// TODO: Buffer list. Prompt unsaved buffers on exit.
// TODO: Load big files spanning multiple buffers (& keep track of it)
// TODO: Search options - ignore case, complete word.
@ -23,7 +22,7 @@
#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)
#define CURSORROW 10 // Row cursor initially shown on (if enough text)
#define PROMPT_ROW NROWS + 1 // Row where input prompt is shown
#define IOSZ 1024 // Size of chunks to use when loading/saving file
@ -36,11 +35,11 @@
#define DELETE 0x7f
#ifdef AUXMEM
#define BUFSZ 0xb7fe // All of aux from 0x800 to 0xbfff, minus a byte
#define BUFSZ 0xb7fe // Aux from 0x800 to 0xbfff, minus a pad byte
char iobuf[IOSZ]; // Buffer for disk I/O
uint8_t banktbl[1+8*16]; // Handles up to 8MB. Map of banks.
uint8_t auxbank; // Currently selected aux bank (physical)
uint8_t l_auxbank; // Currently selected aux bank (logical)
uint8_t l_auxbank; // Currently selected aux bank (logical)
#else
#define BUFSZ (20480 - 1024) // 19KB
char gapbuf[BUFSZ];
@ -49,18 +48,20 @@ char padding = 0; // To null terminate for strstr()
// The following fields, plus the gap buffer, represent the state of
// the current buffer. These are stashed in each aux page from 0x200 up.
// Total 80 + 2 + 2 + 1 = 85 bytes
// Total 80 + 2 + 2 + 2 = 86 bytes
#define BUFINFOSZ 86
char filename[80] = "";
char status[2] = ""; // status[0] is 1 if file has been modified
// status[1] is 1 if should warn for overwrite
uint16_t gapbegin = 0;
uint16_t gapend = BUFSZ - 1;
uint8_t modified; // If 1, file contents have been modified
uint8_t rowlen[NROWS]; // Number of chars on each row of screen
char userentry[82] = ""; // Couple extra chars so we can store 80 col line
char search[80] = "";
char replace[80] = "";
uint8_t rowlen[NROWS]; // Number of chars on each row of screen
// Interface to read_char_update_pos()
uint8_t do_print;
uint16_t pos, startsel, endsel;
@ -438,7 +439,7 @@ void update_status_line(void) {
switch (mode) {
case SEL_NONE:
cprintf("OA-? Help | [%03u] %c File:%s %2uKB free",
l_auxbank, modified ? '*' : ' ', filename, (FREESPACE() + 512) / 1024);
l_auxbank, status[0] ? '*' : ' ', filename, (FREESPACE() + 512) / 1024);
l = 44 - strlen(filename);
break;
#ifdef OLD_SELMODE
@ -477,7 +478,7 @@ void update_status_line(void) {
break;
case SRCH3:
cprintf("OA-? Help | [%03u] %c File:%s %2uKB free | Not Found",
l_auxbank, modified ? '*' : ' ', filename, (FREESPACE() + 512) / 1024);
l_auxbank, status[0] ? '*' : ' ', filename, (FREESPACE() + 512) / 1024);
l = 44 - 12 - strlen(filename);
break;
}
@ -496,9 +497,9 @@ void update_status_line(void) {
* Set modified status
*/
void set_modified(uint8_t mod) {
if (modified == mod)
if (status[0] == mod)
return;
modified = mod;
status[0] = mod;
update_status_line();
}
@ -674,6 +675,68 @@ uint8_t next_tabstop(uint8_t col) {
return (col / 8) * 8 + 8;
}
#ifdef AUXMEM
#define FROMAUX 0
#define TOAUX 1
/*
* Copy to/from aux memory using AUXMOVE
*/
void copyaux(char *src, char *dst, uint16_t len, uint8_t dir) {
char **a1 = (char**)0x3c;
char **a2 = (char**)0x3e;
char **a4 = (char**)0x42;
*a1 = src;
*a2 = src + len - 1; // AUXMOVE moves length+1 bytes!!
*a4 = dst;
if (dir == TOAUX) {
__asm__("sec"); // Copy main->aux
__asm__("jsr $c311"); // AUXMOVE
} else {
__asm__("clc"); // Copy aux->main
__asm__("jsr $c311"); // AUXMOVE
}
}
#endif
/*
* Translate logic aux bank number to physical.
* This is necessary because there may be 'holes' in the banks
* Logical banks are numbered 1..maxbank contiguously.
* Physical banks start at 0 and may be non-contiguous.
*/
uint8_t bank_log_to_phys(uint8_t l) {
uint8_t i;
for (i = 1; i < 1+8*16; ++i)
if (banktbl[i] == l - 1)
return i - 1;
show_error("Bad bank"); // Should never happen
}
/*
* Change the active bank of aux memory
* Current physical bank is in auxbank
* logbank - desired logical bank
* Must be in LC.
*/
#ifdef AUXMEM
#pragma code-name (push, "LC")
void change_aux_bank(uint8_t logbank) {
l_auxbank = logbank;
// Saves filename[], gapbegin, gapend and modified (BUFINFOSZ bytes)
__asm__("lda %v", auxbank);
__asm__("sta $c073"); // Set aux bank
copyaux(filename, (void*)0x0200, BUFINFOSZ, TOAUX);
// Load new filename[], gapbegin, gapend and modified (BUFINFOSZ bytes)
auxbank = bank_log_to_phys(l_auxbank);
__asm__("lda %v", auxbank);
__asm__("sta $c073"); // Set aux bank
copyaux((void*)0x0200, filename, BUFINFOSZ, FROMAUX);
__asm__("lda #$00");
__asm__("sta $c073"); // Set aux bank back to 0
}
#pragma code-name (pop)
#endif
/*
* Load a file from disk into the gapbuf
* filename - name of file to load
@ -683,12 +746,13 @@ uint8_t next_tabstop(uint8_t col) {
* 1 if file can't be opened
*/
#pragma code-name (push, "LC")
uint8_t load_file(char *filename, uint8_t replace) {
uint8_t load_file(char *fname, uint8_t replace) {
uint8_t partctr = 0;
uint8_t col;
char *p;
uint16_t i, j, s;
uint8_t c, cont;
FILE *fp = fopen(filename, "r");
FILE *fp = fopen(fname, "r");
if (!fp)
return 1;
if (!replace)
@ -705,10 +769,25 @@ uint8_t load_file(char *filename, uint8_t replace) {
p = gapbuf + gapend - IOSZ; // Read to mem just before gapend
#endif
do {
#ifdef AUXMEM
if (replace) {
if (FREESPACE() < 15000) {
strcpy(userentry, filename);
change_aux_bank(++l_auxbank); /// TODO: EXPERIMENT!!!
sprintf(filename, "%s:%u", userentry, ++partctr);
}
} else {
if (FREESPACE() < IOSZ * 2) {
show_error("File truncated");
goto done;
}
}
#else
if (FREESPACE() < IOSZ * 2) {
show_error("File truncated");
goto done;
}
#endif
cputc('.');
s = fread(p, 1, IOSZ, fp);
cont = (s == IOSZ ? 1 : 0);
@ -729,19 +808,34 @@ uint8_t load_file(char *filename, uint8_t replace) {
set_gapbuf(gapbegin++, p[i]);
++col;
}
#ifdef AUXMEM
if (replace) {
if (FREESPACE() < 15000) {
strcpy(userentry, filename);
change_aux_bank(++l_auxbank); /// TODO: EXPERIMENT!!!
sprintf(filename, "%s:%u", userentry, ++partctr);
}
} else {
if (FREESPACE() < IOSZ * 2) {
show_error("File truncated");
goto done;
}
}
#else
if (FREESPACE() < IOSZ * 2) {
show_error("File truncated");
goto done;
}
#endif
}
} while (cont);
// --gapbegin; // Eat EOF character
done:
fclose(fp);
if (replace) {
jump_pos(0);
pos = 0;
set_modified(0);
status[1] = 0; // No need to prompt for overwrite on save
startsel = endsel = 65535U;
mode = SEL_NONE;
}
@ -755,6 +849,7 @@ done:
* copymode - if 1, copy test from startsel to endsel only
* Returns 0 on success
* 1 if file can't be opened
* 2 if user aborts
*/
#ifndef AUXMEM
#pragma code-name (push, "LC")
@ -770,6 +865,17 @@ uint8_t save_file(char *filename, uint8_t copymode) {
char *p;
#endif
FILE *fp;
// If status[1] is set, check for overwrite
if (!copymode && status[1]) {
fp = fopen(filename, "r");
if (fp) {
fclose(fp);
sprintf(userentry, "File '%s' exists, overwrite");
if (prompt_okay(userentry) != 0)
return 2;
}
fclose(fp);
}
_filetype = PRODOS_T_TXT;
_auxtype = 0;
fp = fopen(filename, "w");
@ -1272,26 +1378,22 @@ void goto_eol(void) {
/*
* Word left
*/
#pragma code-name (push, "LC")
void word_left(void) {
do {
cursor_left();
} while ((get_gapbuf(gapbegin) != ' ') && (get_gapbuf(gapbegin) != EOL) &&
(gapbegin > 0));
}
#pragma code-name (pop)
/*
* Word right
*/
#pragma code-name (push, "LC")
void word_right(void) {
do {
cursor_right();
} while ((get_gapbuf(gapbegin) != ' ') && (get_gapbuf(gapbegin) != EOL) &&
(gapend < BUFSZ - 1));
}
#pragma code-name (pop)
/*
* Jump forward 15 screen lines
@ -1359,7 +1461,6 @@ void word_wrap_para(uint8_t addbreaks) {
* Help screen
* EDITHELP.TXT is expected to contain lines of exactly 80 chars
*/
#pragma code-name (push, "LC")
void help(void) {
FILE *fp = fopen("EDITHELP.TXT", "rb");
char *p;
@ -1400,52 +1501,50 @@ done:
cgetc();
clrscr();
}
#pragma code-name (pop)
/*
* Load EMAIL.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_email(void) {
revers(0);
clrscr();
exec("EMAIL.SYSTEM", NULL); // Assume it is in current directory
}
#pragma code-name (pop)
/*
* 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)
/*
* Save file to disk, handle user interface
*/
void save(void) {
uint8_t rc;
if (strlen(filename) == 0) {
if (prompt_for_name("*UNSAVED CHANGES* File to save", 1) == 255)
status[1] = 1; // Prompt if save will overwrite existing file
sprintf(userentry, "[%03u] *UNSAVED CHANGES* File to save", l_auxbank);
if (prompt_for_name(userentry, 1) == 255)
return; // If ESC pressed
if (strlen(userentry) == 0)
return;
strcpy(filename, userentry);
}
sprintf(userentry, "Save to %s", filename);
if (prompt_okay(userentry) == 0) {
if (save_file(filename, 0)) {
sprintf(userentry, "Can't save %s", filename);
show_error(userentry);
draw_screen();
} else {
set_modified(0);
}
rc = save_file(filename, 0);
switch (rc) {
case 0: // Success
status[1] = 0; // No need to prompt for overwrite next time
set_modified(0);
break;
case 1: // Save error
sprintf(userentry, "Can't save '%s'", filename);
show_error(userentry);
draw_screen();
break;
}
}
@ -1522,31 +1621,12 @@ search:
mode = SEL_NONE;
}
#ifdef AUXMEM
#define FROMAUX 0
#define TOAUX 1
/*
* Copy to/from aux memory using AUXMOVE
*/
void copyaux(char *src, char *dst, uint16_t len, uint8_t dir) {
char **a1 = (char**)0x3c;
char **a2 = (char**)0x3e;
char **a4 = (char**)0x42;
*a1 = src;
*a2 = src + len - 1; // AUXMOVE moves length+1 bytes!!
*a4 = dst;
if (dir == TOAUX) {
__asm__("sec"); // Copy main->aux
__asm__("jsr $c311"); // AUXMOVE
} else {
__asm__("clc"); // Copy aux->main
__asm__("jsr $c311"); // AUXMOVE
}
}
#endif
/*
* Available aux banks. Taken from RamWorks III Manual p47
* banktbl is populated as follows:
* First byte is number of banks
* Following bytes are the logical bank numbers in physical bank order
* Final byte is $ff terminator
*/
void avail_aux_banks(void) {
__asm__("sta $c009"); // Store in ALTZP
@ -1577,7 +1657,7 @@ findthem:
__asm__("sta %v,x", banktbl);
__asm__("cpx #128"); // 8MB max
__asm__("bcs %g", done);
notone:
notone: // 'not one', not 'no tone' !
__asm__("iny");
__asm__("bpl %g", findthem);
done:
@ -1590,20 +1670,6 @@ done:
__asm__("sta %v,x", banktbl); // Terminator
}
/*
* Translate logic aux bank number to physical.
* This is necessary because there may be 'holes' in the banks
* Logical banks are numbered 1..maxbank contiguously.
* Physical banks start at 0 and may be non-contiguous.
*/
uint8_t bank_log_to_phys(uint8_t l) {
uint8_t i;
for (i = 1; i < 1+8*16; ++i)
if (banktbl[i] == l - 1)
return i - 1;
show_error("Bad bank"); // Should never happen
}
/*
* Initialize the data at 0x200 in each aux bank so that all buffers
* are empty, unmodified and without a filename
@ -1616,10 +1682,10 @@ void init_aux_banks(void) {
cprintf("\n\n\n%u x 64KB aux banks -> %uKB\n", banktbl[0], banktbl[0]*64);
for (i = 1; i < banktbl[0]; ++i) {
auxbank = bank_log_to_phys(i);
// Saves filename[], gapbegin, gapend and modified (85 bytes)
// Saves filename[], gapbegin, gapend and modified (BUFINFOSZ bytes)
__asm__("lda %v", auxbank);
__asm__("sta $c073"); // Set aux bank
copyaux(filename, (void*)0x0200, 85, TOAUX);
copyaux(filename, (void*)0x0200, BUFINFOSZ, TOAUX);
}
auxbank = 0;
l_auxbank = 1;
@ -1628,32 +1694,63 @@ void init_aux_banks(void) {
}
/*
* Change the active bank of aux memory
* Current physical bank is in auxbank
* logbank - desired logical bank
* Must be in LC.
* Generate buffer list
*/
#ifdef AUXMEM
#pragma code-name (push, "LC")
void change_aux_bank(uint8_t logbank) {
l_auxbank = logbank;
// Saves filename[], gapbegin, gapend and modified (85 bytes)
__asm__("lda %v", auxbank);
__asm__("sta $c073"); // Set aux bank
copyaux(filename, (void*)0x0200, 85, TOAUX);
// Load new filename[], gapbegin, gapend and modified (85 bytes)
auxbank = bank_log_to_phys(l_auxbank);
__asm__("lda %v", auxbank);
__asm__("sta $c073"); // Set aux bank
copyaux((void*)0x0200, filename, 85, FROMAUX);
__asm__("lda #$00");
__asm__("sta $c073"); // Set aux bank back to 0
startsel = endsel = 65535U;
draw_screen();
void buffer_list(void) {
uint8_t o_aux = l_auxbank, row = 0;
uint8_t i;
cursor(0);
for (i = 1; i < banktbl[0]; ++i) {
if (row == 0) {
clrscr();
cprintf("Buf Size Mod Filename\r");
gotoxy(0, ++row);
}
change_aux_bank(i);
cprintf("[%03u] %05u | %c | %s\r",
i, DATASIZE(), (status[0] ? '*' : ' '), filename);
if (DATASIZE() > 0)
gotoxy(0, ++row);
if (row == 22) {
cprintf("[Press Any Key]");
cgetc();
row = 0;
}
}
change_aux_bank(o_aux);
gotoxy(0, 23);
cprintf("[Press Any Key]");
cgetc();
}
#pragma code-name (pop)
#endif
/*
* Save all modified buffers
*/
#ifdef AUXMEM
#pragma code-name (push, "LC")
void save_all(void) {
uint8_t o_aux = l_auxbank;
uint8_t i;
cursor(0);
for (i = 1; i < banktbl[0]; ++i) {
change_aux_bank(i);
if (status[0]) { // If buffer is modified
draw_screen();
save();
}
}
change_aux_bank(o_aux);
}
#pragma code-name (pop)
#endif
/*
* Sort startsel / endsel in ascending order to allow backwards selection
*/
void order_selection(void) {
uint16_t tmp;
if (startsel > endsel) {
@ -1675,7 +1772,7 @@ int edit(char *fname) {
strcpy(filename, fname);
cprintf("Loading file %s ", filename);
if (load_file(filename, 1)) {
sprintf(userentry, "Can't load %s", filename);
sprintf(userentry, "Can't load '%s'", filename);
show_error(userentry);
strcpy(filename, "");
}
@ -1781,7 +1878,7 @@ int edit(char *fname) {
break;
}
order_selection();
if (save_file("CLIPBOARD", 1)) {
if (save_file("CLIPBOARD", 1) == 1) {
show_error("Can't save CLIPBOARD");
draw_screen();
break;
@ -1868,7 +1965,7 @@ int edit(char *fname) {
break;
case 0x80 + 'L': // OA-L "Load"
case 0x80 + 'l':
if (modified)
if (status[0])
save();
if (prompt_for_name("File to load", 1) == 255)
break; // ESC pressed
@ -1883,7 +1980,7 @@ int edit(char *fname) {
gapend = BUFSZ - 1;
strcpy(filename, userentry);
if (load_file(filename, 1)) {
sprintf(userentry, "Can't load %s", filename);
sprintf(userentry, "Can't load '%s'", filename);
show_error(userentry);
strcpy(filename, "");
}
@ -1908,12 +2005,12 @@ int edit(char *fname) {
if (strlen(userentry) == 0)
break;
strcpy(filename, userentry);
status[1] = 1; // Should prompt if overwriting file on save
update_status_line();
break;
case 0x80 + 'Q': // OA-Q "Quit"
case 0x80 + 'q': // OA-q
if (modified)
save();
save_all();
if (quit_to_email) {
if (prompt_okay("Add attachments") == 0)
load_attacher();
@ -1942,6 +2039,11 @@ int edit(char *fname) {
save();
draw_screen();
break;
case 0x80 + 'A': // OA-A "Save All"
case 0x80 + 'a': // OA-a
save_all();
draw_screen();
break;
case 0x80 + DELETE: // OA-Backspace
case 0x04: // Ctrl-D "DELETE"
if (mode == SEL_NONE) {
@ -2072,10 +2174,10 @@ copymove2_cleanup:
// CA-number (1-9) - quick jump to first 9 buffers
if ((c >= '1') && (c <= '9')) {
change_aux_bank(c - '0');
startsel = endsel = 65535U;
draw_screen();
break;
}
// CA-B "Buffer"
if ((c == 'B') || (c == 'b')) {
} else if ((c == 'B') || (c == 'b')) { // CA-B "Buffer"
sprintf(userentry, "Buffer # (1-%u)", banktbl[0]);
if (prompt_for_name(userentry, 0) == 255)
break;
@ -2087,6 +2189,12 @@ copymove2_cleanup:
break;
}
change_aux_bank(tmp);
startsel = endsel = 65535U;
draw_screen();
break;
} else if ((c == 'L') || (c == 'l')) {
buffer_list();
draw_screen();
break;
}
#endif