2012-03-11 10:57:13 -04:00
|
|
|
/*******************************************************************************
|
|
|
|
|
2013-07-10 09:26:01 -04:00
|
|
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
2012-03-11 10:57:13 -04:00
|
|
|
|
2013-07-10 09:26:01 -04:00
|
|
|
This program is free software: you can redistribute it and/or modify it
|
|
|
|
under the terms of the GNU General Public License as published by the Free
|
|
|
|
Software Foundation, either version 3 of the License, or (at your option)
|
|
|
|
any later version.
|
2012-03-11 10:57:13 -04:00
|
|
|
|
2013-07-10 09:26:01 -04:00
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
more details.
|
2012-03-11 10:57:13 -04:00
|
|
|
|
2013-07-10 09:26:01 -04:00
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
|
|
this program. If not, see <http://www.gnu.org/licenses/>.
|
2012-03-11 10:57:13 -04:00
|
|
|
|
2013-07-10 09:26:01 -04:00
|
|
|
editor.cpp
|
|
|
|
A simple and hacked together text editor.
|
2012-03-11 10:57:13 -04:00
|
|
|
|
|
|
|
*******************************************************************************/
|
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
#include <sys/keycodes.h>
|
|
|
|
#include <sys/termmode.h>
|
2011-11-18 18:56:55 -05:00
|
|
|
#include <stdio.h>
|
2012-01-22 17:46:41 -05:00
|
|
|
#include <stdlib.h>
|
2011-11-18 18:56:55 -05:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <string.h>
|
2011-11-22 11:26:47 -05:00
|
|
|
#include <errno.h>
|
2011-11-26 05:00:45 -05:00
|
|
|
#include <error.h>
|
2012-07-29 17:41:36 -04:00
|
|
|
#include <termios.h>
|
2011-11-18 18:56:55 -05:00
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
const int MODE_QUIT = 1;
|
|
|
|
const int MODE_TEXT = 2;
|
|
|
|
const int MODE_CONFIRM_QUIT = 3;
|
|
|
|
const int MODE_SAVE = 4;
|
|
|
|
const int MODE_LOAD = 5;
|
2011-11-18 18:56:55 -05:00
|
|
|
|
|
|
|
const unsigned WIDTH = 80;
|
|
|
|
const unsigned HEIGHT = 24;
|
|
|
|
char buffers[HEIGHT+1][WIDTH+1];
|
|
|
|
|
|
|
|
unsigned cursorx = 0;
|
|
|
|
unsigned cursory = 0;
|
|
|
|
unsigned numlines = 1;
|
|
|
|
|
|
|
|
char filename[256];
|
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
bool bufferchanged = false;
|
2011-11-18 18:56:55 -05:00
|
|
|
|
|
|
|
void clearbuffers()
|
|
|
|
{
|
|
|
|
for ( unsigned y = 0; y < HEIGHT + 1; y++ )
|
|
|
|
{
|
|
|
|
for ( unsigned x = 0; x < WIDTH + 1; x++ ) { buffers[y][x] = 0; }
|
|
|
|
}
|
|
|
|
|
|
|
|
bufferchanged = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cursorto(unsigned x, unsigned y)
|
|
|
|
{
|
|
|
|
printf("\e[%u;%uH", y+1+1, x+1);
|
Implemented large parts of the stdio(3), including fprintf.
Made FILE an interface to various backends. This allows application writers
to override the standard FILE API functions with their own backends. This
is highly unportable - it'd be nice if a real standard existed for this.
glibc already does something like this internally, but AFAIK you can't hook
into it.
Added fdopen(3), fopen(3), fregister(3), funregister(3), fread(3),
fwrite(3), fseek(3), clearerr(3), ferror(3), feof(3), rewind(3), ftell(3),
fflush(3), fclose(3), fileno(3), fnewline(3), fcloseall(3), memset(3),
stdio(3), vfprintf(3), fprintf(3), and vprintf(3).
Added a file-descriptor backend to the FILE API.
fd's {0, 1, 2} are now initialized as stdin, stdout, and stderr when the
standard library initializes.
fcloseall(3) is now called on exit(3).
decl/intn_t_.h now @include(size_t.h) instead of declaring it itself.
Added <stdint.h>.
The following programs now flush stdout: cat(1), clear(1), editor(1),
init(1), mxsh(1).
printf(3) is now hooked up against vprintf(3), while Maxsi::PrintF
remains using the system call, for now.
2011-12-23 22:08:10 -05:00
|
|
|
fflush(stdout);
|
2011-11-18 18:56:55 -05:00
|
|
|
}
|
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
char* readline(int fd)
|
|
|
|
{
|
|
|
|
unsigned oldtermmode;
|
|
|
|
if ( gettermmode(fd, &oldtermmode) ) { return NULL; }
|
|
|
|
|
|
|
|
unsigned termmode = TERMMODE_UNICODE
|
|
|
|
| TERMMODE_SIGNAL
|
|
|
|
| TERMMODE_UTF8
|
|
|
|
| TERMMODE_LINEBUFFER
|
|
|
|
| TERMMODE_ECHO;
|
|
|
|
if ( settermmode(fd, termmode) ) { return NULL; }
|
|
|
|
|
|
|
|
size_t lineused = 0;
|
|
|
|
size_t linelength = 32UL;
|
|
|
|
char* line = new char[linelength + 1];
|
|
|
|
line[0] = '\0';
|
|
|
|
|
|
|
|
while ( true )
|
|
|
|
{
|
|
|
|
char c;
|
|
|
|
ssize_t numbytes = read(fd, &c, sizeof(c));
|
|
|
|
if ( numbytes < 0 ) { delete[] line; line = NULL; break; }
|
|
|
|
if ( !numbytes ) { break; }
|
|
|
|
if ( c == '\n' ) { break; }
|
|
|
|
|
|
|
|
if ( lineused == linelength )
|
|
|
|
{
|
|
|
|
size_t newlinelength = 2 * linelength;
|
|
|
|
char* newline = new char[newlinelength];
|
|
|
|
if ( !newline ) { delete[] line; line = NULL; break; }
|
|
|
|
memcpy(newline, line, lineused * sizeof(*line));
|
|
|
|
delete[] line;
|
|
|
|
line = newline;
|
|
|
|
linelength = newlinelength;
|
|
|
|
}
|
|
|
|
|
|
|
|
line[lineused++] = c;
|
|
|
|
line[lineused] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( settermmode(fd, oldtermmode) ) { delete[] line; line = NULL; }
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
2011-11-18 18:56:55 -05:00
|
|
|
void drawtextmode()
|
|
|
|
{
|
|
|
|
const char* printfilename = ( strlen(filename) > 0 ) ? filename : "New Buffer";
|
|
|
|
printf("\e[30m\e[47m\e[2J\e[H");
|
|
|
|
printf("Text Editor\t\tfile: %s\n", printfilename);
|
|
|
|
printf("\e[37m\e[40m\e[0J");
|
|
|
|
for ( unsigned y = 0; y < HEIGHT; y++ )
|
|
|
|
{
|
|
|
|
printf("%s", buffers[y]);
|
|
|
|
if ( y < HEIGHT-1 ) { printf("\n"); }
|
|
|
|
}
|
|
|
|
|
Implemented large parts of the stdio(3), including fprintf.
Made FILE an interface to various backends. This allows application writers
to override the standard FILE API functions with their own backends. This
is highly unportable - it'd be nice if a real standard existed for this.
glibc already does something like this internally, but AFAIK you can't hook
into it.
Added fdopen(3), fopen(3), fregister(3), funregister(3), fread(3),
fwrite(3), fseek(3), clearerr(3), ferror(3), feof(3), rewind(3), ftell(3),
fflush(3), fclose(3), fileno(3), fnewline(3), fcloseall(3), memset(3),
stdio(3), vfprintf(3), fprintf(3), and vprintf(3).
Added a file-descriptor backend to the FILE API.
fd's {0, 1, 2} are now initialized as stdin, stdout, and stderr when the
standard library initializes.
fcloseall(3) is now called on exit(3).
decl/intn_t_.h now @include(size_t.h) instead of declaring it itself.
Added <stdint.h>.
The following programs now flush stdout: cat(1), clear(1), editor(1),
init(1), mxsh(1).
printf(3) is now hooked up against vprintf(3), while Maxsi::PrintF
remains using the system call, for now.
2011-12-23 22:08:10 -05:00
|
|
|
fflush(stdout);
|
2011-11-18 18:56:55 -05:00
|
|
|
cursorto(cursorx, cursory);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned textmode()
|
|
|
|
{
|
|
|
|
drawtextmode();
|
|
|
|
|
|
|
|
bool ctrl = false;
|
2012-01-22 17:46:41 -05:00
|
|
|
unsigned dectrlmode = 0;
|
2011-11-18 18:56:55 -05:00
|
|
|
|
2011-11-24 13:27:24 -05:00
|
|
|
int oldcursorx = -1;
|
|
|
|
int oldcursory = -1;
|
2011-11-18 18:56:55 -05:00
|
|
|
while ( true )
|
|
|
|
{
|
2012-09-08 14:55:43 -04:00
|
|
|
if ( oldcursorx != (int) cursorx || oldcursory != (int) cursory )
|
2011-11-24 13:27:24 -05:00
|
|
|
{
|
|
|
|
cursorto(cursorx, cursory);
|
|
|
|
oldcursorx = cursorx;
|
|
|
|
oldcursory = cursory;
|
|
|
|
}
|
2011-11-18 18:56:55 -05:00
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
unsigned termmode = TERMMODE_KBKEY | TERMMODE_UNICODE | TERMMODE_SIGNAL;
|
|
|
|
if ( settermmode(0, termmode) ) { error(1, errno, "settermmode"); }
|
2011-11-18 18:56:55 -05:00
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
uint32_t codepoint = 0;
|
|
|
|
ssize_t numbytes = read(0, &codepoint, sizeof(codepoint));
|
|
|
|
if ( !numbytes ) { break; }
|
|
|
|
if ( numbytes < 0 ) { error(1, errno, "read stdin"); }
|
2012-09-08 14:55:43 -04:00
|
|
|
if ( numbytes < (ssize_t) sizeof(codepoint) ) {
|
2012-01-22 17:46:41 -05:00
|
|
|
printf("unexpectedly got %zi bytes\n", numbytes);
|
|
|
|
printf("bytes: %x\n", codepoint);
|
2011-11-18 18:56:55 -05:00
|
|
|
|
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
fprintf(stderr, "bad stdin data\n"); exit(1); }
|
|
|
|
if ( !codepoint ) { continue; }
|
|
|
|
int kbkey = KBKEY_DECODE(codepoint);
|
|
|
|
if ( kbkey )
|
2011-11-18 18:56:55 -05:00
|
|
|
{
|
2012-01-22 17:46:41 -05:00
|
|
|
if ( kbkey == -KBKEY_LCTRL && dectrlmode ) { return dectrlmode; }
|
|
|
|
int abskbkey = (kbkey < 0) ? -kbkey : kbkey;
|
|
|
|
if ( abskbkey == KBKEY_LCTRL ) { ctrl = (0 < kbkey); continue; }
|
|
|
|
switch ( kbkey )
|
|
|
|
{
|
|
|
|
case -KBKEY_ESC:
|
2011-11-18 18:56:55 -05:00
|
|
|
return MODE_CONFIRM_QUIT;
|
|
|
|
break;
|
2012-01-22 17:46:41 -05:00
|
|
|
case KBKEY_UP:
|
2011-11-18 18:56:55 -05:00
|
|
|
if ( cursory ) { cursory--; }
|
|
|
|
break;
|
2012-01-22 17:46:41 -05:00
|
|
|
case KBKEY_DOWN:
|
2011-11-18 18:56:55 -05:00
|
|
|
if ( cursory < numlines-1 ) { cursory++; }
|
|
|
|
break;
|
2012-01-22 17:46:41 -05:00
|
|
|
case KBKEY_LEFT:
|
2011-11-18 18:56:55 -05:00
|
|
|
if ( cursorx ) { cursorx--; }
|
|
|
|
break;
|
2012-01-22 17:46:41 -05:00
|
|
|
case KBKEY_RIGHT:
|
2011-11-18 18:56:55 -05:00
|
|
|
if ( cursorx < WIDTH-1 ) { cursorx++; }
|
|
|
|
break;
|
2012-01-22 17:46:41 -05:00
|
|
|
case KBKEY_O:
|
2012-03-21 19:52:29 -04:00
|
|
|
if ( ctrl ) { dectrlmode = MODE_SAVE; }
|
2012-01-22 17:46:41 -05:00
|
|
|
break;
|
|
|
|
case KBKEY_R:
|
2012-03-21 19:52:29 -04:00
|
|
|
if ( ctrl ) { dectrlmode = MODE_LOAD; }
|
2012-01-22 17:46:41 -05:00
|
|
|
break;
|
|
|
|
case KBKEY_X:
|
2012-03-21 19:52:29 -04:00
|
|
|
if ( ctrl ) { dectrlmode = MODE_CONFIRM_QUIT; }
|
2012-01-22 17:46:41 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ctrl ) { continue; }
|
|
|
|
|
|
|
|
switch ( codepoint )
|
|
|
|
{
|
|
|
|
case '\n':
|
|
|
|
cursorx = 0;
|
|
|
|
if ( cursory < HEIGHT-1 ) { numlines++; cursory++; }
|
|
|
|
break;
|
2011-11-18 18:56:55 -05:00
|
|
|
case '\b':
|
|
|
|
if ( cursorx )
|
|
|
|
{
|
|
|
|
cursorx--;
|
|
|
|
|
|
|
|
for ( unsigned x = cursorx; x < WIDTH; x++ )
|
|
|
|
{
|
|
|
|
buffers[cursory][x] = buffers[cursory][x+1];
|
|
|
|
bufferchanged = true;
|
|
|
|
}
|
Implemented large parts of the stdio(3), including fprintf.
Made FILE an interface to various backends. This allows application writers
to override the standard FILE API functions with their own backends. This
is highly unportable - it'd be nice if a real standard existed for this.
glibc already does something like this internally, but AFAIK you can't hook
into it.
Added fdopen(3), fopen(3), fregister(3), funregister(3), fread(3),
fwrite(3), fseek(3), clearerr(3), ferror(3), feof(3), rewind(3), ftell(3),
fflush(3), fclose(3), fileno(3), fnewline(3), fcloseall(3), memset(3),
stdio(3), vfprintf(3), fprintf(3), and vprintf(3).
Added a file-descriptor backend to the FILE API.
fd's {0, 1, 2} are now initialized as stdin, stdout, and stderr when the
standard library initializes.
fcloseall(3) is now called on exit(3).
decl/intn_t_.h now @include(size_t.h) instead of declaring it itself.
Added <stdint.h>.
The following programs now flush stdout: cat(1), clear(1), editor(1),
init(1), mxsh(1).
printf(3) is now hooked up against vprintf(3), while Maxsi::PrintF
remains using the system call, for now.
2011-12-23 22:08:10 -05:00
|
|
|
printf("\e[2K\r%s", buffers[cursory]);
|
|
|
|
fflush(stdout);
|
2011-11-18 18:56:55 -05:00
|
|
|
}
|
|
|
|
else if ( 0 < cursory && strlen(buffers[cursory]) == 0 )
|
|
|
|
{
|
|
|
|
for ( unsigned y = cursory; y < numlines; y++ )
|
|
|
|
{
|
|
|
|
for ( unsigned x = 0; x < WIDTH; x++ )
|
|
|
|
{
|
|
|
|
buffers[y][x] = buffers[y+1][x];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
numlines--;
|
|
|
|
cursory--;
|
|
|
|
cursorx = strlen(buffers[cursory]);
|
|
|
|
|
|
|
|
drawtextmode();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t linelen = strlen(buffers[cursory]);
|
|
|
|
if ( linelen < cursorx ) { cursorx = linelen; }
|
|
|
|
|
|
|
|
if ( WIDTH <= cursorx ) { continue; }
|
|
|
|
if ( codepoint >= 0x80 ) { continue; }
|
|
|
|
if ( codepoint == '\t' ) { continue; }
|
|
|
|
if ( codepoint == '\b' ) { continue; }
|
|
|
|
if ( codepoint == '\n' ) { continue; }
|
|
|
|
if ( codepoint == '\r' ) { continue; }
|
|
|
|
|
|
|
|
char msg[2];
|
|
|
|
msg[0] = codepoint;
|
|
|
|
msg[1] = 0;
|
|
|
|
printf("%s", msg);
|
|
|
|
buffers[cursory][cursorx++] = codepoint;
|
Implemented large parts of the stdio(3), including fprintf.
Made FILE an interface to various backends. This allows application writers
to override the standard FILE API functions with their own backends. This
is highly unportable - it'd be nice if a real standard existed for this.
glibc already does something like this internally, but AFAIK you can't hook
into it.
Added fdopen(3), fopen(3), fregister(3), funregister(3), fread(3),
fwrite(3), fseek(3), clearerr(3), ferror(3), feof(3), rewind(3), ftell(3),
fflush(3), fclose(3), fileno(3), fnewline(3), fcloseall(3), memset(3),
stdio(3), vfprintf(3), fprintf(3), and vprintf(3).
Added a file-descriptor backend to the FILE API.
fd's {0, 1, 2} are now initialized as stdin, stdout, and stderr when the
standard library initializes.
fcloseall(3) is now called on exit(3).
decl/intn_t_.h now @include(size_t.h) instead of declaring it itself.
Added <stdint.h>.
The following programs now flush stdout: cat(1), clear(1), editor(1),
init(1), mxsh(1).
printf(3) is now hooked up against vprintf(3), while Maxsi::PrintF
remains using the system call, for now.
2011-12-23 22:08:10 -05:00
|
|
|
fflush(stdout);
|
2011-11-18 18:56:55 -05:00
|
|
|
bufferchanged = true;
|
|
|
|
if ( WIDTH <= cursorx ) { cursorx = WIDTH-1; }
|
|
|
|
}
|
|
|
|
|
|
|
|
return MODE_QUIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned confirmquit()
|
|
|
|
{
|
|
|
|
if ( !bufferchanged ) { return MODE_QUIT; }
|
|
|
|
|
|
|
|
printf("\e37m\e40m\e[2J\e[H");
|
|
|
|
printf("There are unsaved changes: Are you sure you want to quit? (Y/N)\n");
|
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
if ( settermmode(0, TERMMODE_KBKEY | TERMMODE_SIGNAL | TERMMODE_ECHO) )
|
2011-11-18 18:56:55 -05:00
|
|
|
{
|
2012-01-22 17:46:41 -05:00
|
|
|
error(1, errno, "settermmode");
|
|
|
|
}
|
2011-11-18 18:56:55 -05:00
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
while ( true )
|
|
|
|
{
|
|
|
|
uint32_t codepoint;
|
|
|
|
ssize_t numbytes = read(0, &codepoint, sizeof(codepoint));
|
|
|
|
if ( !numbytes ) { exit(0); }
|
|
|
|
if ( numbytes < 0 ) { error(1, errno, "read stdin"); }
|
2012-09-08 14:55:43 -04:00
|
|
|
if ( numbytes < (ssize_t) sizeof(codepoint) ) { fprintf(stderr, "bad stdin data\n"); exit(1); }
|
2012-01-22 17:46:41 -05:00
|
|
|
if ( !codepoint ) { continue; }
|
|
|
|
|
|
|
|
int kbkey = KBKEY_DECODE(codepoint);
|
|
|
|
if ( !kbkey ) { continue; }
|
|
|
|
if ( 0 < kbkey ) { continue; }
|
|
|
|
|
|
|
|
switch ( kbkey )
|
2011-11-18 18:56:55 -05:00
|
|
|
{
|
2012-01-22 17:46:41 -05:00
|
|
|
case -KBKEY_ESC:
|
2011-11-18 18:56:55 -05:00
|
|
|
return MODE_QUIT;
|
|
|
|
break;
|
2012-01-22 17:46:41 -05:00
|
|
|
case -KBKEY_N:
|
2011-11-18 18:56:55 -05:00
|
|
|
return MODE_TEXT;
|
2012-01-22 17:46:41 -05:00
|
|
|
case -KBKEY_Y:
|
2011-11-18 18:56:55 -05:00
|
|
|
return MODE_QUIT;
|
|
|
|
default:
|
|
|
|
printf("Would you like to quit? N for No, Y for Yes\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool savetofile(const char* path)
|
|
|
|
{
|
|
|
|
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0777);
|
2011-11-26 05:00:45 -05:00
|
|
|
if ( fd < 0 ) { error(0, errno, "%s", path); return false; }
|
2011-11-18 18:56:55 -05:00
|
|
|
|
|
|
|
for ( unsigned y = 0; y < numlines; y++ )
|
|
|
|
{
|
|
|
|
size_t len = strlen(buffers[y]);
|
|
|
|
buffers[y][len] = '\n';
|
2012-03-24 10:34:30 -04:00
|
|
|
bool result = writeall(fd, buffers[y], len+1) == len+1;
|
2011-11-18 18:56:55 -05:00
|
|
|
buffers[y][len] = 0;
|
2011-11-26 05:00:45 -05:00
|
|
|
if ( !result ) { error(0, errno, "write: %s", path); close(fd); return false; }
|
2011-11-18 18:56:55 -05:00
|
|
|
}
|
|
|
|
|
2011-11-26 05:00:45 -05:00
|
|
|
if ( close(fd) ) { error(0, errno, "close: %s", path); return false; }
|
2012-01-22 17:46:41 -05:00
|
|
|
strcpy(filename, path);
|
2011-11-18 18:56:55 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int savemode()
|
|
|
|
{
|
|
|
|
printf("\e37m\e40m\e[2J\e[H");
|
|
|
|
printf("Please enter the filename you wish to save the text to and press "
|
2012-01-22 17:46:41 -05:00
|
|
|
"enter. Type an empty filename to abort.\n\n");
|
2011-11-18 18:56:55 -05:00
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
char* storage = NULL;
|
2011-11-18 18:56:55 -05:00
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
do
|
2011-11-18 18:56:55 -05:00
|
|
|
{
|
2012-01-22 17:46:41 -05:00
|
|
|
delete[] storage;
|
|
|
|
printf("File to Write: ");
|
|
|
|
fflush(stdout);
|
|
|
|
storage = readline(0);
|
|
|
|
if ( !storage ) { error(1, errno, "readline"); }
|
|
|
|
if ( !storage[0] ) { delete[] storage; return MODE_TEXT; }
|
|
|
|
} while ( !savetofile(storage) );
|
|
|
|
delete[] storage;
|
2011-11-18 18:56:55 -05:00
|
|
|
|
|
|
|
bufferchanged = false;
|
|
|
|
|
|
|
|
printf("Succesfully saved\n");
|
|
|
|
sleep(1);
|
|
|
|
return MODE_TEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool loadfromfile(const char* path)
|
|
|
|
{
|
|
|
|
int fd = open(path, O_RDONLY, 0777);
|
2011-11-26 05:00:45 -05:00
|
|
|
if ( fd < 0 ) { error(0, errno, "%s", path); return false; }
|
2011-11-18 18:56:55 -05:00
|
|
|
|
|
|
|
clearbuffers();
|
|
|
|
|
|
|
|
const size_t BUFFER_SIZE = 256;
|
|
|
|
char buffer[BUFFER_SIZE];
|
|
|
|
|
|
|
|
bool done = false;
|
|
|
|
while ( !done )
|
|
|
|
{
|
|
|
|
ssize_t bytesread = read(fd, buffer, BUFFER_SIZE);
|
2011-11-26 05:00:45 -05:00
|
|
|
if ( bytesread < 0 ) { error(0, errno, "read: %s", path); close(fd); return false; }
|
2011-11-18 18:56:55 -05:00
|
|
|
if ( bytesread == 0 ) { break; }
|
|
|
|
for ( ssize_t i = 0; i < bytesread; i++ )
|
|
|
|
{
|
|
|
|
if ( buffer[i] == '\n' )
|
|
|
|
{
|
|
|
|
if ( HEIGHT-1 <= ++cursory ) { done = true; break; }
|
|
|
|
cursorx = 0;
|
|
|
|
continue;
|
|
|
|
}
|
2012-03-21 19:52:29 -04:00
|
|
|
|
|
|
|
if ( WIDTH <= cursorx ) { continue; }
|
2011-11-18 18:56:55 -05:00
|
|
|
buffers[cursory][cursorx++] = buffer[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
numlines = cursory + 1;
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
cursorx = 0;
|
|
|
|
cursory = 0;
|
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
strcpy(filename, path);
|
|
|
|
|
2011-11-18 18:56:55 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int loadmode()
|
|
|
|
{
|
|
|
|
printf("\e37m\e40m\e[2J\e[H");
|
|
|
|
printf("Please enter the filename you wish to load text from and press "
|
2012-01-22 17:46:41 -05:00
|
|
|
"enter. Type an empty filename to abort.\n\n");
|
2011-11-18 18:56:55 -05:00
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
char* storage = NULL;
|
2011-11-18 18:56:55 -05:00
|
|
|
|
2012-01-22 17:46:41 -05:00
|
|
|
do
|
2011-11-18 18:56:55 -05:00
|
|
|
{
|
2012-01-22 17:46:41 -05:00
|
|
|
delete[] storage;
|
|
|
|
printf("File to Load: ");
|
|
|
|
fflush(stdout);
|
|
|
|
storage = readline(0);
|
|
|
|
if ( !storage ) { error(1, errno, "readline"); }
|
|
|
|
if ( !storage[0] ) { delete[] storage; return MODE_TEXT; }
|
|
|
|
} while ( !loadfromfile(storage) );
|
|
|
|
delete[] storage;
|
2011-11-18 18:56:55 -05:00
|
|
|
|
|
|
|
bufferchanged = false;
|
|
|
|
|
|
|
|
return MODE_TEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void run()
|
|
|
|
{
|
|
|
|
bufferchanged = false;
|
|
|
|
|
|
|
|
unsigned mode = MODE_TEXT;
|
2012-09-08 14:55:43 -04:00
|
|
|
while ( mode != (unsigned) MODE_QUIT )
|
2011-11-18 18:56:55 -05:00
|
|
|
{
|
|
|
|
switch ( mode )
|
|
|
|
{
|
|
|
|
case MODE_TEXT:
|
|
|
|
mode = textmode();
|
|
|
|
break;
|
|
|
|
case MODE_CONFIRM_QUIT:
|
|
|
|
mode = confirmquit();
|
|
|
|
break;
|
|
|
|
case MODE_SAVE:
|
|
|
|
mode = savemode();
|
|
|
|
break;
|
|
|
|
case MODE_LOAD:
|
|
|
|
mode = loadmode();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("Application Bug: Unknown Mode\n");
|
|
|
|
sleep(1);
|
|
|
|
mode = MODE_TEXT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("\e[37m\e[40m\e[2J\e[H");
|
Implemented large parts of the stdio(3), including fprintf.
Made FILE an interface to various backends. This allows application writers
to override the standard FILE API functions with their own backends. This
is highly unportable - it'd be nice if a real standard existed for this.
glibc already does something like this internally, but AFAIK you can't hook
into it.
Added fdopen(3), fopen(3), fregister(3), funregister(3), fread(3),
fwrite(3), fseek(3), clearerr(3), ferror(3), feof(3), rewind(3), ftell(3),
fflush(3), fclose(3), fileno(3), fnewline(3), fcloseall(3), memset(3),
stdio(3), vfprintf(3), fprintf(3), and vprintf(3).
Added a file-descriptor backend to the FILE API.
fd's {0, 1, 2} are now initialized as stdin, stdout, and stderr when the
standard library initializes.
fcloseall(3) is now called on exit(3).
decl/intn_t_.h now @include(size_t.h) instead of declaring it itself.
Added <stdint.h>.
The following programs now flush stdout: cat(1), clear(1), editor(1),
init(1), mxsh(1).
printf(3) is now hooked up against vprintf(3), while Maxsi::PrintF
remains using the system call, for now.
2011-12-23 22:08:10 -05:00
|
|
|
fflush(stdout);
|
2011-11-18 18:56:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
2011-11-26 14:56:45 -05:00
|
|
|
if ( !isatty(1) ) { error(1, errno, "stdout must be a tty"); return 1; }
|
2012-07-29 17:41:36 -04:00
|
|
|
struct winsize ws;
|
|
|
|
if ( tcgetwinsize(1, &ws) != 0 )
|
|
|
|
error(1, errno, "tcgetwinsize");
|
|
|
|
if ( ws.ws_col != 80 || ws.ws_row != 25 )
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Sorry, this application only works with 80x25 "
|
|
|
|
"terminal resolutions, please fix it. :)\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2011-11-26 14:56:45 -05:00
|
|
|
|
2011-11-18 18:56:55 -05:00
|
|
|
if ( argc < 2 )
|
|
|
|
{
|
|
|
|
clearbuffers();
|
|
|
|
strcpy(filename, "");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(filename, argv[1]);
|
|
|
|
if ( !loadfromfile(filename) ) { clearbuffers(); }
|
|
|
|
cursorx = 0;
|
|
|
|
cursory = 0;
|
|
|
|
}
|
2012-03-21 19:52:29 -04:00
|
|
|
|
2011-11-18 18:56:55 -05:00
|
|
|
run();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|