commit 3e622e86c7ebbedd97b0d855cfff4ae9b59cc312
parent 10159ed5d2665304cd03cd9b657c7df41296a2cc
Author: Louis Burda <quent.burda@gmail.com>
Date: Tue, 20 Jul 2021 00:26:45 +0200
Allow output of multiple entries
Diffstat:
M | tmenu.c | | | 177 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
1 file changed, 98 insertions(+), 79 deletions(-)
diff --git a/tmenu.c b/tmenu.c
@@ -24,14 +24,22 @@ enum {
void* checkp(void *p);
void die(const char *fmtstr, ...);
-char* aprintf(const char *fmtstr, ...);
-ssize_t fgetln(char *buf, size_t size, FILE *f);
+char* aprintf(const char *fmtstr, ...); /* yet unused */
-int handleopt(const char *flag, const char **args);
+int readkey(FILE *f);
+ssize_t freadln(char *buf, size_t size, FILE *f);
+
+size_t entlen(size_t i);
+char* readent(char *buf, size_t linei);
+void setent(size_t linei, size_t start);
void search_handlekey(int c);
void search_selnext();
+int run();
+int handleopt(const char *flag, const char **args);
+int main(int argc, const char **argv);
+
const char *CSI_CLEARLINE = "\x1b[K";
const char *CSI_HIDECUR = "\x1b[25l";
const char *CSI_SHOWCUR = "\x1b[25h";
@@ -45,12 +53,13 @@ const char *userfile = NULL;
FILE *f;
-size_t linesel, linecap, linec, *lines = NULL;
+size_t entsel, entcap, entcnt, *entries = NULL;
char searchbuf[1024] = { 0 };
size_t searchc = 0;
int mode = MODE_BROWSE;
+int multiout = 0;
void*
checkp(void *p)
@@ -95,10 +104,11 @@ aprintf(const char *fmtstr, ...)
}
int
-readcode(FILE *f)
+readkey(FILE *f)
{
int c;
+ if ((c = fgetc(f)) != '\x1b') return c;
if ((c = fgetc(f)) != '[') return c;
switch ((c = fgetc(f))) {
case 'A':
@@ -114,71 +124,85 @@ readcode(FILE *f)
return c;
}
-void
-setent(size_t linei, size_t pos)
+ssize_t
+freadln(char *buf, size_t size, FILE *f)
{
- if (linei >= linecap) {
- linecap *= 2;
- lines = checkp(realloc(lines, linecap));
- }
- lines[linei] = pos;
-}
+ size_t i = 0;
-void
-search_handlekey(int c)
-{
- switch (c) {
- case 127: /* DEL */
- if (searchc) searchc--;
- return;
- default:
- if (searchc < sizeof(searchbuf))
- searchbuf[searchc++] = c & 0xff;
- }
- search_selnext();
+ for (i = 0; i < size && (buf[i] = fgetc(f)) >= 0; i++)
+ if (buf[i] == '\n') return i + 1;
+
+ return (buf[i] < 0) ? -1 : i;
}
size_t
-linesize(size_t linei)
+entlen(size_t linei)
{
- return lines[linei + 1] - lines[linei];
+ return entries[linei + 1] - entries[linei];
}
char*
-readline(char *buf, int linei)
+readent(char *buf, size_t linei)
{
size_t nleft, nread;
char *bp, *tok;
- fseek(f, lines[linei], SEEK_SET);
- nleft = linesize(linei);
+ fseek(f, entries[linei], SEEK_SET);
+ nleft = entlen(linei);
buf = bp = checkp(realloc(buf, nleft));
while (nleft && (nread = fread(bp, 1, nleft, f)) > 0) {
nleft -= nread;
bp += nread;
}
if (nread < 0) die("Failed to read line %i from input\n", linei);
- tok = memchr(buf, '\n', linesize(linei));
+ tok = memchr(buf, '\n', entlen(linei));
if (tok) *tok = '\0';
return buf;
}
void
+setent(size_t linei, size_t pos)
+{
+ if (linei >= entcap) {
+ entcap *= 2;
+ entries = checkp(realloc(entries, entcap));
+ }
+ entries[linei] = pos;
+}
+
+void
+search_handlekey(int c)
+{
+ switch (c) {
+ case 127: /* DEL */
+ if (searchc) searchc--;
+ return;
+ default:
+ if (searchc < sizeof(searchbuf))
+ searchbuf[searchc++] = c & 0xff;
+ }
+ search_selnext();
+}
+
+void
search_selnext()
{
size_t i, linei, nread, nleft;
char *line = NULL, *end, *bp;
- if (!searchc) return;
+ if (!searchc) {
+ entsel = (entsel + 1) % entcnt;
+ return;
+ }
- for (i = 0; i < linec; i++) {
- linei = (linesel + 1 + i) % linec;
- line = bp = readline(line, linei);
- end = line + linesize(linei);
+ for (i = 0; i < entcnt; i++) {
+ linei = (entsel + 1 + i) % entcnt;
+ line = bp = readent(line, linei);
+ end = line + entlen(linei);
while (end - bp && (bp = memchr(bp, searchbuf[0], end - bp))) {
if (!memcmp(bp, searchbuf, MIN(end - bp, searchc))) {
- linesel = linei;
+ entsel = linei;
goto exit;
}
bp += 1;
@@ -189,7 +213,7 @@ exit:
free(line);
}
-void
+int
run()
{
struct termios prevterm, newterm;
@@ -199,98 +223,97 @@ run()
char *tok, iobuf[1024], *line = NULL;
int c, termw;
- linecap = 100;
- lines = checkp(calloc(linecap, sizeof(size_t)));
+ entcap = 100;
+ entries = checkp(calloc(entcap, sizeof(size_t)));
if (!userfile) {
if (!(f = tmpfile()))
die("Failed to create temporary file\n");
- linec = start = pos = 0;
- while ((nread = fgetln(iobuf, sizeof(iobuf), stdin)) > 0) {
+ entcnt = start = pos = 0;
+ while ((nread = freadln(iobuf, sizeof(iobuf), stdin)) > 0) {
pos += nread;
if (fwrite(iobuf, 1, nread, f) != nread)
die("Writing to tmp file failed\n");
if (iobuf[nread-1] == '\n') {
- setent(linec++, start);
+ setent(entcnt++, start);
start = pos;
}
}
- setent(linec, pos);
+ setent(entcnt, pos);
fseek(f, 0, SEEK_SET);
if (!freopen("/dev/tty", "r", stdin))
die("Failed to reattach to pseudo tty\n");
+ if (fread(NULL, 0, 0, f) < 0) return EXIT_FAILURE;
} else {
if (!(f = fopen(userfile, "r")))
die("Failed to open file for reading: %s\n", userfile);
- linec = start = pos = 0;
- while ((nread = fgetln(iobuf, sizeof(iobuf), f)) > 0) {
+ entcnt = start = pos = 0;
+ while ((nread = freadln(iobuf, sizeof(iobuf), f)) > 0) {
pos += nread;
if (iobuf[nread-1] == '\n') {
- setent(linec++, start);
+ setent(entcnt++, start);
start = pos;
}
}
- setent(linec, pos);
+ setent(entcnt, pos);
fseek(f, 0, SEEK_SET);
}
- if (!linec) return;
+ if (!entcnt) return EXIT_SUCCESS;
if (tcgetattr(fileno(stdin), &prevterm))
- die("Failed to get terminal properies\n");
+ die("Failed to get term attrs\n");
cfmakeraw(&newterm);
if (tcsetattr(fileno(stdin), TCSANOW, &newterm))
- die("Failed to set new terminal properties\n");
+ die("Failed to set term attrs\n");
termw = (ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) != -1) ? ws.ws_col : 80;
fprintf(stderr, "%s", CSI_HIDECUR);
- linesel = 0;
+ entsel = 0;
do {
if (mode == MODE_BROWSE) {
- line = readline(line, linesel);
+ line = readent(line, entsel);
fprintf(stderr, "%s%s%.*s\r", CSI_CLEARLINE,
prompts[mode], termw - (int) strlen(prompts[mode]),
line);
} else if (mode == MODE_SEARCH) {
- line = readline(line, linesel);
+ line = readent(line, entsel);
fprintf(stderr, "%s%s%.*s: %.*s\r", CSI_CLEARLINE,
prompts[mode], (int) searchc, searchbuf,
(int) (termw - strlen(prompts[mode]) - searchc),
line);
}
- c = getc(stdin);
- if (c == 0x1b) c = readcode(stdin);
- switch (c) {
+ switch ((c = readkey(stdin))) {
case 0x03: /* CTRL+C */
goto exit;
case 0x13: /* CTRL+S */
- if (mode != MODE_SEARCH) {
- mode = MODE_SEARCH;
- search_selnext();
- }
+ mode = MODE_SEARCH;
+ search_selnext();
break;
case 0x02: /* CTRL+B */
mode = MODE_BROWSE;
break;
- case '\r':
- line = readline(line, linesel);
- printf("%.*s", (int) linesize(linesel), line);
- goto exit;
case CODE_UP:
- if (linesel != 0) linesel--;
+ mode = MODE_BROWSE;
+ if (entsel != 0) entsel--;
break;
case CODE_DOWN:
- if (linesel != linec - 1) linesel++;
+ mode = MODE_BROWSE;
+ if (entsel != entcnt - 1) entsel++;
break;
+ case '\r': /* NEWLINE */
+ line = readent(line, entsel);
+ printf("%.*s\n", (int) entlen(entsel), line);
+ if (!multiout) goto exit;
default:
if (mode == MODE_SEARCH) {
search_handlekey(c);
@@ -305,17 +328,8 @@ exit:
tcsetattr(fileno(stdin), TCSANOW, &prevterm);
fclose(f);
-}
-
-ssize_t
-fgetln(char *buf, size_t size, FILE *f)
-{
- size_t i = 0;
-
- for (i = 0; i < size && (buf[i] = fgetc(f)) >= 0; i++)
- if (buf[i] == '\n') return i + 1;
- return (buf[i] < 0) ? -1 : i;
+ return EXIT_SUCCESS;
}
int
@@ -323,6 +337,12 @@ handleopt(const char *flag, const char **args)
{
if (flag[0] && flag[1]) die("Unsupported flag: -%s\n", flag);
+ switch (flag[0]) {
+ case 'm':
+ multiout = 1;
+ break;
+ }
+
return 0;
}
@@ -341,6 +361,5 @@ main(int argc, const char **argv)
}
}
- run();
+ return run();
}
-