backed up and did some minor optimizations

master
ElectricAlchemist 5 years ago
parent 1ba416bb97
commit 70acc3bd6b
  1. 3
      Makefile
  2. BIN
      ste
  3. 644
      ste.bak
  4. 29
      ste.c

@ -1,7 +1,8 @@
CC=gcc
CFLAGS=-Wall -Wextra -pedantic -Werror
OFLAGS=-O3
LFLAGS=-lncursesw -ltcmalloc
LFLAGS=-lncursesw
#-ltcmalloc
ste: ste.c
$(CC) $(CFLAGS) $(OFLAGS) $(LFLAGS) -o ste $^

BIN
ste

Binary file not shown.

@ -0,0 +1,644 @@
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* defines */
#define CTRL(k) ((k) & 0x1f) // Control mask modifier
#define TABSIZE 4 // Tab size as used in render
/* main data structure containing:
* -cursor position
* +real (matching memory)
* +offset (memory and screen offset)
* +render (drawn on the screen)
* -window size
* -statusbar message */
struct term {
struct {
int x;
int y;
int off_x;
int off_y;
int r_x;
int r_y;
int xx;
int yy;
} cur;
struct {
int x;
int y;
} dim;
char statusbar[30];
int pad;
} t;
/* Row structure, defines actual and
* render chars, actual and render size
* and difference between render and
* real size of the row */
typedef struct row {
int size;
char *chars;
int r_size;
char *render;
int delta;
} row;
/* Rows structure (or file buffer)
* defines rows and teh number of rows */
struct {
row *rw;
long rownum;
} rows;
/* Prototypes */
/* draw operations */
static void drawBar (char *s);
static void drawScreen ();
static void drawLines (void);
static void updateRender (row *rw);
static void updateScroll (void);
static void cursorMove(int a);
static int decimalSize (int n);
static inline void lnMove (int y, int x);
static int curRealToRender (row *rw, int c_x);
/* Row operations */
static inline void rowInit (void);
static void rowAddChar (row *rw, char c);
static void rowDeleteChar (row *rw, int m);
static void rowCpy (row *to, row *from);
/* Terminal operations */
static void termInit (void);
static void termExit (void);
static void termDie (char *s);
/* file operations */
static void fileOpen (char *filename);
void fileSave (char *filename);
/* buffer operations */
static void rowAddLast (char *s, int len);
/* garbage */
/* testing */
static void updateInfo (void);
static void rowAddRow (int pos);
static int whatsThat (void);
static void rowFree (row *rw);
/* --------------------------------- main ------------------------------------ */
int main (int argc, char *argv[])
{
/* Initialize the first row */
rowInit();
/* Try to open the file */
if (argc != 2) {
perror("File not found");
exit(1);
} else fileOpen(argv[1]);
/* Initialize the terminal in raw mode,
* start curses and initialize the term struct */
termInit();
/* Set the statusbar left (static) message */
sprintf(t.statusbar, "%s : %s %ld lines %dx%d", argv[0], argv[1], rows.rownum, t.dim.y, t.dim.y);
/* remember the initial row number */
int irow = decimalSize(rows.rownum);
/* Main event loop */
int c;
while (1) {
/* Redraw the screen */
drawScreen();
/* Wait for an event (keypress) */
switch (c = getch()) {
case (CTRL('q')):
termExit();
break;
case (KEY_LEFT):
case (KEY_RIGHT):
case (KEY_UP):
case (KEY_DOWN):
cursorMove(c);
break;
case (KEY_BACKSPACE):
rowDeleteChar(&rows.rw[t.cur.yy], 0);
break;
case (KEY_DC):
rowDeleteChar(&rows.rw[t.cur.yy], 1);
break;
case (KEY_ENTER):
case (10):
case ('\r'):
rowAddRow(t.cur.yy);
break;
case (KEY_END):
t.cur.y = rows.rownum;
t.cur.off_y = 0;
break;
case (KEY_HOME):
t.cur.y = 0;
t.cur.off_y = 0;
break;
default:
if (c == KEY_STAB) c = '\t';
rowAddChar(&rows.rw[t.cur.yy], c);
}
if (decimalSize(rows.rownum) - irow) updateInfo();
}
/* If by chance i find myself here be sure
* end curses mode and clenaup */
termExit();
return 0;
}
/* ----------------------------- end of main ---------------------------------- */
void termInit (void)
{
/* Init the screen and refresh */
initscr();
refresh();
/* Enable raw mode, this makes the termianl ignore
* interrupt signals like CTRL+C and CTRL+Z
* allowing us to make our own bindings */
raw();
/* Allow use of function keys */
keypad(stdscr, TRUE);
/* Turn off echoing */
noecho();
/* Set the tab size */
set_tabsize(TABSIZE);
/* Start color mode */
start_color();
init_pair(2, COLOR_BLACK, COLOR_CYAN);
init_pair(1, COLOR_RED, COLOR_BLACK);
/* Set default color */
//bkgd(COLOR_PAIR(1));
/* Populate the main data structure */
updateInfo();
/* Initialize the data staructure */
t.cur.x = t.cur.off_x = 0;
t.cur.y = t.cur.off_y = 0;
}
/* Calculate the correct spacing for the line numbers
* based on the size of the file */
int decimalSize (int n)
{
static int l;
for (l = 0; n > 0; l++) n /= 10;
return l + 1;
}
void termExit (void)
{
erase();
refresh();
endwin();
exit(0);
}
void termDie (char *s)
{
erase();
refresh();
endwin();
perror(s);
exit(1);
}
/* ----------------------------- term operations -------------------------------- */
void drawScreen ()
{
/* Clear the screen */
erase();
/* Update Scroll */
updateScroll();
/* draw the lines */
drawLines();
/* draw the bar */
drawBar(t.statusbar);
/* move back to the cursor position */
lnMove(t.cur.y, t.cur.r_x);
/* refresh the screen */
refresh();
}
/* Draw all the appropriate lines (following cursor) to the screen */
void drawLines (void)
{
static unsigned int line = 0, ln = 0;
static int i = 0;
/* move to the beginning of the screen */
//lnMove(0, 0);
for (i = 0; i < t.dim.y; i++) {
if (i >= rows.rownum) break;
ln = i + t.cur.off_y;
/* Draw the line number */
attron(COLOR_PAIR(1));
move(i, 0);
printw("%d", ln + 1);
attroff(COLOR_PAIR(1));
lnMove(i, 0);
/* Draw the line matcing render memory */
addnstr(&rows.rw[ln].render[t.cur.off_x], t.dim.x + 1 - rows.rw[ln].delta);
lnMove(++line, 0);
}
lnMove(t.cur.y, t.cur.x);
}
/* Move avoiding the space allocated for line numbers */
void lnMove (int y, int x)
{
move(y, x + t.pad);
}
/* Draw the status bar at the bottom of the screen */
void drawBar (char *s)
{
/* Set maximum contrast for bar */
attron(COLOR_PAIR(2));
/* get the length of the statusbar text */
int len = strlen(s);
/* Print the message */
mvprintw(t.dim.y, 0, s);
/* Fill everything else with spaces */
for (int i = len; i <= t.dim.x + t.pad; i++)
mvaddch(t.dim.y, i, ' ');
static char m[40];
sprintf(m, "x: %d y: %d Zoom: %c", t.cur.xx, t.cur.yy, whatsThat());
mvaddstr(t.dim.y, t.dim.x + t.pad - strlen(m), m);
/* Return to normal contrast mode */
attroff(COLOR_PAIR(2));
}
/* convert the cursor matchoing the memory to the drawn one */
int curRealToRender (row *rw, int c_x)
{
static int r_x = 0, i = 0;
for (i = 0, r_x = 0; i < c_x; i++) {
if (rw->chars[i] == '\t') r_x += (TABSIZE - 1) - (r_x % TABSIZE);
r_x++;
}
return r_x;
}
/* -------------------------------- draw operations -------------------------------- */
/* Open a file and put it into a buffer line by line */
void fileOpen (char *filename)
{
FILE *fp = fopen(filename, "r");
if (!fp) termDie("Cannot open file");
/* Init the linebuffer */
char *line = NULL;
/* Set linecap to 0 so getline will atumatically allocate
* memory for the line buffer*/
size_t linecap = 0;
ssize_t linelen;
/* getline returns -1 if no new line is present */
while ((linelen = getline(&line, &linecap, fp)) != -1) {
while (linelen > 0 && (line[linelen - 1] == '\n' || line[linelen - 1] == '\r'))
linelen--;
rowAddLast(line, linelen);
}
/* free the line buffer */
free(line);
/* close the file */
fclose(fp);
}
/* Add a row to the file buffer */
void rowAddLast (char *s, int len)
{
/* Extend the block of memory containing the lines */
// reallocarray fails safely
row *newr = NULL;
newr = (row*) reallocarray(rows.rw, (rows.rownum + 1), sizeof(*newr));
if (newr == NULL) termDie("realloc rowAddLast");
else rows.rw = newr;
//rows.rw = (row*) realloc(rows.rw, sizeof(row) * (rows.rownum + 1));
/* Allocate memory for the line and copy it
* at the current row number */
rows.rw[rows.rownum].chars = (char*) malloc(len + 1);
memcpy(rows.rw[rows.rownum].chars, s, len);
rows.rw[rows.rownum].chars[len] = '\0';
rows.rw[rows.rownum].size = len;
updateRender(&rows.rw[rows.rownum]);
rows.rownum++;
}
void updateRender (row *rw)
{
/* count the special characters (only tabs for now) */
int tabs = 0, i;
for (i = 0; i <= rw->size; i++) {
if (rw->chars[i] == '\t') tabs++;
}
rw->render = NULL;
free(rw->render);
/* Render is long as size with the added tab spaces - 1
* (we already count for the \t as a char) */
rw->render = malloc(rw->size + tabs * (TABSIZE - 1) + 1);
if (rw->render == NULL) termDie ("malloc in updateRender");
/* put all the characters (substituing all special chars)
* into the render buffer */
static int off, j = 0;
off = 0;
for (i = 0; i <= rw->size; i++) {
if (rw->chars[i] == '\t') {
for (j = 0; j < TABSIZE; j++){
if (!j) rw->render[off++] = '|';
else rw->render[off++] = ' ';
}
} else {
rw->render[off++] = rw->chars[i];
}
}
off -= 1;
rw->render[off] = '\0';
rw->r_size = off;
}
void rowInit (void)
{
rows.rw = NULL;
rows.rownum = 0;
}
void rowAddChar (row *rw, char c) // WIP
{
// Error checking (allow tab)
if (!c || (iscntrl(c) && c != '\t')) return;
int i = 0;
char *s = rw->chars;
// reallocate mem and inc size
rw->chars = (char*) malloc(rw->size + 2);
rw->size++;
// copy bf cursor
for (i = 0; i < t.cur.xx; i++) {
rw->chars[i] = s[i];
}
// add at cursor
rw->chars[t.cur.xx++] = c;
//copy after cursor
for (i = t.cur.xx; i < rw->size + 1; i++) {
rw->chars[i] = s[i - 1];
}
free(s);
updateRender(rw);
t.cur.x++;
}
void rowDeleteChar (row *rw, int m) // WIP
{
char *s = rw->chars;
//Do not delete NULL char
if (s[t.cur.xx - 1] == '\0' && t.cur.xx) return;
if (!t.cur.xx && !m) return;
if (s[t.cur.xx] == '\0' && m) return;
rw->chars = malloc(rw->size);
rw->size--;
// Backspace
if (!m) {
for (int i = 0; i < t.cur.xx - 1; i++)
rw->chars[i] = s[i];
for (int i = t.cur.xx; i < rw->size + 1; i++)
rw->chars[i - 1] = s[i];
t.cur.x--;
// Delete
} else {
if(t.cur.xx) {
for (int i = 0; i < t.cur.xx; i++)
rw->chars[i] = s[i];
}
for (int i = t.cur.xx; i < rw->size + 1; i++)
rw->chars[i] = s[i + 1];
}
free(s);
updateRender(rw);
}
/* ----------------------------- file operations --------------------------- */
/* take care of the cursor movement */
void cursorMove (int a)
{
switch (a) {
case (KEY_LEFT):
if (t.cur.x <= 0 && !t.cur.off_x) {
if (t.cur.y) {
t.cur.y--;
t.cur.yy--;
t.cur.x = rows.rw[t.cur.yy].size;
}
} else t.cur.x--;
break;
case (KEY_RIGHT):
if (t.cur.xx >= rows.rw[t.cur.yy].size) {
if (t.cur.yy < rows.rownum - 1) {
t.cur.y++;
t.cur.yy++;
if (t.cur.off_x) t.cur.off_x = 0;
t.cur.x = rows.rw[t.cur.yy].size;
}
} else t.cur.x++;
break;
case (KEY_UP):
if (t.cur.yy > 0) {
if (t.cur.y) {
t.cur.y--;
t.cur.yy--;
if (t.cur.xx > rows.rw[t.cur.yy].size) {
if (t.cur.off_x) t.cur.off_x = 0;
t.cur.x = rows.rw[t.cur.yy].size;
}
}
break;
case (KEY_DOWN):
if (t.cur.yy < rows.rownum - 1) {
t.cur.y++;
t.cur.yy++;
if (t.cur.xx > rows.rw[t.cur.yy].size) {
if (t.cur.off_x) t.cur.off_x = 0;
t.cur.x = rows.rw[t.cur.yy].size;
}
}
break;
}
}
}
void updateScroll (void)
{
/* Set y offset */
if (t.cur.y >= t.dim.y) {
if (t.cur.y == t.dim.y) t.cur.off_y++;
else t.cur.off_y += t.cur.y - t.dim.y;
t.cur.y = t.dim.y - 1;
} else if (t.cur.y <= 0 && t.cur.off_y > 0) {
t.cur.off_y--;
t.cur.y = 0;
}
/* Set x offeset */
if (t.cur.x >= t.dim.x) {
if (t.cur.x == t.dim.x - 1) t.cur.off_x++;
else t.cur.off_x += t.cur.x - t.dim.x;
t.cur.x = t.dim.x;
} else if (t.cur.x <= 0 && t.cur.off_x > 0) {
t.cur.off_x--;
t.cur.x = 0;
}
/* convert the cursor from real to render */
t.cur.yy = t.cur.y + t.cur.off_y;
t.cur.xx = t.cur.x + t.cur.off_x;
t.cur.r_x = curRealToRender(&rows.rw[t.cur.yy], t.cur.x);
}
/*---------------------------------- scroll ------------------------------------*/
/* See whats under the cursor (memory) */
int whatsThat (void) {
int c = rows.rw[t.cur.yy].chars[t.cur.xx];
switch (c) {
case ('\t'):
return '^';
break;
case (' '):
return '~';
break;
case ('\0'):
return '.';
break;
default:
return c;
break;
}
return 0;
}
void rowAddRow (int pos) // WIP; TO DOCUMENT
{
char *s = NULL;
// Move away other lines
//copy old last line to new space
rowAddLast(rows.rw[rows.rownum].chars, rows.rw[rows.rownum].size);
for (int last = rows.rownum - 1; last > pos; last--) {
rowCpy(&rows.rw[last], &rows.rw[last - 1]);
}
//copy previous row
int l = rows.rw[pos].size - t.cur.xx;
s = malloc(l + 1);
memcpy(s, &rows.rw[pos].chars[t.cur.xx], l);
s[l] = '\0';
// Delete prev row until cursor
char *p = malloc(t.cur.xx + 1);
memcpy(p, rows.rw[pos].chars, t.cur.xx);
p[t.cur.xx] = '\0';
rowFree(&rows.rw[pos]);
rows.rw[pos].chars = malloc(t.cur.xx + 1);
memcpy(rows.rw[pos].chars, p, t.cur.xx + 1);
free(p);
rows.rw[pos].size = t.cur.xx;
updateRender(&rows.rw[pos]);
if (pos != rows.rownum - 1) {
rowFree(&rows.rw[pos + 1]);
rows.rw[pos + 1].chars = malloc(strlen(s) + 1);
memcpy(rows.rw[pos + 1].chars, s, strlen(s) + 1);
rows.rw[pos + 1].size = strlen(s);
updateRender(&rows.rw[pos + 1]);
} else rowAddLast(s, l);
free(s);
t.cur.y++;
t.cur.x = 0;
t.cur.off_x = 0;
}
void rowFree (row *rw) // WIP
{
free(rw->render);
free(rw->chars);
rw->size = 0;
rw->r_size = 0;
}
void rowCpy (row *to, row *from) // WIP
{
rowFree(to);
to->chars = malloc(strlen(from->chars) + 1);
if (to->chars == NULL) termDie("malloc in rowCpy");
to->size = from->size;
memcpy(to->chars, from->chars, to->size);
updateRender(to);
}
/*--------------------------------- garbage ------------------------------------*/
void updateInfo (void)
{
getmaxyx(stdscr, t.dim.y, t.dim.x);
t.dim.y -= 1;
t.pad = decimalSize(rows.rownum);
t.dim.x -= t.pad + 1;
}
/*--------------------------------- testing ------------------------------------*/

29
ste.c

@ -63,7 +63,7 @@ static void updateRender (row *rw);
static void updateScroll (void);
static void cursorMove(int a);
static int decimalSize (int n);
static void lnMove (int y, int x);
static inline void lnMove (int y, int x);
static int curRealToRender (row *rw, int c_x);
/* Row operations */
@ -249,11 +249,11 @@ void drawScreen ()
/* Draw all the appropriate lines (following cursor) to the screen */
void drawLines (void)
{
int line = 0, ln;
static int line = 0, ln, i;
/* move to the beginning of the screen */
lnMove(0, 0);
//lnMove(0, 0);
for (int i = 0; i < t.dim.y; i++) {
for (i = 0; i < t.dim.y; i++) {
if (i >= rows.rownum) break;
ln = i + t.cur.off_y;
@ -278,10 +278,9 @@ void drawLines (void)
}
/* Move avoiding the space allocated for line numbers */
void lnMove (int y, int x)
inline void lnMove (int y, int x)
{
x += t.pad;
move(y, x);
move(y, x + t.pad);
}
/* Draw the status bar at the bottom of the screen */
@ -297,7 +296,7 @@ void drawBar (char *s)
for (int i = len; i <= t.dim.x + t.pad; i++)
mvaddch(t.dim.y, i, ' ');
char m[40];
static char m[40];
sprintf(m, "x: %d y: %d Zoom: %c", t.cur.xx, t.cur.yy, whatsThat());
mvaddstr(t.dim.y, t.dim.x + t.pad - strlen(m), m);
@ -347,7 +346,10 @@ void fileOpen (char *filename)
void rowAddLast (char *s, int len)
{
/* Extend the block of memory containing the lines */
rows.rw = realloc(rows.rw, sizeof(row) * (rows.rownum + 1));
row *newr = reallocarray(rows.rw, rows.rownum + 1, sizeof(row));
if (newr == NULL) termDie("realloc in rowAddLast");
else rows.rw = newr;
//rows.rw = realloc(rows.rw, sizeof(row) * (rows.rownum + 1));
/* Allocate memory for the line and copy it
* at the current row number */
@ -362,8 +364,8 @@ void rowAddLast (char *s, int len)
void updateRender (row *rw)
{
/* count the special characters (only tabs for now) */
int tabs = 0, i;
for (i = 0; i < rw->size; i++) {
static int tabs = 0, i, off;
for (i = 0, tabs = 0; i < rw->size; i++) {
if (rw->chars[i] == '\t') tabs++;
}
rw->render = NULL;
@ -377,8 +379,7 @@ void updateRender (row *rw)
/* put all the characters (substituing all special chars)
* into the render buffer */
int off = 0;
for (i = 0; i < rw->size; i++) {
for (i = 0, off = 0; i < rw->size; i++) {
if (rw->chars[i] == '\t') {
for (int j = 0; j < TABSIZE; j++){
if (!j) rw->render[off++] = '|';
@ -622,7 +623,7 @@ void rowFree (row *rw) // WIP
void rowCpy (row *to, row *from) // WIP
{
rowFree(to);
to->chars = malloc(strlen(from->chars) + 1);
to->chars = (char*) malloc(strlen(from->chars) + 1);
to->size = from->size;
memcpy(to->chars, from->chars, to->size);
updateRender(to);

Loading…
Cancel
Save