Introduction
Introduction Statistics Contact Development Disclaimer Help
reorganise code - gramscii - A simple editor for ASCII box-and-arrow charts
Log
Files
Refs
Tags
README
LICENSE
---
commit 8e3d23b921d9bbcb7c53017bacff8a3050a34b55
parent 3d53fcefe3ca3e6f25d1731c2caa0c1c0e676453
Author: KatolaZ <[email protected]>
Date: Sat, 27 Jul 2019 06:57:12 +0100
reorganise code
Diffstat:
M Makefile | 6 +++---
M TODO | 6 +++++-
A arg.h | 37 +++++++++++++++++++++++++++++…
M config.h | 14 +++++++++-----
A draw.c | 324 ++++++++++++++++++++++++++++++
A files.c | 73 +++++++++++++++++++++++++++++…
D gramscii.c | 1057 -----------------------------…
A gramscii.h | 138 ++++++++++++++++++++++++++++++
A main.c | 175 +++++++++++++++++++++++++++++…
A screen.c | 419 +++++++++++++++++++++++++++++…
10 files changed, 1183 insertions(+), 1066 deletions(-)
---
diff --git a/Makefile b/Makefile
@@ -3,8 +3,8 @@
include config.mk
-SRC = gramscii.c
-INC = config.h
+SRC = main.c draw.c screen.c files.c
+INC = config.h gramscii.h
all: options gramscii
@@ -22,7 +22,7 @@ gramscii: ${SRC} ${INC}
clean:
@echo cleaning
- @rm -f $(SRC:.c=)
+ @rm -f $(SRC:.c=) gramscii
install: all
@echo installing executable to ${DESTDIR}${BINDIR}
diff --git a/TODO b/TODO
@@ -5,10 +5,13 @@
- use [ENTER] to exit from text insert
- maybe move "text" mode to "t"
- implement ellipse
+- filled box (B)
+- manage fill character (as for other styles)
+- implement comment (#: ignore until the end of the line)
+ parse control characters
+ parse arrows (text-mode will allow movements as well)
- (?) implement CTRL+G as abort (aside ESC)
-- add crop command (c)
+- add crop command (C)
- (?) remove extra blanks until EOL when saving to file
+ visual selection
- crop-to
@@ -21,6 +24,7 @@
- allow scrolling (both vertical and horizontal)
- catch SIGWINCH and react appropriately (after scrolling is
enabled)
+* reorganise code
* change screen management (i.e., dynamic array of lines)
* add action multiplier (e.g., "7h" moves left by 7 cols)
* add scripting mode option ("-s"?)
diff --git a/arg.h b/arg.h
@@ -0,0 +1,37 @@
+#ifndef ARG_H
+#define ARG_H
+
+#define USED(x) ((void)(x))
+
+extern char *argv0;
+
+#define ARGBEGIN for(argv0 = *argv, argv++, argc--;\
+ argv[0] && argv[0][0] == '-'\
+ && argv[0][1];\
+ argc--, argv++) {\
+ char _argc;\
+ char **_argv;\
+ if(argv[0][1] == '-' && argv[0][2] == '\0') {\
+ argv++;\
+ argc--;\
+ break;\
+ }\
+ int i_;\
+ for(i_ = 1, _argv = argv; argv[0][i_];\
+ i_++) {\
+ if(_argv != argv)\
+ break;\
+ _argc = argv[0][i_];\
+ switch(_argc)
+
+#define ARGEND }\
+ USED(_argc);\
+ }\
+ USED(argv);\
+ USED(argc);
+
+#define EARGF(x) ((argv[1] == NULL)? ((x), abort(), (char *)0) :\
+ (argc--, argv++, argv[0]))
+
+#endif
+
diff --git a/config.h b/config.h
@@ -1,18 +1,22 @@
/* This is part of `gramscii`` -- see COPYING for details */
+#ifndef __LOCAL_CONFIG_H__
+#define __LOCAL_CONFIG_H__
/* Config options */
/** MARKERS -- the first character is the default one **/
/* markers for horizontal lines */
-char hlines[] = {"-~=#*@._ "};
+static char hlines[] = {"-~=#*@._ "};
/* markers for vertical lines */
-char vlines[] = {"|H#*@:;i "};
+static char vlines[] = {"|H#*@:;i "};
/* markers for corners */
-char corners[] = {"+'H#*@.\"`"};
+static char corners[] = {"+'H#*@.\"`"};
/* markers for arrow start points */
-char st_marks[] = {"+o-|<>^v*"};
+static char st_marks[] = {"+o-|<>^v*"};
/* markers for arrow endpoints */
-char end_marks[] = {">+o-|<^v*"};
+static char end_marks[] = {">+o-|<^v*"};
/** LONG_STEP (movements through uppercase HJKL) **/
#define LONG_STEP 5
+
+#endif
diff --git a/draw.c b/draw.c
@@ -0,0 +1,324 @@
+#include <stdlib.h>
+
+#include "gramscii.h"
+#include "config.h"
+
+/*** drawing-related functions ***/
+
+/*** Lines and markers ***/
+
+void toggle_hline(){
+
+ cur_hl = (cur_hl + 1) % hlines_sz;
+ line_h = hlines[cur_hl];
+
+}
+
+void toggle_corner(){
+
+ cur_corn = (cur_corn + 1 ) % corners_sz;
+ corner = corners[cur_corn];
+
+}
+
+void toggle_vline(){
+
+ cur_vl = (cur_vl + 1) % vlines_sz;
+ line_v = vlines[cur_vl];
+
+}
+
+void toggle_st_mark(){
+
+ cur_start = (cur_start + 1 ) % stmarks_sz;
+ mark_st = st_marks[cur_start];
+}
+
+void toggle_end_mark(){
+
+ cur_end = (cur_end+ 1 ) % endmarks_sz;
+ mark_end = end_marks[cur_end];
+}
+
+int change_style(char c){
+ switch(c){
+ case '-':
+ toggle_hline();
+ break;
+ case '|':
+ toggle_vline();
+ break;
+ case '+':
+ toggle_corner();
+ break;
+ case '<':
+ toggle_st_mark();
+ break;
+ case '>':
+ toggle_end_mark();
+ break;
+ case '.':
+ reset_styles();
+ break;
+ default:
+ return 0;
+ }
+ return c;
+}
+
+
+
+
+/***** text, box, arrows *****/
+
+void get_text(FILE *fc){
+ char c;
+ int orig_x = x;
+
+ redraw();
+ while((c=fgetc(fc))!=EOF && c != 27){
+ if(c=='\n'){
+ set_cur(BG);
+ y += 1;
+ x = orig_x;
+ }
+ else {
+ set_cur(c);
+ update_current();
+ modified = 1;
+ x += 1;
+ if (x >= WIDTH)
+ x = orig_x;
+ }
+ check_bound();
+ status_bar();
+ show_cursor();
+ }
+ mode=MOVE;
+}
+
+void draw_box(int x1, int y1, int fix){
+
+ int xmin, ymin, xmax, ymax;
+ int i;
+ void (*f)(int, int, char);
+
+ if (fix == FIX)
+ f = set_xy;
+ else
+ f = draw_xy;
+
+ xmin = MIN(x, x1);
+ xmax = MAX(x, x1);
+ ymin = MIN(y, y1);
+ ymax = MAX(y, y1);
+
+ for(i=xmin+1; i<=xmax; i++){
+ f(i, ymin, line_h);
+ f(i, ymax, line_h);
+ }
+ for(i=ymin+1; i<=ymax; i++){
+ f(xmin, i, line_v);
+ f(xmax, i, line_v);
+ }
+ f(xmin, ymin, corner);
+ f(xmin, ymax, corner);
+ f(xmax, ymin, corner);
+ f(xmax, ymax, corner);
+ show_cursor();
+}
+
+void get_box(FILE *fc){
+ char c;
+ int orig_x=x, orig_y=y;
+ redraw();
+ step = 1;
+ draw_box(x,y,NOFIX);
+ while((c=fgetc(fc))!=EOF && c != 27 && c!= 'b' && c != '\n'){
+ if (change_style(c))
+ goto update_box;
+ if (!move_around(c, fc))
+ continue;
+ check_bound();
+ redraw();
+ step = 1;
+update_box:
+ draw_box(orig_x, orig_y, NOFIX);
+ status_bar();
+ show_cursor();
+ }
+ if (c == 'b' || c == '\n'){
+ draw_box(orig_x, orig_y, FIX);
+ modified = 1;
+ }
+ redraw();
+ mode = MOVE;
+}
+
+void draw_arrow(int x, int y, char *a, int a_len, int fix){
+
+ int i, j, cur_dir;
+ char line;
+ void (*f)(int, int, char);
+
+
+ if (fix == FIX)
+ f = set_xy;
+ else
+ f = draw_xy;
+
+ f(x,y,mark_st);
+ if (!a_len){
+ show_cursor();
+ return;
+ }
+ cur_dir=DIR_N;
+ for (i=0; i<a_len; i+=2){
+ if (i>0) {
+ /* If we are switching between horizontal and vertical…
+ if (((cur_dir & DIR_HOR) && (a[i] & DIR_VER)) ||
+ ((cur_dir & DIR_VER) && (a[i] & DIR_HOR))){
+ f(x,y,corner);
+ show_cursor();
+ }
+ }
+ for(j=0; j<a[i+1]; j++){
+ line = (a[i] & DIR_L) || (a[i] & DIR_R) ? line_h : lin…
+ x += progr_x(a[i]);
+ y += progr_y(a[i]);
+ f(x, y, line);
+ }
+ /* f(x,y,mark_end);*/
+ cur_dir = a[i];
+ }
+ if (autoend){
+ if (cur_dir != DIR_N)
+ f(x,y, get_mark(cur_dir));
+ }
+ else
+ f(x,y,mark_end);
+ show_cursor();
+}
+
+void get_arrow(FILE *fc){
+
+ char c;
+ int orig_x=x, orig_y=y, arrow_len;
+ static char *arrow = NULL;
+ static int arrow_sz;
+
+ if (!arrow){
+ arrow_sz = 100;
+ arrow = malloc(arrow_sz * sizeof(char));
+ }
+ arrow_len = 0;
+ dir = DIR_N;
+
+ redraw();
+ step = 1;
+ draw_arrow(x,y, arrow, 0, NOFIX);
+ while((c=fgetc(fc))!=EOF && c != 27 && c!= 'a' && c != '\n'){
+ if (change_style(c))
+ goto update_arrow;
+ if (!move_around(c, fc))
+ continue;
+ check_bound();
+ /* FIXME: if we are out of bound, do nothing? */
+ if (arrow_len == arrow_sz){
+ arrow_sz *=2;
+ arrow = realloc(arrow, arrow_sz * sizeof(char));
+ }
+ arrow[arrow_len++] = dir;
+ arrow[arrow_len++] = step;
+ redraw();
+ step = 1;
+update_arrow:
+ draw_arrow(orig_x, orig_y, arrow, arrow_len, NOFIX);
+ status_bar();
+ show_cursor();
+ }
+ if (c == 'a' || c == '\n'){
+ draw_arrow(orig_x, orig_y, arrow, arrow_len, FIX);
+ modified = 1;
+ }
+ redraw();
+ mode = MOVE;
+}
+
+
+void do_erase(int x1, int y1){
+ int i;
+ switch(dir){
+ case DIR_R:
+ for(i=x1; i<=x; i++) set_xy(i,y,BG);
+ break;
+ case DIR_L:
+ for(i=x1; i>=x; i--) set_xy(i,y,BG);
+ break;
+ case DIR_U:
+ for(i=y1; i>=y; i--) set_xy(x,i,BG);
+ break;
+ case DIR_D:
+ for(i=y1; i<=y; i++) set_xy(x,i,BG);
+ break;
+ }
+}
+
+
+void erase(FILE *fc){
+ char c;
+ int orig_x = x, orig_y = y;
+ status_bar();
+ show_cursor();
+ while((c=fgetc(fc))!=EOF && c!=27 && c!= 'x' && c != '\n'){
+ if (!move_around(c, fc)) continue;
+ check_bound();
+ do_erase(orig_x, orig_y);
+ step = 1;
+ modified = 1;
+ orig_x = x;
+ orig_y = y;
+ redraw();
+ status_bar();
+ show_cursor();
+ }
+ mode = MOVE;
+}
+
+
+/*** Visual ***/
+
+
+void visual_box(FILE *fc){
+ int orig_x =x, orig_y = y;
+ char c, f = BG;
+
+ redraw();
+ step = 1;
+ set_video(VIDEO_REV);
+ draw_box(x,y,NOFIX);
+ while((c=fgetc(fc))!=EOF && c != 27 && c!= 'v' && c != '\n'){
+ if (!move_around(c, fc)) switch(c){
+ case 'f':/* fill */
+ f = get_key(fc, "fill char: "); /** FALLTHROUG…
+ case 'x':/* erase */
+ erase_box(orig_x, orig_y, f);
+ modified = 1;
+ goto vis_exit;
+ break;
+ }
+ check_bound();
+ set_video(VIDEO_NRM);
+ redraw();
+ step = 1;
+ f = BG;
+ set_video(VIDEO_REV);
+ draw_box(orig_x, orig_y, NOFIX);
+ status_bar();
+ show_cursor();
+ }
+vis_exit:
+ set_video(VIDEO_NRM);
+ redraw();
+ mode = MOVE;
+}
diff --git a/files.c b/files.c
@@ -0,0 +1,73 @@
+#include <stdio.h>
+#include <string.h>
+#include "gramscii.h"
+
+
+/*** File management ***/
+
+void write_file(FILE *fc){
+ FILE *fout;
+ int i;
+
+ if (!fname[0] || force_new){
+ get_string(fc, "Write to: ", fname, 255);
+ if ((fout=fopen(fname, "r"))!=NULL){
+ if (!is_yes(get_key(fc,"File exists. Overwrite [y/n]?"…
+ fclose(fout);
+ return;
+ }
+ fclose(fout);
+ }
+ }
+ if((fout=fopen(fname, "w"))==NULL){
+ get_key(fc, "Error opening file.");
+ return;
+ }
+ for (i=0; i<HEIGHT; i++){
+ fprintf(fout, "%s\n", screen[i].s);
+ }
+ fclose(fout);
+ modified = 0;
+ get_key(fc, "File saved.");
+}
+
+void check_modified(FILE *fc){
+
+ if (modified){
+ if (!is_yes(get_key(fc, "Unsaved changes. Write to file [y/n]?…
+ return;
+ }
+ write_file(fc);
+ }
+}
+
+void load_file(FILE *fc){
+
+ char newfname[256];
+ FILE *fin;
+ int i;
+
+ get_string(fc, "Load file: ", newfname, 255);
+ if ((fin=fopen(newfname, "r")) != NULL){
+ i = 0;
+ while((fgets(screen[i].s, WIDTH+2, fin)) != NULL && i<HEIGHT)
+ screen[i++].s[WIDTH-1]='\0';
+ for(;i<HEIGHT; i++){
+ erase_line(screen[i].s);
+ }
+ fclose(fin);
+ }
+ strcpy(fname, newfname);
+ modified=0;
+ redraw();
+}
+
+void new_file(FILE *fc){
+ check_modified(fc);
+ erase_screen();
+ go_to(HOME);
+ redraw();
+ fname[0] = '\0';
+ modified=0;
+}
+
diff --git a/gramscii.c b/gramscii.c
@@ -1,1057 +0,0 @@
-/*
-*
-* gramscii: a simple editor for ASCII box-and-arrow charts
-*
-* Copyright (c) 2019 Vincenzo "KatolaZ" Nicosia <[email protected]>
-*
-* 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.
-*
-* 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.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. Please see the attached file COPYING.
-* Otherwise, please visit <https://www.gnu.org/licenses/>.
-*
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <unistd.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <ctype.h>
-
-#include "config.h"
-
-#include "arg.h"
-
-typedef struct{
- int sz;
- int lst;
- char *s;
-} line_t;
-
-
-#define MOVE 0x00
-#define BOX 0x01
-#define ARROW 0x02
-#define TEXT 0x04
-#define DEL 0x08
-#define VIS 0x10
-
-#define DIR_N 0x00
-#define DIR_R 0x01
-#define DIR_U 0x02
-#define DIR_D 0x04
-#define DIR_L 0x08
-
-#define DIR_HOR (DIR_R | DIR_L)
-#define DIR_VER (DIR_D | DIR_U)
-
-
-#define NOFIX 0x0
-#define FIX 0x1
-
-#define BG ' '
-#define PTR '+'
-#define UND '_'
-#define ARR_L '<'
-#define ARR_R '>'
-#define ARR_U '^'
-#define ARR_D 'v'
-
-#define HOME 0x01
-#define END 0x02
-#define MIDDLE 0x04
-
-#define VIDEO_NRM 0
-#define VIDEO_REV 7
-
-#define MIN(x,y) (x) < (y) ? (x) : (y)
-#define MAX(x,y) (x) > (y) ? (x) : (y)
-
-#define DEBUG 1
-
-line_t *screen;
-int num_lines;
-int WIDTH, HEIGHT;
-
-int state;
-int dir;
-int x;
-int y;
-int step;
-int mult;
-int force_new;
-char cursor;
-char corner;
-
-int hlines_sz= sizeof(hlines) -1;
-int vlines_sz= sizeof(vlines) -1;
-int corners_sz = sizeof(corners) -1;
-int stmarks_sz = sizeof(st_marks) - 1;
-int endmarks_sz = sizeof(st_marks) - 1;
-
-int cur_hl, cur_vl, cur_corn, cur_start, cur_end;
-char line_h;
-char line_v;
-char mark_st;
-char mark_end;
-
-char modified;
-char fname[256];
-
-char visual;
-char silent;
-char autoend;
-
-char *argv0;
-
-struct termios t1, t2, t3;
-
-
-void dump_lines(){
- int i;
- for (i=0; i<HEIGHT; i++){
- printf("%s\n", screen[i].s);
- }
-}
-
-void cleanup(int s){
-
- if (!silent)
- printf("\033[;H\033[2J");
- if (silent)
- dump_lines();
- tcsetattr(0, TCSANOW, &t1);
- fflush(stdout);
- exit(0);
-}
-
-void exit_cleanup(void){
- cleanup(0);
-}
-
-
-/*** Status bar ***/
-
-char* state_str(){
- switch(state){
- case MOVE:
- return "mov";
- case TEXT:
- return "txt";
- case BOX:
- return "box";
- case ARROW:
- return "arr";
- case DEL:
- return "del";
- case VIS:
- return "vis";
- default:
- return "ERR";
- }
- return "ERR";
-}
-
-char get_mark(char dir){
- switch(dir){
- case DIR_U:
- return '^';
- case DIR_D:
- return 'v';
- case DIR_L:
- return '<';
- case DIR_R:
- return '>';
- }
- return '>';
-}
-
-
-void status_bar(){
-
- if (silent)
- return;
- printf("\033[%d;1f\033[7m", HEIGHT+1);
- printf("%*s", WIDTH-1, "");
- printf("\033[%d;1f\033[7m", HEIGHT+1);
- printf(" x:%3d y:%3d -- MODE:%4s HL:%c VL:%c CN:%c SP:%c EP:%c %10s",
- x, y, state_str(), line_h, line_v, corner, mark_st, mark_end, …
- if (!modified)
- printf(" [%s]", fname );
- else
- printf(" *%s*", fname );
-#ifdef DEBUG
- printf(" '%d' ", screen[y].s[x]);
-#endif
- printf("\033[0m");
- fflush(stdout);
-}
-
-char get_key(FILE *fc, char *msg){
-
- if (silent)
- return 0;
- printf("\033[%d;1f\033[7m", HEIGHT+1);
- printf("%*s", WIDTH, "");
- printf("\033[%d;1f\033[7m", HEIGHT+1);
- printf("%s", msg);
- fflush(stdout);
- printf("\033[0m");
- fflush(stdout);
- return fgetc(fc);
-}
-
-void get_string(FILE *fc, char *msg, char *s, int sz){
-
- if (!silent){
- printf("\033[%d;1f\033[7m", HEIGHT+1);
- printf("%*s", WIDTH, "");
- printf("\033[%d;1f\033[7m", HEIGHT+1);
-
- /* We must activate echo now */
- t3 = t2;
- t3.c_lflag |= (ECHO | ICANON);
- tcsetattr(0, TCSANOW, &t3);
- printf("%s", msg);
- printf("\033[0m");
- }
- fgets(s, sz, fc);
- s[strlen(s)-1] = '\0';
- tcsetattr(0, TCSANOW, &t2);
- if (!silent)
- fflush(stdout);
-}
-
-int is_yes(char c){
- return c=='y' ? 1 : c == 'Y'? 1 : 0;
-}
-
-/*** Screen management ***/
-
-void show_cursor(){
- if (silent)
- return;
- printf("\033[%d;%df", y+1, x+1);
- fflush(stdout);
-}
-
-
-void set_xy(int _x, int _y, char c){
- line_t *tmp;
- if (_y >= num_lines){
- tmp = realloc(screen, (_y + LONG_STEP)* sizeof(line_t));
- if (tmp == NULL){
- fprintf(stderr, "Unable to allocate memory for more li…
- exit(1);
- }
- else while ( num_lines < _y + LONG_STEP){
- screen[num_lines].sz = WIDTH+1;
- screen[num_lines].s = malloc((screen[num_lines].sz) * …
- if (screen[num_lines].s == NULL){
- perror("allocating screen[num_lines].s");
- exit(1);
- }
- memset(screen[num_lines].s, BG, screen[num_lines].sz);
- screen[num_lines].lst = 0;
- screen[num_lines].s[screen[num_lines].lst+1]='\0';
- num_lines ++;
- }
- }
- if (screen[_y].sz < _x + 2){
- screen[_y].sz = (_x +2) * 2;
- screen[_y].s = realloc(screen[_y].s, screen[_y].sz * sizeof(ch…
- }
- while (screen[_y].lst<_x){
- screen[_y].lst ++;
- screen[_y].s[screen[_y].lst] = BG;
- }
- screen[_y].s[_x] = c;
- if (_x == screen[_y].lst)
- screen[_y].s[_x+1] = '\0';
-}
-
-void set_cur(char c){
- set_xy(x, y, c);
-}
-
-void draw_xy(int x, int y, char c){
- /* FIXME: check if x and y are valid!!!! */
- if (silent)
- return;
- printf("\033[%d;%df",y+1,x+1);
- putchar(c);
- fflush(stdout);
-}
-
-void update_current(){
- if (silent)
- return;
- printf("\033[%d'%df",y+1,x+1);
- putchar(screen[y].s[x]);
- fflush(stdout);
-}
-
-void erase_line(char *s){
- while(*s){
- *s = BG;
- s++;
- }
-}
-
-void erase_box(int x1, int y1, char c){
- int x_incr, y_incr, i;
-
- x_incr = x1 < x? +1: -1;
- y_incr = y1 < y? +1: -1;
- do{
- i = y1;
- do{
- set_xy(x1, i, c);
- } while(i != y && (1 | (i += y_incr)));
- } while(x1 != x && (1 | (x1 += x_incr)));
-
-}
-
-void erase_screen(){
- int i;
- for(i=0;i<HEIGHT; i++)
- erase_line(screen[i].s);
-}
-
-void check_bound(){
- if (x<0) x=0;
- else if (x>=WIDTH) x = WIDTH-1;
- if (y<0) y=0;
- else if (y>=HEIGHT) y = HEIGHT -1;
-}
-
-void reset_styles(){
-
- cur_corn = 0;
- corner = corners[0];
- cur_hl = cur_vl = 0;
- cur_start = cur_end = 0;
- line_h = hlines[cur_hl];
- line_v = vlines[cur_vl];
- mark_st = st_marks[cur_start];
- mark_end = end_marks[cur_end];
-}
-
-void redraw(){
- int i;
-
- if (silent)
- return;
- printf("\033[2J\033[1;1H");
- for (i=0;i<HEIGHT;i++){
- fprintf(stdout,"%s\n",screen[i].s);
- }
- status_bar();
- show_cursor();
-}
-
-void go_to(int where){
- switch(where){
- case HOME:
- x = y = 0;
- break;
- case END:
- x = WIDTH-1;
- y = HEIGHT-1;
- break;
- case MIDDLE:
- x = WIDTH/2;
- y = HEIGHT/2;
- break;
- }
- check_bound();
- show_cursor();
-}
-
-void handle_goto(){
- char c;
- c=getchar();
- switch(c){
- case 'h':
- dir = DIR_L;
- x = 0;
- break;
- case 'l':
- dir = DIR_R;
- x = WIDTH - 1;
- break;
- case 'j':
- dir = DIR_D;
- y = HEIGHT - 1;
- break;
- case 'k':
- dir = DIR_U;
- y = 0;
- break;
- case 'g':
- dir = DIR_N;
- go_to(HOME);
- break;
- case 'G':
- dir = DIR_N;
- go_to(END);
- break;
- case 'm':
- dir = DIR_N;
- go_to(MIDDLE);
- break;
- }
- check_bound();
- show_cursor();
-}
-
-
-int get_escape(FILE *fc){
- char c[4];
-
- c[0] = fgetc(fc);
- if (c[0] == '['){
- c[1] = fgetc(fc);
- switch(c[1]){
- case 'D':
- dir = DIR_L;
- x -= step;
- break;
- case 'B':
- dir = DIR_D;
- y += step;
- break;
- case 'A':
- dir = DIR_U;
- y -= step;
- break;
- case 'C':
- dir = DIR_R;
- x += step;
- break;
- }
- return 1;
- }
- else{
- ungetc(c[0], fc);
- return 0;
- }
-
-}
-
-
-int move_around(char c, FILE *fc){
-
- if (isdigit(c)){
- if (mult)
- mult *=10;
- mult += c - '0';
- return 0;
- }
- switch(c){
- case 27: /* control sequence? */
- c = get_escape(fc);
- break;
- case 'H': step = LONG_STEP;/** FALLTHROUGH **/
- case 'h':
- dir = DIR_L;
- if (mult)
- step *= mult;
- x -= step;
- break;
- case 'J': step = LONG_STEP;/** FALLTHROUGH **/
- case 'j':
- if (mult)
- step *= mult;
- dir = DIR_D;
- y += step;
- break;
- case 'K': step = LONG_STEP;/** FALLTHROUGH **/
- case 'k':
- if (mult)
- step *= mult;
- dir = DIR_U;
- y -= step;
- break;
- case 'L': step = LONG_STEP;/** FALLTHROUGH **/
- case 'l':
- if (mult)
- step *= mult;
- dir = DIR_R;
- x += step;
- break;
- case 'g':
- handle_goto();
- break;
- default:
- return 0;
- }
- mult = 0;
- return c;
-}
-
-int progr_x(int dir){
- return dir == DIR_L ? -1 : dir == DIR_R ? 1: 0;
-}
-
-
-int progr_y(int dir){
- return dir == DIR_U ? -1 : dir == DIR_D ? 1: 0;
-}
-
-void set_video(int v){
- if (silent)
- return;
- printf("\033[%dm", v);
- fflush(stdout);
-}
-
-/*** Lines and markers ***/
-
-void toggle_hline(){
-
- cur_hl = (cur_hl + 1) % hlines_sz;
- line_h = hlines[cur_hl];
-
-}
-
-void toggle_corner(){
-
- cur_corn = (cur_corn + 1 ) % corners_sz;
- corner = corners[cur_corn];
-
-}
-
-void toggle_vline(){
-
- cur_vl = (cur_vl + 1) % vlines_sz;
- line_v = vlines[cur_vl];
-
-}
-
-void toggle_st_mark(){
-
- cur_start = (cur_start + 1 ) % stmarks_sz;
- mark_st = st_marks[cur_start];
-}
-
-void toggle_end_mark(){
-
- cur_end = (cur_end+ 1 ) % endmarks_sz;
- mark_end = end_marks[cur_end];
-}
-
-int change_style(char c){
- switch(c){
- case '-':
- toggle_hline();
- break;
- case '|':
- toggle_vline();
- break;
- case '+':
- toggle_corner();
- break;
- case '<':
- toggle_st_mark();
- break;
- case '>':
- toggle_end_mark();
- break;
- case '.':
- reset_styles();
- break;
- default:
- return 0;
- }
- return c;
-}
-
-
-
-
-/***** text, box, arrows *****/
-
-void get_text(FILE *fc){
- char c;
- int orig_x = x;
-
- redraw();
- while((c=fgetc(fc))!=EOF && c != 27){
- if(c=='\n'){
- set_cur(BG);
- y += 1;
- x = orig_x;
- }
- else {
- set_cur(c);
- update_current();
- modified = 1;
- x += 1;
- if (x >= WIDTH)
- x = orig_x;
- }
- check_bound();
- status_bar();
- show_cursor();
- }
- state=MOVE;
-}
-
-void draw_box(int x1, int y1, int fix){
-
- int xmin, ymin, xmax, ymax;
- int i;
- void (*f)(int, int, char);
-
- if (fix == FIX)
- f = set_xy;
- else
- f = draw_xy;
-
- xmin = MIN(x, x1);
- xmax = MAX(x, x1);
- ymin = MIN(y, y1);
- ymax = MAX(y, y1);
-
- for(i=xmin+1; i<=xmax; i++){
- f(i, ymin, line_h);
- f(i, ymax, line_h);
- }
- for(i=ymin+1; i<=ymax; i++){
- f(xmin, i, line_v);
- f(xmax, i, line_v);
- }
- f(xmin, ymin, corner);
- f(xmin, ymax, corner);
- f(xmax, ymin, corner);
- f(xmax, ymax, corner);
- show_cursor();
-}
-
-void get_box(FILE *fc){
- char c;
- int orig_x=x, orig_y=y;
- redraw();
- step = 1;
- draw_box(x,y,NOFIX);
- while((c=fgetc(fc))!=EOF && c != 27 && c!= 'b' && c != '\n'){
- if (change_style(c))
- goto update_box;
- if (!move_around(c, fc))
- continue;
- check_bound();
- redraw();
- step = 1;
-update_box:
- draw_box(orig_x, orig_y, NOFIX);
- status_bar();
- show_cursor();
- }
- if (c == 'b' || c == '\n'){
- draw_box(orig_x, orig_y, FIX);
- modified = 1;
- }
- redraw();
- state = MOVE;
-}
-
-void draw_arrow(int x, int y, char *a, int a_len, int fix){
-
- int i, j, cur_dir;
- char line;
- void (*f)(int, int, char);
-
-
- if (fix == FIX)
- f = set_xy;
- else
- f = draw_xy;
-
- f(x,y,mark_st);
- if (!a_len){
- show_cursor();
- return;
- }
- cur_dir=DIR_N;
- for (i=0; i<a_len; i+=2){
- if (i>0) {
- /* If we are switching between horizontal and vertical…
- if (((cur_dir & DIR_HOR) && (a[i] & DIR_VER)) ||
- ((cur_dir & DIR_VER) && (a[i] & DIR_HOR))){
- f(x,y,corner);
- show_cursor();
- }
- }
- for(j=0; j<a[i+1]; j++){
- line = (a[i] & DIR_L) || (a[i] & DIR_R) ? line_h : lin…
- x += progr_x(a[i]);
- y += progr_y(a[i]);
- f(x, y, line);
- }
- /* f(x,y,mark_end);*/
- cur_dir = a[i];
- }
- if (autoend){
- if (cur_dir != DIR_N)
- f(x,y, get_mark(cur_dir));
- }
- else
- f(x,y,mark_end);
- show_cursor();
-}
-
-void get_arrow(FILE *fc){
-
- char c;
- int orig_x=x, orig_y=y, arrow_len;
- static char *arrow = NULL;
- static int arrow_sz;
-
- if (!arrow){
- arrow_sz = 100;
- arrow = malloc(arrow_sz * sizeof(char));
- }
- arrow_len = 0;
- dir = DIR_N;
-
- redraw();
- step = 1;
- draw_arrow(x,y, arrow, 0, NOFIX);
- while((c=fgetc(fc))!=EOF && c != 27 && c!= 'a' && c != '\n'){
- if (change_style(c))
- goto update_arrow;
- if (!move_around(c, fc))
- continue;
- check_bound();
- /* FIXME: if we are out of bound, do nothing? */
- if (arrow_len == arrow_sz){
- arrow_sz *=2;
- arrow = realloc(arrow, arrow_sz * sizeof(char));
- }
- arrow[arrow_len++] = dir;
- arrow[arrow_len++] = step;
- redraw();
- step = 1;
-update_arrow:
- draw_arrow(orig_x, orig_y, arrow, arrow_len, NOFIX);
- status_bar();
- show_cursor();
- }
- if (c == 'a' || c == '\n'){
- draw_arrow(orig_x, orig_y, arrow, arrow_len, FIX);
- modified = 1;
- }
- redraw();
- state = MOVE;
-}
-
-
-void do_delete(int x1, int y1){
- int i;
- switch(dir){
- case DIR_R:
- for(i=x1; i<=x; i++) set_xy(i,y,BG);
- break;
- case DIR_L:
- for(i=x1; i>=x; i--) set_xy(i,y,BG);
- break;
- case DIR_U:
- for(i=y1; i>=y; i--) set_xy(x,i,BG);
- break;
- case DIR_D:
- for(i=y1; i<=y; i++) set_xy(x,i,BG);
- break;
- }
-}
-
-
-void delete(FILE *fc){
- char c;
- int orig_x = x, orig_y = y;
- status_bar();
- show_cursor();
- while((c=fgetc(fc))!=EOF && c!=27 && c!= 'x' && c != '\n'){
- if (!move_around(c, fc)) continue;
- check_bound();
- do_delete(orig_x, orig_y);
- step = 1;
- modified = 1;
- orig_x = x;
- orig_y = y;
- redraw();
- status_bar();
- show_cursor();
- }
- state = MOVE;
-}
-
-/*** File management ***/
-
-void write_file(FILE *fc){
- FILE *fout;
- int i;
-
- if (!fname[0] || force_new){
- get_string(fc, "Write to: ", fname, 255);
- if ((fout=fopen(fname, "r"))!=NULL){
- if (!is_yes(get_key(fc,"File exists. Overwrite [y/n]?"…
- fclose(fout);
- return;
- }
- fclose(fout);
- }
- }
- if((fout=fopen(fname, "w"))==NULL){
- get_key(fc, "Error opening file.");
- return;
- }
- for (i=0; i<HEIGHT; i++){
- fprintf(fout, "%s\n", screen[i].s);
- }
- fclose(fout);
- modified = 0;
- get_key(fc, "File saved.");
-}
-
-void check_modified(FILE *fc){
-
- if (modified){
- if (!is_yes(get_key(fc, "Unsaved changes. Write to file [y/n]?…
- return;
- }
- write_file(fc);
- }
-}
-
-void load_file(FILE *fc){
-
- char newfname[256];
- FILE *fin;
- int i;
-
- get_string(fc, "Load file: ", newfname, 255);
- if ((fin=fopen(newfname, "r")) != NULL){
- i = 0;
- while((fgets(screen[i].s, WIDTH+2, fin)) != NULL && i<HEIGHT)
- screen[i++].s[WIDTH-1]='\0';
- for(;i<HEIGHT; i++){
- erase_line(screen[i].s);
- }
- fclose(fin);
- }
- strcpy(fname, newfname);
- modified=0;
- redraw();
-}
-
-void new_file(FILE *fc){
- check_modified(fc);
- erase_screen();
- go_to(HOME);
- redraw();
- fname[0] = '\0';
- modified=0;
-}
-
-/*** Visual ***/
-
-
-void visual_box(FILE *fc){
- int orig_x =x, orig_y = y;
- char c, f = BG;
-
- redraw();
- step = 1;
- set_video(VIDEO_REV);
- draw_box(x,y,NOFIX);
- while((c=fgetc(fc))!=EOF && c != 27 && c!= 'v' && c != '\n'){
- if (!move_around(c, fc)) switch(c){
- case 'f':/* fill */
- f = get_key(fc, "fill char: "); /** FALLTHROUG…
- case 'x':/* erase */
- erase_box(orig_x, orig_y, f);
- modified = 1;
- goto vis_exit;
- break;
- }
- check_bound();
- set_video(VIDEO_NRM);
- redraw();
- step = 1;
- f = BG;
- set_video(VIDEO_REV);
- draw_box(orig_x, orig_y, NOFIX);
- status_bar();
- show_cursor();
- }
-vis_exit:
- set_video(VIDEO_NRM);
- redraw();
- state = MOVE;
-}
-
-/*** Initialisation ***/
-
-void init_screen(){
- int i;
- struct winsize wsz;
-
- if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz)){
- WIDTH=wsz.ws_col - 2;
- HEIGHT=wsz.ws_row - 1;
- }
- else {
- WIDTH=80;
- HEIGHT=24;
- }
- screen = malloc(HEIGHT * sizeof(line_t));
- num_lines = HEIGHT;
- if (screen == NULL){
- perror("allocating screen");
- exit(1);
- }
- for (i=0; i<HEIGHT; i++){
- screen[i].sz = WIDTH+1;
- screen[i].s = malloc((screen[i].sz) * sizeof(char));
- if (screen[i].s == NULL){
- perror("allocating screen[i].s");
- exit(1);
- }
- memset(screen[i].s, BG, screen[i].sz);
- screen[i].lst = 0;
- screen[i].s[screen[i].lst+1]='\0';
- }
- reset_styles();
-}
-
-void init(){
-
- signal(SIGHUP, cleanup);
- signal(SIGINT, cleanup);
- signal(SIGTERM, cleanup);
- signal(SIGQUIT, cleanup);
- atexit(exit_cleanup);
-
- tcgetattr(0, &t1);
- t2 = t1;
- t2.c_lflag &= ~(ICANON | ECHO);
- tcsetattr(0, TCSANOW, &t2);
-
- init_screen();
- x = 0;
- y = 0;
- modified = 0;
- fname[0] = '\0';
- redraw();
-}
-
-
-/*** Commands ***/
-
-void commands(FILE *fc){
-
- char c;
- while((c=fgetc(fc))!=EOF){
- if (!change_style(c) && !move_around(c, fc)){
- switch(c){
- case 'i':
- state = TEXT;
- get_text(fc);
- break;
- case 'R':
- redraw();
- break;
- case 'b':
- state = BOX;
- get_box(fc);
- break;
- case 'A': autoend=1;
- case 'a':
- state = ARROW;
- get_arrow(fc);
- autoend = 0;
- break;
- case 'W':
- force_new = 1;/** FALLTHROUGH **/
- case 'w':
- write_file(fc);
- break;
- case 'e':
- check_modified(fc);/** FALLTHROUGH **/
- case 'E':
- load_file(fc);
- break;
- case 'N':
- new_file(fc);
- break;
- case 'x':
- state = DEL;
- delete(fc);
- break;
- case 'v':
- state = VIS;
- visual_box(fc);
- break;
- case 'q':
- check_modified(fc);/** FALLTHROUGH **/
- case 'Q':
- exit(0);
- break;
- }
- }
- check_bound();
- status_bar();
- show_cursor();
- step = 1;
- force_new = 0;
- }
-
-}
-
-void usage(){
- fprintf(stderr, "Usage: %s [-s] [-h] [file ...]\n", argv0);
- exit(1);
-}
-
-
-int main(int argc, char *argv[]){
- FILE *fc;
-
- ARGBEGIN {
- case 's':
- silent = 1;
- break;
- case 'h': /* FALLTHROUGH */
- default:
- usage();
- } ARGEND;
-
- init();
- while (argc){
- fc = fopen(argv[0], "r");
- if (fc == NULL){
- fprintf(stderr, "Error opening file %s\n", argv[0]);
- }
- else {
- commands(fc);
- fclose(fc);
- redraw();
- }
- argv++;
- argc--;
- }
- commands(stdin);
- return 0;
-}
diff --git a/gramscii.h b/gramscii.h
@@ -0,0 +1,138 @@
+#ifndef __GRAMSCII_H__
+#define __GRAMSCII_H__
+
+#include <stdio.h>
+#include <termios.h>
+#include <unistd.h>
+
+/** types **/
+
+typedef struct{
+ int sz;
+ int lst;
+ char *s;
+} line_t;
+
+/** constants **/
+
+#define MOVE 0x00
+#define BOX 0x01
+#define ARROW 0x02
+#define TEXT 0x04
+#define DEL 0x08
+#define VIS 0x10
+
+#define DIR_N 0x00
+#define DIR_R 0x01
+#define DIR_U 0x02
+#define DIR_D 0x04
+#define DIR_L 0x08
+
+#define DIR_HOR (DIR_R | DIR_L)
+#define DIR_VER (DIR_D | DIR_U)
+
+
+#define NOFIX 0x0
+#define FIX 0x1
+
+#define BG ' '
+#define PTR '+'
+#define UND '_'
+#define ARR_L '<'
+#define ARR_R '>'
+#define ARR_U '^'
+#define ARR_D 'v'
+
+#define HOME 0x01
+#define END 0x02
+#define MIDDLE 0x04
+
+#define VIDEO_NRM 0
+#define VIDEO_REV 7
+
+
+/** MACROS **/
+
+#define MIN(x,y) (x) < (y) ? (x) : (y)
+#define MAX(x,y) (x) > (y) ? (x) : (y)
+
+#define progr_x(d) ((d) == DIR_L ? -1 : (d) == DIR_R ? 1 : 0)
+#define progr_y(d) ((d) == DIR_U ? -1 : (d) == DIR_D ? 1 : 0)
+
+/* #define DEBUG 1 */
+
+/** global variables **/
+
+line_t *screen;
+int num_lines;
+int WIDTH, HEIGHT;
+
+int mode;
+int dir;
+int x;
+int y;
+int step;
+int mult;
+int force_new;
+char cursor;
+char corner;
+
+int hlines_sz;
+int vlines_sz;
+int corners_sz;
+int stmarks_sz;
+int endmarks_sz;
+
+int cur_hl, cur_vl, cur_corn, cur_start, cur_end;
+char line_h;
+char line_v;
+char mark_st;
+char mark_end;
+
+char modified;
+char fname[256];
+
+char visual;
+char silent;
+char autoend;
+
+struct termios t1, t2, t3;
+
+/** screen-related functions **/
+void reset_styles();
+void redraw();
+int move_around(char c, FILE *fc);
+void check_bound();
+void status_bar();
+void show_cursor();
+void set_cur(char c);
+void update_current();
+void set_xy(int _x, int _y, char c);
+void draw_xy(int x, int y, char c);
+char get_mark(char dir);
+void set_video(int v);
+char get_key(FILE *fc, char *msg);
+void get_string(FILE *fc, char *msg, char *s, int sz);
+void erase_box(int x1, int y1, char c);
+int is_yes(char c);
+void init_screen();
+void erase_line(char *s);
+void erase_screen();
+void go_to(int where);
+
+/** drawing-related functions **/
+int change_style(char c);
+void get_text(FILE *fc);
+void get_box(FILE *fc);
+void get_arrow(FILE *fc);
+void erase(FILE *fc);
+void visual_box(FILE *fc);
+
+/** file-related functions **/
+void write_file(FILE *fc);
+void check_modified(FILE *fc);
+void load_file(FILE *fc);
+void new_file(FILE *fc);
+
+
+#endif
diff --git a/main.c b/main.c
@@ -0,0 +1,175 @@
+/*
+*
+* gramscii: a simple editor for ASCII box-and-arrow charts
+*
+* Copyright (c) 2019 Vincenzo "KatolaZ" Nicosia <[email protected]>
+*
+* 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.
+*
+* 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.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. Please see the attached file COPYING.
+* Otherwise, please visit <https://www.gnu.org/licenses/>.
+*
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include "arg.h"
+#include "gramscii.h"
+
+
+char *argv0;
+
+void dump_lines(){
+ int i;
+ for (i=0; i<HEIGHT; i++){
+ printf("%s\n", screen[i].s);
+ }
+}
+
+void cleanup(int s){
+
+ if (!silent)
+ printf("\033[;H\033[2J");
+ else
+ dump_lines();
+ tcsetattr(0, TCSANOW, &t1);
+ fflush(stdout);
+ exit(0);
+}
+
+void exit_cleanup(void){
+ cleanup(0);
+}
+
+/*** Initialisation ***/
+
+void init(){
+
+ signal(SIGHUP, cleanup);
+ signal(SIGINT, cleanup);
+ signal(SIGTERM, cleanup);
+ signal(SIGQUIT, cleanup);
+ atexit(exit_cleanup);
+
+ tcgetattr(0, &t1);
+ t2 = t1;
+ t2.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(0, TCSANOW, &t2);
+
+ init_screen();
+ x = 0;
+ y = 0;
+ modified = 0;
+ fname[0] = '\0';
+ redraw();
+}
+
+
+/*** Commands ***/
+
+void commands(FILE *fc){
+
+ char c;
+ while((c=fgetc(fc))!=EOF){
+ if (!change_style(c) && !move_around(c, fc)){
+ switch(c){
+ case 'i':
+ mode = TEXT;
+ get_text(fc);
+ break;
+ case 'R':
+ redraw();
+ break;
+ case 'b':
+ mode = BOX;
+ get_box(fc);
+ break;
+ case 'A': autoend=1;
+ case 'a':
+ mode = ARROW;
+ get_arrow(fc);
+ autoend = 0;
+ break;
+ case 'W':
+ force_new = 1;/** FALLTHROUGH **/
+ case 'w':
+ write_file(fc);
+ break;
+ case 'e':
+ check_modified(fc);/** FALLTHROUGH **/
+ case 'E':
+ load_file(fc);
+ break;
+ case 'N':
+ new_file(fc);
+ break;
+ case 'x':
+ mode = DEL;
+ erase(fc);
+ break;
+ case 'v':
+ mode = VIS;
+ visual_box(fc);
+ break;
+ case 'q':
+ check_modified(fc);/** FALLTHROUGH **/
+ case 'Q':
+ exit(0);
+ break;
+ }
+ }
+ check_bound();
+ status_bar();
+ show_cursor();
+ step = 1;
+ force_new = 0;
+ }
+
+}
+
+void usage(){
+ fprintf(stderr, "Usage: %s [-s] [-h] [file ...]\n", argv0);
+ exit(1);
+}
+
+
+int main(int argc, char *argv[]){
+ FILE *fc;
+
+ ARGBEGIN {
+ case 's':
+ silent = 1;
+ break;
+ case 'h': /* FALLTHROUGH */
+ default:
+ usage();
+ } ARGEND;
+
+ init();
+ while (argc){
+ fc = fopen(argv[0], "r");
+ if (fc == NULL){
+ fprintf(stderr, "Error opening file %s\n", argv[0]);
+ }
+ else {
+ commands(fc);
+ fclose(fc);
+ redraw();
+ }
+ argv++;
+ argc--;
+ }
+ commands(stdin);
+ return 0;
+}
diff --git a/screen.c b/screen.c
@@ -0,0 +1,419 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+#include "gramscii.h"
+#include "config.h"
+
+/*** screen management functions ***/
+
+
+/*** Status bar ***/
+
+char* mode_str(){
+ switch(mode){
+ case MOVE:
+ return "mov";
+ case TEXT:
+ return "txt";
+ case BOX:
+ return "box";
+ case ARROW:
+ return "arr";
+ case DEL:
+ return "del";
+ case VIS:
+ return "vis";
+ default:
+ return "ERR";
+ }
+ return "ERR";
+}
+
+char get_mark(char dir){
+ switch(dir){
+ case DIR_U:
+ return '^';
+ case DIR_D:
+ return 'v';
+ case DIR_L:
+ return '<';
+ case DIR_R:
+ return '>';
+ }
+ return '>';
+}
+
+
+void status_bar(){
+
+ if (silent)
+ return;
+ printf("\033[%d;1f\033[7m", HEIGHT+1);
+ printf("%*s", WIDTH-1, "");
+ printf("\033[%d;1f\033[7m", HEIGHT+1);
+ printf(" x:%3d y:%3d -- MODE:%4s HL:%c VL:%c CN:%c SP:%c EP:%c %10s",
+ x, y, mode_str(), line_h, line_v, corner, mark_st, mark_end, "…
+ if (!modified)
+ printf(" [%s]", fname );
+ else
+ printf(" *%s*", fname );
+#ifdef DEBUG
+ printf(" '%d' ", screen[y].s[x]);
+#endif
+ printf("\033[0m");
+ fflush(stdout);
+}
+
+char get_key(FILE *fc, char *msg){
+
+ if (silent)
+ return 0;
+ printf("\033[%d;1f\033[7m", HEIGHT+1);
+ printf("%*s", WIDTH, "");
+ printf("\033[%d;1f\033[7m", HEIGHT+1);
+ printf("%s", msg);
+ fflush(stdout);
+ printf("\033[0m");
+ fflush(stdout);
+ return fgetc(fc);
+}
+
+void get_string(FILE *fc, char *msg, char *s, int sz){
+
+ if (!silent){
+ printf("\033[%d;1f\033[7m", HEIGHT+1);
+ printf("%*s", WIDTH, "");
+ printf("\033[%d;1f\033[7m", HEIGHT+1);
+
+ /* We must activate echo now */
+ t3 = t2;
+ t3.c_lflag |= (ECHO | ICANON);
+ tcsetattr(0, TCSANOW, &t3);
+ printf("%s", msg);
+ printf("\033[0m");
+ }
+ fgets(s, sz, fc);
+ s[strlen(s)-1] = '\0';
+ tcsetattr(0, TCSANOW, &t2);
+ if (!silent)
+ fflush(stdout);
+}
+
+int is_yes(char c){
+ return c=='y' ? 1 : c == 'Y'? 1 : 0;
+}
+
+/*** Screen management ***/
+
+void show_cursor(){
+ if (silent)
+ return;
+ printf("\033[%d;%df", y+1, x+1);
+ fflush(stdout);
+}
+
+
+void set_xy(int _x, int _y, char c){
+ line_t *tmp;
+ if (_y >= num_lines){
+ tmp = realloc(screen, (_y + LONG_STEP)* sizeof(line_t));
+ if (tmp == NULL){
+ fprintf(stderr, "Unable to allocate memory for more li…
+ exit(1);
+ }
+ else while ( num_lines < _y + LONG_STEP){
+ screen[num_lines].sz = WIDTH+1;
+ screen[num_lines].s = malloc((screen[num_lines].sz) * …
+ if (screen[num_lines].s == NULL){
+ perror("allocating screen[num_lines].s");
+ exit(1);
+ }
+ memset(screen[num_lines].s, BG, screen[num_lines].sz);
+ screen[num_lines].lst = 0;
+ screen[num_lines].s[screen[num_lines].lst+1]='\0';
+ num_lines ++;
+ }
+ }
+ if (screen[_y].sz < _x + 2){
+ screen[_y].sz = (_x +2) * 2;
+ screen[_y].s = realloc(screen[_y].s, screen[_y].sz * sizeof(ch…
+ }
+ while (screen[_y].lst<_x){
+ screen[_y].lst ++;
+ screen[_y].s[screen[_y].lst] = BG;
+ }
+ screen[_y].s[_x] = c;
+ if (_x == screen[_y].lst)
+ screen[_y].s[_x+1] = '\0';
+}
+
+void set_cur(char c){
+ set_xy(x, y, c);
+}
+
+void draw_xy(int x, int y, char c){
+ /* FIXME: check if x and y are valid!!!! */
+ if (silent)
+ return;
+ printf("\033[%d;%df",y+1,x+1);
+ putchar(c);
+ fflush(stdout);
+}
+
+void update_current(){
+ if (silent)
+ return;
+ printf("\033[%d'%df",y+1,x+1);
+ putchar(screen[y].s[x]);
+ fflush(stdout);
+}
+
+void erase_line(char *s){
+ while(*s){
+ *s = BG;
+ s++;
+ }
+}
+
+void erase_box(int x1, int y1, char c){
+ int x_incr, y_incr, i;
+
+ x_incr = x1 < x? +1: -1;
+ y_incr = y1 < y? +1: -1;
+ do{
+ i = y1;
+ do{
+ set_xy(x1, i, c);
+ } while(i != y && (1 | (i += y_incr)));
+ } while(x1 != x && (1 | (x1 += x_incr)));
+
+}
+
+void erase_screen(){
+ int i;
+ for(i=0;i<HEIGHT; i++)
+ erase_line(screen[i].s);
+}
+
+void check_bound(){
+ if (x<0) x=0;
+ else if (x>=WIDTH) x = WIDTH-1;
+ if (y<0) y=0;
+ else if (y>=HEIGHT) y = HEIGHT -1;
+}
+
+void reset_styles(){
+
+ cur_corn = 0;
+ corner = corners[0];
+ cur_hl = cur_vl = 0;
+ cur_start = cur_end = 0;
+ line_h = hlines[cur_hl];
+ line_v = vlines[cur_vl];
+ mark_st = st_marks[cur_start];
+ mark_end = end_marks[cur_end];
+}
+
+void redraw(){
+ int i;
+
+ if (silent)
+ return;
+ printf("\033[2J\033[1;1H");
+ for (i=0;i<HEIGHT;i++){
+ fprintf(stdout,"%s\n",screen[i].s);
+ }
+ status_bar();
+ show_cursor();
+}
+
+void go_to(int where){
+ switch(where){
+ case HOME:
+ x = y = 0;
+ break;
+ case END:
+ x = WIDTH-1;
+ y = HEIGHT-1;
+ break;
+ case MIDDLE:
+ x = WIDTH/2;
+ y = HEIGHT/2;
+ break;
+ }
+ check_bound();
+ show_cursor();
+}
+
+void handle_goto(){
+ char c;
+ c=getchar();
+ switch(c){
+ case 'h':
+ dir = DIR_L;
+ x = 0;
+ break;
+ case 'l':
+ dir = DIR_R;
+ x = WIDTH - 1;
+ break;
+ case 'j':
+ dir = DIR_D;
+ y = HEIGHT - 1;
+ break;
+ case 'k':
+ dir = DIR_U;
+ y = 0;
+ break;
+ case 'g':
+ dir = DIR_N;
+ go_to(HOME);
+ break;
+ case 'G':
+ dir = DIR_N;
+ go_to(END);
+ break;
+ case 'm':
+ dir = DIR_N;
+ go_to(MIDDLE);
+ break;
+ }
+ check_bound();
+ show_cursor();
+}
+
+
+int get_escape(FILE *fc){
+ char c[4];
+
+ c[0] = fgetc(fc);
+ if (c[0] == '['){
+ c[1] = fgetc(fc);
+ switch(c[1]){
+ case 'D':
+ dir = DIR_L;
+ x -= step;
+ break;
+ case 'B':
+ dir = DIR_D;
+ y += step;
+ break;
+ case 'A':
+ dir = DIR_U;
+ y -= step;
+ break;
+ case 'C':
+ dir = DIR_R;
+ x += step;
+ break;
+ }
+ return 1;
+ }
+ else{
+ ungetc(c[0], fc);
+ return 0;
+ }
+
+}
+
+
+int move_around(char c, FILE *fc){
+
+ if (isdigit(c)){
+ if (mult)
+ mult *=10;
+ mult += c - '0';
+ return 0;
+ }
+ switch(c){
+ case 27: /* control sequence? */
+ c = get_escape(fc);
+ break;
+ case 'H': step = LONG_STEP;/** FALLTHROUGH **/
+ case 'h':
+ dir = DIR_L;
+ if (mult)
+ step *= mult;
+ x -= step;
+ break;
+ case 'J': step = LONG_STEP;/** FALLTHROUGH **/
+ case 'j':
+ if (mult)
+ step *= mult;
+ dir = DIR_D;
+ y += step;
+ break;
+ case 'K': step = LONG_STEP;/** FALLTHROUGH **/
+ case 'k':
+ if (mult)
+ step *= mult;
+ dir = DIR_U;
+ y -= step;
+ break;
+ case 'L': step = LONG_STEP;/** FALLTHROUGH **/
+ case 'l':
+ if (mult)
+ step *= mult;
+ dir = DIR_R;
+ x += step;
+ break;
+ case 'g':
+ handle_goto();
+ break;
+ default:
+ return 0;
+ }
+ mult = 0;
+ return c;
+}
+
+
+void set_video(int v){
+ if (silent)
+ return;
+ printf("\033[%dm", v);
+ fflush(stdout);
+}
+
+
+void init_screen(){
+ int i;
+ struct winsize wsz;
+
+ if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz)){
+ WIDTH=wsz.ws_col - 2;
+ HEIGHT=wsz.ws_row - 1;
+ }
+ else {
+ WIDTH=80;
+ HEIGHT=24;
+ }
+ screen = malloc(HEIGHT * sizeof(line_t));
+ num_lines = HEIGHT;
+ if (screen == NULL){
+ perror("allocating screen");
+ exit(1);
+ }
+ for (i=0; i<HEIGHT; i++){
+ screen[i].sz = WIDTH+1;
+ screen[i].s = malloc((screen[i].sz) * sizeof(char));
+ if (screen[i].s == NULL){
+ perror("allocating screen[i].s");
+ exit(1);
+ }
+ memset(screen[i].s, BG, screen[i].sz);
+ screen[i].lst = 0;
+ screen[i].s[screen[i].lst+1]='\0';
+ }
+ hlines_sz= sizeof(hlines) -1;
+ vlines_sz= sizeof(vlines) -1;
+ corners_sz = sizeof(corners) -1;
+ stmarks_sz = sizeof(st_marks) - 1;
+ endmarks_sz = sizeof(st_marks) - 1;
+ reset_styles();
+}
+
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.