aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2016-05-23 17:14:32 +0200
committerMarc André Tanner <mat@brain-dump.org>2016-05-29 11:24:23 +0200
commit8bd8422031eba0f98a904ef20a57507df4df21d5 (patch)
treeb60cac320c53462928cc9c96c231779ac95dc339
parente419d484245bf20f01c4b04da78cd15fbaac6366 (diff)
downloadvis-8bd8422031eba0f98a904ef20a57507df4df21d5.tar.gz
vis-8bd8422031eba0f98a904ef20a57507df4df21d5.tar.xz
vis-menu: more cleanup
-rw-r--r--vis-menu.c414
1 files changed, 195 insertions, 219 deletions
diff --git a/vis-menu.c b/vis-menu.c
index 65aeea1..5883a0d 100644
--- a/vis-menu.c
+++ b/vis-menu.c
@@ -46,11 +46,10 @@
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
-enum Color {
+typedef enum {
C_Normal,
C_Reverse
-};
-typedef enum Color Color;
+} Color;
typedef struct Item Item;
struct Item {
@@ -58,24 +57,6 @@ struct Item {
Item *left, *right;
};
-static void appenditem(Item*, Item**, Item**);
-static void calcoffsets(void);
-static void cleanup(void);
-static void die(const char*);
-static void drawtext(const char*, size_t, Color);
-static void drawmenu(void);
-static char *fstrstr(const char*, const char*);
-static void insert(const char*, ssize_t);
-static void match();
-static size_t nextrune(int);
-static void readstdin(void);
-static int run(void);
-static void resetline(void);
-static void setup(void);
-static size_t textw(const char*);
-static size_t textwn(const char*, int);
-static void xread(int fildes, void *buf, size_t nbyte);
-
static char text[BUFSIZ] = "";
static int barpos = 0;
static int mw, mh;
@@ -89,9 +70,9 @@ static Item *prev, *curr, *next, *sel;
static struct termios tio_old, tio_new;
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
-void
+static void
appenditem(Item *item, Item **list, Item **last) {
- if(!*last)
+ if (!*last)
*list = item;
else
(*last)->right = item;
@@ -100,47 +81,60 @@ appenditem(Item *item, Item **list, Item **last) {
*last = item;
}
-void
+static size_t
+textwn(const char *s, int l) {
+ int b, c; /* bytes and UTF-8 characters */
+
+ for(b=c=0; s && s[b] && (l<0 || b<l); b++) if((s[b] & 0xc0) != 0x80) c++;
+ return c+4; /* Accomodate for the leading and trailing spaces */
+}
+
+static size_t
+textw(const char *s) {
+ return textwn(s, -1);
+}
+
+static void
calcoffsets(void) {
int i, n;
- if(lines>0)
+ if (lines > 0)
n = lines;
else
n = mw - (promptw + inputw + textw("<") + textw(">"));
- for(i = 0, next = curr; next; next = next->right)
- if((i += (lines>0 ? 1 : MIN(textw(next->text), n))) > n)
+ for (i = 0, next = curr; next; next = next->right)
+ if ((i += (lines>0 ? 1 : MIN(textw(next->text), n))) > n)
break;
- for(i = 0, prev = curr; prev && prev->left; prev = prev->left)
- if((i += (lines>0 ? 1 : MIN(textw(prev->left->text), n))) > n)
+ for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
+ if ((i += (lines>0 ? 1 : MIN(textw(prev->left->text), n))) > n)
break;
}
-void
+static void
cleanup() {
- if(barpos==0) fprintf(stderr, "\n");
+ if (barpos == 0) fprintf(stderr, "\n");
else fprintf(stderr, "\033[G\033[K");
tcsetattr(0, TCSANOW, &tio_old);
}
-void
+static void
die(const char *s) {
tcsetattr(0, TCSANOW, &tio_old);
fprintf(stderr, "%s\n", s);
exit(1);
}
-void
+static void
drawtext(const char *t, size_t w, Color col) {
const char *prestr, *poststr;
int i, tw;
char *buf;
- if(w<5) return; /* This is the minimum size needed to write a label: 1 char + 4 padding spaces */
- tw=w-4; /* This is the text width, without the padding */
- if((buf=calloc(1, (tw+1))) == NULL) die("Can't calloc.");
- switch(col) {
+ if (w<5) return; /* This is the minimum size needed to write a label: 1 char + 4 padding spaces */
+ tw = w-4; /* This is the text width, without the padding */
+ if (!(buf = calloc(1, tw+1))) die("Can't calloc.");
+ switch (col) {
case C_Reverse:
prestr="\033[7m";
poststr="\033[0m";
@@ -151,16 +145,22 @@ drawtext(const char *t, size_t w, Color col) {
}
memset(buf, ' ', tw);
- buf[tw]='\0';
+ buf[tw] = '\0';
memcpy(buf, t, MIN(strlen(t), tw));
- if(textw(t)>w) /* Remember textw returns the width WITH padding */
- for(i=MAX((tw-4), 0); i<tw; i++) buf[i]='.';
+ if (textw(t) > w) /* Remember textw returns the width WITH padding */
+ for (i = MAX((tw-4), 0); i < tw; i++) buf[i] = '.';
fprintf(stderr, "%s %s %s", prestr, buf, poststr);
free(buf);
}
-void
+static void
+resetline(void) {
+ if (barpos != 0) fprintf(stderr, "\033[%iH", barpos > 0 ? 0 : (mh-lines));
+ else fprintf(stderr, "\033[%iF", lines);
+}
+
+static void
drawmenu(void) {
Item *item;
int rw;
@@ -172,29 +172,29 @@ drawmenu(void) {
fprintf(stderr, "\033[0G");
fprintf(stderr, "\033[K");
- if(prompt)
+ if (prompt)
drawtext(prompt, promptw, C_Reverse);
- drawtext(text, ((lines==0 && matches)?inputw:mw-promptw), C_Normal);
+ drawtext(text, (lines==0 && matches) ? inputw : mw-promptw, C_Normal);
- if(lines>0) {
- if(barpos!=0) resetline();
- for(rw=0, item = curr; item != next; rw++, item = item->right) {
+ if (lines > 0) {
+ if (barpos != 0) resetline();
+ for (rw = 0, item = curr; item != next; rw++, item = item->right) {
fprintf(stderr, "\n");
drawtext(item->text, mw, (item == sel) ? C_Reverse : C_Normal);
}
- for(; rw<lines; rw++)
+ for (; rw < lines; rw++)
fprintf(stderr, "\n\033[K");
resetline();
- } else if(matches) {
- rw=mw-(4+promptw+inputw);
- if(curr->left)
+ } else if (matches) {
+ rw = mw-(4+promptw+inputw);
+ if (curr->left)
drawtext("<", 5 /*textw("<")*/, C_Normal);
- for(item = curr; item != next; item = item->right) {
+ for (item = curr; item != next; item = item->right) {
drawtext(item->text, MIN(textw(item->text), rw), (item == sel) ? C_Reverse : C_Normal);
- if((rw-= textw(item->text)) <= 0) break;
+ if ((rw -= textw(item->text)) <= 0) break;
}
- if(next) {
+ if (next) {
fprintf(stderr, "\033[%iG", mw-5);
drawtext(">", 5 /*textw(">")*/, C_Normal);
}
@@ -203,27 +203,14 @@ drawmenu(void) {
fprintf(stderr, "\033[%iG", (int)(promptw+textwn(text, cursor)-1));
}
-char*
+static char*
fstrstr(const char *s, const char *sub) {
- size_t len;
-
- for(len = strlen(sub); *s; s++)
- if(!fstrncmp(s, sub, len))
- return (char *)s;
+ for (size_t len = strlen(sub); *s; s++)
+ if (!fstrncmp(s, sub, len))
+ return (char*)s;
return NULL;
}
-void
-insert(const char *str, ssize_t n) {
- if(strlen(text) + n > sizeof text - 1)
- return;
- memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0));
- if(n > 0)
- memcpy(&text[cursor], str, n);
- cursor += n;
- match();
-}
-
static void
match(void)
{
@@ -278,7 +265,18 @@ match(void)
calcoffsets();
}
-size_t
+static void
+insert(const char *str, ssize_t n) {
+ if (strlen(text) + n > sizeof text - 1)
+ return;
+ memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0));
+ if (n > 0)
+ memcpy(&text[cursor], str, n);
+ cursor += n;
+ match();
+}
+
+static size_t
nextrune(int inc) {
ssize_t n;
@@ -286,42 +284,85 @@ nextrune(int inc) {
return n;
}
-void
+static void
readstdin() {
char buf[sizeof text], *p, *maxstr = NULL;
size_t i, max = 0, size = 0;
for(i = 0; fgets(buf, sizeof buf, stdin); i++) {
- if(i+1 >= size / sizeof *items)
- if(!(items = realloc(items, (size += BUFSIZ))))
+ if (i+1 >= size / sizeof *items)
+ if (!(items = realloc(items, (size += BUFSIZ))))
die("Can't realloc.");
- if((p = strchr(buf, '\n')))
+ if ((p = strchr(buf, '\n')))
*p = '\0';
- if(!(items[i].text = strdup(buf)))
+ if (!(items[i].text = strdup(buf)))
die("Can't strdup.");
- if(strlen(items[i].text) > max)
+ if (strlen(items[i].text) > max)
max = textw(maxstr = items[i].text);
}
- if(items)
+ if (items)
items[i].text = NULL;
inputw = textw(maxstr);
}
-void
-resetline(void) {
- if(barpos!=0) fprintf(stderr, "\033[%iH", (barpos>0)?0:(mh-lines));
- else fprintf(stderr, "\033[%iF", lines);
+static void
+xread(int fd, void *buf, size_t nbyte) {
+ if (read(fd, buf, nbyte) < 0)
+ die("Can not read.");
}
-int
+static void
+setup(void) {
+ int fd, result = -1;
+ struct winsize ws;
+
+ /* re-open stdin to read keyboard */
+ if (!freopen("/dev/tty", "r", stdin)) die("Can't reopen tty.");
+
+ /* ioctl() the tty to get size */
+ fd = open("/dev/tty", O_RDWR);
+ if (fd == -1) {
+ mh = 24;
+ mw = 80;
+ } else {
+ result = ioctl(fd, TIOCGWINSZ, &ws);
+ close(fd);
+ if (result < 0) {
+ mw = 80;
+ mh = 24;
+ } else {
+ mw = ws.ws_col;
+ mh = ws.ws_row;
+ }
+ }
+
+ /* change terminal attributes, save old */
+ tcgetattr(0, &tio_old);
+ tio_new = tio_old;
+ tio_new.c_iflag &= ~(BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+ tio_new.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+ tio_new.c_cflag &= ~(CSIZE|PARENB);
+ tio_new.c_cflag |= CS8;
+ tio_new.c_cc[VMIN] = 1;
+ tcsetattr(0, TCSANOW, &tio_new);
+
+ lines = MIN(MAX(lines, 0), mh);
+ promptw = prompt ? textw(prompt) : 0;
+ inputw = MIN(inputw, mw/3);
+ match();
+ if (barpos != 0) resetline();
+ drawmenu();
+}
+
+static int
run(void) {
char buf[32];
char c;
- while(1) {
+ for (;;) {
xread(0, &c, 1);
memset(buf, '\0', sizeof buf);
- buf[0]=c;
+ buf[0] = c;
switch_top:
switch(c) {
case CONTROL('['):
@@ -329,7 +370,7 @@ run(void) {
esc_switch_top:
switch(c) {
case CONTROL('['): /* ESC, need to press twice due to console limitations */
- c=CONTROL('C');
+ c = CONTROL('C');
goto switch_top;
case '[':
xread(0, &c, 1);
@@ -337,68 +378,72 @@ run(void) {
case '1': /* Home */
case '7':
case 'H':
- if(c!='H') xread(0, &c, 1); /* Remove trailing '~' from stdin */
- c=CONTROL('A');
+ if (c != 'H') xread(0, &c, 1); /* Remove trailing '~' from stdin */
+ c = CONTROL('A');
goto switch_top;
case '3': /* Delete */
xread(0, &c, 1); /* Remove trailing '~' from stdin */
- c=CONTROL('D');
+ c = CONTROL('D');
goto switch_top;
case '4': /* End */
case '8':
case 'F':
- if(c!='F') xread(0, &c, 1); /* Remove trailing '~' from stdin */
- c=CONTROL('E');
+ if (c != 'F') xread(0, &c, 1); /* Remove trailing '~' from stdin */
+ c = CONTROL('E');
goto switch_top;
case '5': /* PageUp */
xread(0, &c, 1); /* Remove trailing '~' from stdin */
- c=CONTROL('V');
+ c = CONTROL('V');
goto switch_top;
case '6': /* PageDown */
xread(0, &c, 1); /* Remove trailing '~' from stdin */
- c='v';
+ c = 'v';
goto esc_switch_top;
case 'A': /* Up arrow */
- c=CONTROL('P');
+ c = CONTROL('P');
goto switch_top;
case 'B': /* Down arrow */
- c=CONTROL('N');
+ c = CONTROL('N');
goto switch_top;
case 'C': /* Right arrow */
- c=CONTROL('F');
+ c = CONTROL('F');
goto switch_top;
case 'D': /* Left arrow */
- c=CONTROL('B');
+ c = CONTROL('B');
goto switch_top;
}
break;
case 'b':
- while(cursor > 0 && text[nextrune(-1)] == ' ')
+ while (cursor > 0 && text[nextrune(-1)] == ' ')
cursor = nextrune(-1);
- while(cursor > 0 && text[nextrune(-1)] != ' ')
+ while (cursor > 0 && text[nextrune(-1)] != ' ')
cursor = nextrune(-1);
break;
case 'f':
- while(text[cursor] != '\0' && text[nextrune(+1)] == ' ')
- cursor = nextrune(+1);
- if(text[cursor] != '\0') do
+ while (text[cursor] != '\0' && text[nextrune(+1)] == ' ')
cursor = nextrune(+1);
- while(text[cursor] != '\0' && text[cursor] != ' ');
+ if (text[cursor] != '\0') {
+ do {
+ cursor = nextrune(+1);
+ } while (text[cursor] != '\0' && text[cursor] != ' ');
+ }
break;
case 'd':
- while(text[cursor] != '\0' && text[nextrune(+1)] == ' ') {
+ while (text[cursor] != '\0' && text[nextrune(+1)] == ' ') {
cursor = nextrune(+1);
insert(NULL, nextrune(-1) - cursor);
}
- if(text[cursor] != '\0') do {
- cursor = nextrune(+1);
- insert(NULL, nextrune(-1) - cursor);
- } while(text[cursor] != '\0' && text[cursor] != ' ');
+ if (text[cursor] != '\0') {
+ do {
+ cursor = nextrune(+1);
+ insert(NULL, nextrune(-1) - cursor);
+ } while (text[cursor] != '\0' && text[cursor] != ' ');
+ }
break;
case 'v':
- if(!next)
+ if (!next)
break;
- sel=curr=next;
+ sel = curr = next;
calcoffsets();
break;
default:
@@ -409,7 +454,7 @@ run(void) {
return EXIT_FAILURE;
case CONTROL('M'): /* Return */
case CONTROL('J'):
- if(sel) strncpy(text, sel->text, sizeof text); /* Complete the input first, when hitting return */
+ if (sel) strncpy(text, sel->text, sizeof text); /* Complete the input first, when hitting return */
cursor = strlen(text);
match();
drawmenu();
@@ -419,19 +464,19 @@ run(void) {
puts(text);
return EXIT_SUCCESS;
case CONTROL('A'):
- if(sel == matches) {
- cursor=0;
+ if (sel == matches) {
+ cursor = 0;
break;
}
- sel=curr=matches;
+ sel = curr = matches;
calcoffsets();
break;
case CONTROL('E'):
- if(text[cursor] != '\0') {
+ if (text[cursor] != '\0') {
cursor = strlen(text);
break;
}
- if(next) {
+ if (next) {
curr = matchend;
calcoffsets();
curr = prev;
@@ -442,42 +487,42 @@ run(void) {
sel = matchend;
break;
case CONTROL('B'):
- if(cursor > 0 && (!sel || !sel->left || lines > 0)) {
+ if (cursor > 0 && (!sel || !sel->left || lines > 0)) {
cursor = nextrune(-1);
break;
}
/* fallthrough */
case CONTROL('P'):
- if(sel && sel->left && (sel = sel->left)->right == curr) {
+ if (sel && sel->left && (sel = sel->left)->right == curr) {
curr = prev;
calcoffsets();
}
break;
case CONTROL('F'):
- if(text[cursor] != '\0') {
+ if (text[cursor] != '\0') {
cursor = nextrune(+1);
break;
}
/* fallthrough */
case CONTROL('N'):
- if(sel && sel->right && (sel = sel->right) == next) {
+ if (sel && sel->right && (sel = sel->right) == next) {
curr = next;
calcoffsets();
}
break;
case CONTROL('D'):
- if(text[cursor] == '\0')
+ if (text[cursor] == '\0')
break;
cursor = nextrune(+1);
/* fallthrough */
case CONTROL('H'):
case CONTROL('?'): /* Backspace */
- if(cursor == 0)
+ if (cursor == 0)
break;
insert(NULL, nextrune(-1) - cursor);
break;
case CONTROL('I'): /* TAB */
- if(!sel)
+ if (!sel)
break;
strncpy(text, sel->text, sizeof text);
cursor = strlen(text);
@@ -491,19 +536,19 @@ run(void) {
insert(NULL, 0 - cursor);
break;
case CONTROL('W'):
- while(cursor > 0 && text[nextrune(-1)] == ' ')
+ while (cursor > 0 && text[nextrune(-1)] == ' ')
insert(NULL, nextrune(-1) - cursor);
- while(cursor > 0 && text[nextrune(-1)] != ' ')
+ while (cursor > 0 && text[nextrune(-1)] != ' ')
insert(NULL, nextrune(-1) - cursor);
break;
case CONTROL('V'):
- if(!prev)
+ if (!prev)
break;
sel = curr = prev;
calcoffsets();
break;
default:
- if(!iscntrl(*buf))
+ if (!iscntrl(*buf))
insert(buf, strlen(buf));
break;
}
@@ -511,110 +556,41 @@ run(void) {
}
}
-void
-setup(void) {
- int fd, result=-1;
- struct winsize ws;
-
- /* re-open stdin to read keyboard */
- if(freopen("/dev/tty", "r", stdin) == NULL) die("Can't reopen tty.");
-
- /* ioctl() the tty to get size */
- fd = open("/dev/tty", O_RDWR);
- if(fd == -1) {
- mh=24;
- mw=80;
- } else {
- result = ioctl(fd, TIOCGWINSZ, &ws);
- close(fd);
- if(result<0) {
- mw=80;
- mh=24;
- } else {
- mw=ws.ws_col;
- mh=ws.ws_row;
- }
- }
-
- /* change terminal attributes, save old */
- tcgetattr(0, &tio_old);
- memcpy ((char *)&tio_new, (char *)&tio_old, sizeof(struct termios));
- tio_new.c_iflag &= ~(BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
- tio_new.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
- tio_new.c_cflag &= ~(CSIZE|PARENB);
- tio_new.c_cflag |= CS8;
- tio_new.c_cc[VMIN]=1;
- tcsetattr(0, TCSANOW, &tio_new);
-
- lines=MIN(MAX(lines, 0), mh);
- promptw=(prompt?textw(prompt):0);
- inputw=MIN(inputw, mw/3);
- match();
- if(barpos!=0) resetline();
- drawmenu();
-}
-
-size_t
-textw(const char *s) {
- return textwn(s, -1);
-}
-
-size_t
-textwn(const char *s, int l) {
- int b, c; /* bytes and UTF-8 characters */
-
- for(b=c=0; s && s[b] && (l<0 || b<l); b++) if((s[b] & 0xc0) != 0x80) c++;
- return c+4; /* Accomodate for the leading and trailing spaces */
-}
-
-void
-xread(int fildes, void *buf, size_t nbyte) {
- if (read(fildes, buf, nbyte) < 0)
- die("Can not read.");
+static void
+usage(void) {
+ fputs("usage: vis-menu [-b|-t] [-i] [-l lines] [-p prompt] [initial selection]\n", stderr);
+ exit(EXIT_FAILURE);
}
int
main(int argc, char **argv) {
- int i;
-
- for(i=1; i<argc; i++)
- /* single flags */
- if(!strcmp(argv[i], "-v")) {
+ for (int i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-v")) {
puts("vis-menu " VERSION);
exit(EXIT_SUCCESS);
- }
- else if(!strcmp(argv[i], "-i"))
+ } else if (!strcmp(argv[i], "-i")) {
fstrncmp = strncasecmp;
- else if(!strcmp(argv[i], "-t"))
- barpos=1;
- else if(!strcmp(argv[i], "-b"))
- barpos=-1;
- /* double flags */
- else if(!strcmp(argv[i], "-p")) {
- if(argc > i+1)
- prompt=argv[++i];
- else {
- fprintf(stderr, "Must provide a prompt\n");
- exit(EXIT_FAILURE);
- }
- }
- else if(!strcmp(argv[i], "-l")) {
- if(argc > i+1)
- lines = atoi(argv[++i]);
- else {
- fprintf(stderr, "Must provide a line count\n");
- exit(EXIT_FAILURE);
- }
- }
- else {
+ } else if (!strcmp(argv[i], "-t")) {
+ barpos = +1;
+ } else if (!strcmp(argv[i], "-b")) {
+ barpos = -1;
+ } else if (argv[i][0] != '-') {
strncpy(text, argv[i], sizeof(text)-1);
cursor = strlen(text);
+ } else if (i + 1 == argc) {
+ usage();
+ } else if (!strcmp(argv[i], "-p")) {
+ prompt = argv[++i];
+ } else if (!strcmp(argv[i], "-l")) {
+ lines = atoi(argv[++i]);
+ } else {
+ usage();
}
+ }
readstdin();
setup();
- i = run();
+ int status = run();
cleanup();
- return i;
+ return status;
}
-