From bdd6108e6163c8708719e411cf56c8a504f43cf4 Mon Sep 17 00:00:00 2001 From: nat Date: Sun, 24 May 2020 16:44:19 +0000 Subject: Diffbreaker a utility for manipulating unified diffs interactively with curses(3). --- devel/Makefile | 3 +- devel/diffbreaker/DESCR | 2 + devel/diffbreaker/Makefile | 46 ++ devel/diffbreaker/PLIST | 3 + devel/diffbreaker/files/diffbreaker/Makefile | 9 + devel/diffbreaker/files/diffbreaker/diffbreaker.1 | 96 +++ devel/diffbreaker/files/diffbreaker/diffbreaker.c | 683 ++++++++++++++++++++++ 7 files changed, 841 insertions(+), 1 deletion(-) create mode 100644 devel/diffbreaker/DESCR create mode 100644 devel/diffbreaker/Makefile create mode 100644 devel/diffbreaker/PLIST create mode 100644 devel/diffbreaker/files/diffbreaker/Makefile create mode 100644 devel/diffbreaker/files/diffbreaker/diffbreaker.1 create mode 100644 devel/diffbreaker/files/diffbreaker/diffbreaker.c (limited to 'devel') diff --git a/devel/Makefile b/devel/Makefile index 1ca141c3c55..a6c7cc090af 100644 --- a/devel/Makefile +++ b/devel/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.3134 2020/05/23 08:19:22 adam Exp $ +# $NetBSD: Makefile,v 1.3135 2020/05/24 16:44:19 nat Exp $ # COMMENT= Development utilities @@ -264,6 +264,7 @@ SUBDIR+= devIL SUBDIR+= devhelp SUBDIR+= device-driver-doc-de SUBDIR+= dia2code +SUBDIR+= diffbreaker SUBDIR+= diffuse SUBDIR+= diffutils SUBDIR+= distcc diff --git a/devel/diffbreaker/DESCR b/devel/diffbreaker/DESCR new file mode 100644 index 00000000000..8b527f56b0a --- /dev/null +++ b/devel/diffbreaker/DESCR @@ -0,0 +1,2 @@ +Diffbreaker allows the user to create incremental patches +from a single unified diff interactively using curses. diff --git a/devel/diffbreaker/Makefile b/devel/diffbreaker/Makefile new file mode 100644 index 00000000000..bc7efeaac83 --- /dev/null +++ b/devel/diffbreaker/Makefile @@ -0,0 +1,46 @@ +# $NetBSD: Makefile,v 1.1 2020/05/24 16:44:20 nat Exp $ + +PKGNAME= diffbreaker-0.1 +#PKGREVISION= 1 +CATEGORIES= devel + +MAINTAINER= nat@NetBSD.org +COMMENT= Tool to manuipulate unified diffs using curses +LICENSE= 2-clause-bsd + +NO_CONFIGURE= yes + +USE_LANGUAGES= c +USE_TOOLS= make + +.include "../../mk/bsd.prefs.mk" + +BUILD_DEFS+= MANINSTALL + +INSTALLATION_DIRS= bin +.if !empty(MANINSTALL:Mcatinstall) +INSTALLATION_DIRS+= ${PKGMANDIR}/cat1 +.endif +.if !empty(MANINSTALL:Mmaninstall) +INSTALLATION_DIRS+= ${PKGMANDIR}/man1 +.endif + +pre-build: + ${CP} -R ${FILESDIR}/diffbreaker ${WRKSRC} + +do-install: +.for f in diffbreaker + ${INSTALL_SCRIPT} ${WRKSRC}/${f} ${DESTDIR}${PREFIX}/bin +. if !empty(MANINSTALL:Mcatinstall) +. if defined(CATMAN_SECTION_SUFFIX) && !empty(CATMAN_SECTION_SUFFIX:M[Yy][Ee][Ss]) + ${INSTALL_MAN} ${WRKSRC}/${f}.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1/${f}.1 +. else + ${INSTALL_MAN} ${WRKSRC}/${f}.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1 +. endif +. endif +. if !empty(MANINSTALL:Mmaninstall) + ${INSTALL_MAN} ${WRKSRC}/${f}.1 ${DESTDIR}${PREFIX}/${PKGMANDIR}/man1 +. endif +.endfor + +.include "../../mk/bsd.pkg.mk" diff --git a/devel/diffbreaker/PLIST b/devel/diffbreaker/PLIST new file mode 100644 index 00000000000..0e486e510ea --- /dev/null +++ b/devel/diffbreaker/PLIST @@ -0,0 +1,3 @@ +@comment $NetBSD: PLIST,v 1.1 2020/05/24 16:44:20 nat Exp $ +bin/diffbreaker +man/man1/diffbreaker.1 diff --git a/devel/diffbreaker/files/diffbreaker/Makefile b/devel/diffbreaker/files/diffbreaker/Makefile new file mode 100644 index 00000000000..a05ba67aa21 --- /dev/null +++ b/devel/diffbreaker/files/diffbreaker/Makefile @@ -0,0 +1,9 @@ +# $NetBSD: Makefile,v 1.1 2020/05/24 16:44:20 nat Exp $ + +PROG= diffbreaker +MAN= diffbreaker.1 +DPADD= ${LIBCURSES} ${LIBTERMINFO} +LDADD= -lcurses -lterminfo + +WARNS?= 6 +.include diff --git a/devel/diffbreaker/files/diffbreaker/diffbreaker.1 b/devel/diffbreaker/files/diffbreaker/diffbreaker.1 new file mode 100644 index 00000000000..f4f31bc9d1d --- /dev/null +++ b/devel/diffbreaker/files/diffbreaker/diffbreaker.1 @@ -0,0 +1,96 @@ +.\" $NetBSD: diffbreaker.1,v 1.1 2020/05/24 16:44:20 nat Exp $ +.\" +.\" Copyright (c) 2020 Nathanial Sloss +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd April 10, 2020 +.Dt DIFFBREAKER 1 +.Os +.Sh NAME +.Nm diffbreaker +.Nd unified diff cherry picker / patch set editor +.Sh SYNOPSIS +.Nm +.Op Fl s +.Fl i Ar input file +.Fl o Ar output file +.Sh DESCRIPTION +The +.Nm +command allows the user to create incremental patches from a single unified diff +interactively using +.Xr curses 3 . +.Bl -tag -indent width +.It Fl i Ar input file +Unified diff input file. +.It Fl o Ar output file / beginning of file path. +Output location / file. +A file name of "-" means to write to stderr, useful for redirecting the output. +.It Op Fl s +If the +.Op Fl s +switch is given the output file argument is a prefix and path for files to be +output. +Files are written from output file.1.diff etc. +.PP +If no +.Op Fl s +switch is +.Em not +given the output file is appended to on each subsequent +write. +.El +.Sh KEYS +.Nm +accepts the following keys: +.Bl -tag -indent width +.It [SPACE] +Select / Un-select change. +.It [l] +Redraw the current screen. +.It [j] +Move down 1 line. +.It [k] +Move up 1 line. +.It [G] +Move to the beginning of the diff. +.It [g] +Move to the end of the diff. +.It [w] +Write changes to output file(s). +Clearing sections from the screen in which all changes within a block or file +have been written and return to the top of the diff. +.It [q] +Quit the program, +.Em DISCARDING +any unsaved changes. +.Sh STATUS LINE +At the bottom of the screen the number of unwritten lines in the buffer is +displayed. +.Sh SEE ALSO +.Xr curses 3 +.Xr diff 1 +.Xr patch 1 +.Sh AUTHORS +Nathanial Sloss diff --git a/devel/diffbreaker/files/diffbreaker/diffbreaker.c b/devel/diffbreaker/files/diffbreaker/diffbreaker.c new file mode 100644 index 00000000000..59db98862d0 --- /dev/null +++ b/devel/diffbreaker/files/diffbreaker/diffbreaker.c @@ -0,0 +1,683 @@ +/* $NetBSD: diffbreaker.c,v 1.1 2020/05/24 16:44:20 nat Exp $ */ + +/*- + * Copyright (c) 2018, 2019 Nathanial Sloss + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ssize_t finalize_context(ssize_t context, ssize_t current, ssize_t secthead, + ssize_t first, ssize_t part, ssize_t origoffs, + ssize_t newoffs, ssize_t last, ssize_t pos); +ssize_t update_context(ssize_t lines, ssize_t current, ssize_t last); +ssize_t get_context(ssize_t current, ssize_t last, ssize_t num); +void print_buffer(ssize_t myLine, ssize_t dispLines); +void parse_buffer(char *outfile, bool incremental, uint32_t filesuffix); +void read_data_to_buffer(char *myFile); +void free_buffers_actions(void); +void setup_screen(void); +void mark_dirty(void); +#ifndef __dead +#define __dead __attribute__((__noreturn__)) +#endif +#ifdef __linux__ +extern char *__progname; +#define getprogname() __progname +#endif + +__dead static void usage(void); + +int dispLine, promptLine, scrcols, scrlines; +int displayLines; +WINDOW *mywin = NULL; +static char *buffer; +static char *newbuffer; +static char *action; +static char *newaction; +static ssize_t currentLine, totalLines, cpl; + +#define ORIGBUF(x) (buffer + ((x) * cpl)) +#define NEWBUF(x) (newbuffer + ((x) * cpl)) + +#define COLORTEXT(x) \ + do { \ + if (has_colors()) \ + attrset(COLOR_PAIR(x)); \ + else \ + attrset(A_REVERSE); \ + } while (0) + +#define NORMALTEXT \ + do { \ + if (has_colors()) \ + attrset(COLOR_PAIR(1)); \ + else \ + attrset(A_NORMAL); \ + } while (0) +void +mark_dirty(void) +{ + bool writetome = false, display = false; + bool pending = false, writesect = false; + ssize_t i, j = 0, last = 0, myfile = 0; + + j = 0; + for (i = 0; i < totalLines; i++) { + switch (action[i]) { + case 2: /* Selected */ + if (*ORIGBUF(i) == '-') { + continue; + } + if (*ORIGBUF(i) == '+') { + if (j != i) + strcpy(ORIGBUF(j), ORIGBUF(i)); + *ORIGBUF(j) = ' '; + action[j] = 0; + } + break; + case 5: /* @@ marker */ + if (pending == false && writesect == false) + j = last; + last = j; + pending = false; + writesect = false; + action[j] = action[i]; + if (j != i) + strcpy(ORIGBUF(j), ORIGBUF(i)); + break; + case 6: /* --- */ + if (pending == false && writesect == false) + j = last; + if (writetome == false) + j = myfile; + myfile = j; + pending = true; + writetome = false; + writesect = true; + if (j != i) + strcpy(ORIGBUF(j), ORIGBUF(i)); + action[j] = action[i]; + break; + case 7: /* +++ */ + if (j != i) + strcpy(ORIGBUF(j), ORIGBUF(i)); + action[j] = action[i]; + break; + case 1: /* unselected change */ + display = true; + writesect = true; + writetome = true; + default: + if (j != i) + strcpy(ORIGBUF(j), ORIGBUF(i)); + action[j] = action[i]; + break; + } + j++; + } + totalLines = display ? j-- : 0; + + return; +} + +ssize_t +update_context(ssize_t lines, ssize_t current, ssize_t last) +{ + ssize_t j, l = 0; + j = current; + while (lines > 0) { + if (*ORIGBUF(last + l) == '+') { + l++; + continue; + } + sprintf(NEWBUF(j), "%s", ORIGBUF(last + l++)); + *NEWBUF(j++) = ' '; + if (last + l > totalLines) + break; + lines--; + } + + return j; +} + +ssize_t +get_context(ssize_t current, ssize_t last, ssize_t num) +{ + ssize_t context = 0, tmpcontext = 0, i, j, l; + + i = current - 1; + j = last; + + for (l = 0; tmpcontext < num; l++) { + if ((l + i) > totalLines) + break; + if (i - l >= 0) + context++; + if (action[i - l] == 2) + goto next; + if (action[i - l] != 6 && *ORIGBUF(i - l) == '-') { + tmpcontext++; + continue; + } + if (*ORIGBUF(i - l) == ' ') { + tmpcontext++; + continue; + } +next: + if (context == tmpcontext) { + j = update_context(tmpcontext, j, i - context - 1); + tmpcontext = 0; + num -= tmpcontext; + } + if (action[i - l] == 6 || action[i - l] == 7) + break; + if (action[i - l] == 2) + break; + } + l--; + if (tmpcontext) + j = update_context(tmpcontext, j, i - l); + + return j; +} + +ssize_t +finalize_context(ssize_t context, ssize_t current, ssize_t secthead, + ssize_t first, ssize_t part, ssize_t origoffs, + ssize_t newoffs, ssize_t last, ssize_t pos) +{ + ssize_t blanks, orig, addition, l; + ssize_t fixoffs, j, begblanks; + bool firstf; + + fixoffs = secthead; + j = current; + + firstf = false; + begblanks = 0; + j = update_context(context, j, last); + blanks = orig = addition = 0; + for (l = secthead + 1; l < j; l++) { + if (*NEWBUF(l) == ' ') { + if (!firstf) + begblanks++; + blanks++; + } + if (*NEWBUF(l) == '-') { + firstf = true; + orig++; + } + if (*NEWBUF(l) == '+') { + firstf = true; + addition++; + } + } + sprintf(NEWBUF(fixoffs), "@@ %ld,%ld +%ld,%ld @@\n", + origoffs - first + part + (begblanks - context), + orig + blanks, newoffs + + first - part - (begblanks - context), addition + blanks); + + newaction[secthead] = action[pos]; + + return j; +} + +void +parse_buffer(char *outfile, bool incremental, uint32_t filesuffix) +{ + ssize_t origoffs = 0, newoffs = 0, first = 0, last = 0, part = 0; + ssize_t final = 0, context = 0, fixoffs = 0, i, j, adj; + bool found = false, writecount = false; + char tmpstr[100], tmpstr1[100]; + FILE *myfile = NULL; + + j = 0; + for (i = 0; i < totalLines; i++) { + switch (action[i]) { + case 6: /* --- */ + if (found == true) { + j = finalize_context(context, j, fixoffs, first, + part, origoffs, newoffs, last, i); + final = j; + last = i; + found = false; + } + first = 0; + if (writecount == false) + j = final; + newaction[j] = action[i]; + sprintf(NEWBUF(j++), "%s", ORIGBUF(i)); + break; + case 5: /* @@ */ + if (found == true) { + j = finalize_context(context, j, fixoffs, first, + part, origoffs, newoffs, last, i); + final = j; + last = i; + found = false; + } + first = 0; + part = 0; + fixoffs = j; + + // XXX: this was uninitialized according to valgrind + // check the sscanf return? + tmpstr[0] = '\0'; + tmpstr1[0] = '\0'; + sscanf(ORIGBUF(i), "@@ %s %s\n", tmpstr, tmpstr1); + char *rest = NULL; + origoffs = strtol(tmpstr, &rest, 10); + rest++; + (void)strtol(rest, &rest, 10); + newoffs = strtol(tmpstr1, &rest, 10); + rest++; + //(void)strtol(rest, &rest, 10); + break; + case 1: /* unselected change */ + if (part == 0) + part = i; + if (part && !found && *ORIGBUF(i) == '+') + part++; + break; + case 2: /* selected */ + adj = 0; + if (!found) { + writecount = true; + context = 0; + first = i; + last = i; + j++; + adj = 3; + if (part == 0) + part = i; + + found = true; + } + j = get_context(i, j, i - last + adj); + sprintf(NEWBUF(j++), "%s", ORIGBUF(i)); + last = i; + if (*ORIGBUF(i) == '-') + last++; + final = j; + context = 3; + break; + case 7: + case 4: + writecount = false; + newaction[j] = action[i]; + sprintf(NEWBUF(j++), "%s", ORIGBUF(i)); + default: + break; + } + } + if (context && found) + j = finalize_context(context, j, fixoffs, first, + part, origoffs, newoffs, last, i); + + if (writecount == false && found == false) + j = final; + + char tmppath [512]; + if (incremental) + snprintf(tmppath, sizeof(tmppath), "%s.%d.diff", outfile, + filesuffix); + else + snprintf(tmppath, sizeof(tmppath), "%s", outfile); + + if (!strcmp(tmppath, "-")) + myfile = stderr; + else if ((myfile = fopen(tmppath, "a")) == NULL) { + free_buffers_actions(); + errx(errno, "Could not create/open file(s) for writing."); + /* Not reached */ + } + for (i = 0; i < j; i++) + fprintf(myfile, "%s", NEWBUF(i)); + fclose(myfile); + + return; +} + +void +free_buffers_actions(void) +{ + free(buffer); + free(newbuffer); + free(newaction); + free(action); + + buffer = NULL; + newbuffer = NULL; + newaction = NULL; + action = NULL; + +} + +void +read_data_to_buffer(char *myFile) +{ + char data, line[512], myaction = 0; + ssize_t nr; + ssize_t l = 0, j = 0, n = 0; + int fd, i; + + if ((fd = open(myFile, O_RDONLY)) < 0) + errx(errno, "Error Opening file %s.", myFile); + + memset(line, 0, sizeof(line)); + i = 0; + cpl = 0; + while ((nr = read(fd, line, sizeof(line))) > 0) { + for (i = 0; i < nr; i++) { + j++; + if (line[i] == '\n') { + n++; + if (j > cpl) + cpl = j; + j = 0; + } + } + } + l = n--; + cpl--; + + size_t totalalloc = (size_t)(l * cpl); + if (totalalloc <= 0 || l <= 0) + errx(EXIT_FAILURE, "File mem calc error."); + + if ((newaction = calloc((size_t)l, sizeof(*newaction))) == NULL) + errx(errno, "File mem alloc error."); + if ((action = calloc((size_t)l, sizeof(*action))) == NULL) { + free(newaction); + errx(errno, "File mem alloc error."); + } + if ((buffer = calloc(totalalloc, sizeof(*buffer))) == NULL) { + free(action); + free(newaction); + errx(errno, "File mem alloc error."); + } + if ((newbuffer = calloc(totalalloc, sizeof(*newbuffer))) == NULL) { + free(buffer); + free(action); + free(newaction); + errx(errno, "File mem alloc error."); + } + memset(newaction, 0, (size_t)l * sizeof(*newaction)); + memset(action, 0, (size_t)l * sizeof(*action)); + + l = 0; + j = n = 0; + lseek(fd, 0, SEEK_SET); + while ((nr = read(fd, line, sizeof(line))) > 0) { + for (i = 0; i < nr; i++) { + data = line[i]; + l++; + *(ORIGBUF(j) + n++) = data; + if (l == sizeof(line)) { + l = 0; + n = 0; + j++; + continue; + } + if (data == '\n') { + myaction = 0; + if (*ORIGBUF(j) == '-' && *(ORIGBUF(j) + 1) == + '-' && *(ORIGBUF(j) + 2) == '-') + myaction = 6; + else if (*ORIGBUF(j) == '+' && *(ORIGBUF(j) + 1) == + '+' && *(ORIGBUF(j) + 2) == '+') + myaction = 7; + else if (*ORIGBUF(j) == '+' && myaction != 7) + myaction = 1; + else if (*ORIGBUF(j) == '-' && myaction != 6) + myaction = 1; + else if (*ORIGBUF(j) == '@' && *(ORIGBUF(j) + 1) == + '@') + myaction = 5; + else if (*ORIGBUF(j) != ' ') + myaction = 4; + action[j] = myaction; + if (action[j] != 4) + j++; + n = 0; + l = 0; + } + } + } + + totalLines = j--; + + close(fd); + + return; +} + +void +print_buffer(ssize_t myLine, ssize_t dispLines) +{ + static char tmpline[512]; + ssize_t i, m, startLine; + int j = 0; + + startLine = (myLine / dispLines) * dispLines; + move (0, 0); + for (i = startLine; i < (startLine + dispLines) && i < totalLines; + i++) { + NORMALTEXT; + if (action[i] == 2 && i == myLine) + COLORTEXT(4); + else if (i == myLine) + COLORTEXT(2); + else if (action[i] == 2) + COLORTEXT(5); + else if (action[i] == 4) + COLORTEXT(5); + else if (action[i] == 5) + COLORTEXT(3); + else if (action[i] == 6 || action[i] == 7) + COLORTEXT(3); + if (action[i] != 9) { + snprintf(tmpline, sizeof(tmpline), "%s", ORIGBUF(i)); + int p = 0; + ssize_t llen = (ssize_t)strlen(tmpline); + char tmpstr[1024]; + for (m = 0; m < llen; m++) { + if ((tmpline[m] < ' ') && (tmpline[m] != '\t') + && (tmpline[m] != '\n')) { + snprintf(tmpstr+p, (size_t)(1024 - p), "%s", + unctrl(tmpline[m])); + p += (int)strlen(unctrl(tmpline[m])) - 1; + } else if (tmpline[m] == '\t') { + snprintf(tmpstr+p, (size_t)(1024 - p), " "); + p += 3; + } else + snprintf(tmpstr+p, (size_t)(1024 - p), "%c", tmpline[m]); + p++; + } + p = 0; + llen = (ssize_t)strlen(tmpstr); + for (m = 0; m < llen && p < (scrcols - 1); m++) + mvprintw(j, p++, "%c", tmpstr[m]); + j++; + } + } + NORMALTEXT; + for (; i < startLine + dispLines; i++) { + mvprintw(j, 0, "\n"); + j++; + } + + COLORTEXT(2); + mvprintw(promptLine, 0, "%ld lines remaining", totalLines); + + refresh(); + return; +} + +void +usage(void) +{ + fprintf(stderr, "Usage: %s [-s] -i infile -o outpath/file\n", + getprogname()); + + exit(EXIT_FAILURE); + /* Not reached */ +} + +void +setup_screen(void) +{ + if (!(mywin = initscr())) { + free_buffers_actions(); + errx(EXIT_FAILURE, "\nUnknown terminal type."); + } + + scrlines = LINES; + scrcols = COLS; + + if (scrlines <= 0 || scrcols <= 0) { + delwin(mywin); + endwin(); + + mywin = NULL; + free_buffers_actions(); + errx(EXIT_FAILURE, "\nUnknown screen dimensions."); + } + promptLine = scrlines - 1; + displayLines = scrlines - 2; + if (has_colors()) { + start_color(); + + init_pair(1, COLOR_WHITE, COLOR_BLACK); + init_pair(2, COLOR_BLACK, COLOR_WHITE); + init_pair(3, COLOR_WHITE, COLOR_BLUE); + init_pair(4, COLOR_WHITE, COLOR_YELLOW); + init_pair(5, COLOR_WHITE, COLOR_GREEN); + init_pair(6, COLOR_WHITE, COLOR_RED); + + NORMALTEXT; + } + +} + +int +main(int argc, char *argv[]) +{ + char *infile = NULL, *outfile = NULL; + bool incremental = false; + uint32_t filesuffix = 0; + int ch; + char myKey; + + dispLine = 0; + currentLine = 0; + + while ((ch = getopt(argc, argv, "si:o:")) != EOF) { + switch (ch) { + case 's': + incremental = true; + break; + case 'i': + infile = (char *)(optarg); + break; + case 'o': + outfile = (char *)(optarg); + break; + default: + usage(); + /* Not reached */ + } + } + argc -= optind; + argv += optind; + + if (infile == NULL || outfile == NULL) { + usage(); + /* Not reached */ + } + + read_data_to_buffer(infile); + + setup_screen(); + mark_dirty(); + print_buffer(currentLine, (size_t)(displayLines + 1)); + COLORTEXT(2); + + for (;;) { + myKey = (char)getch(); + if (myKey == 'q') + break; + if (myKey == 'k' && currentLine > 0) + currentLine--; + if (myKey == ' ') { + if (action[currentLine] == 1) + action[currentLine] = 2; + else if (action[currentLine] == 2) + action[currentLine] = 1; + if (currentLine < totalLines -1) + currentLine++; + } + if (myKey == 'j' && currentLine < totalLines - 1) + currentLine++; + if (myKey == 'G') + currentLine = totalLines - 1; + if (myKey == 'g') + currentLine = 0; + if (myKey == 'l') { + if (is_term_resized(LINES, COLS)) { + resizeterm(LINES, COLS); + scrcols = COLS; + scrlines = LINES; + promptLine = scrlines - 1; + displayLines = scrlines - 2; + } + } + if (myKey == 'w') { + currentLine = 0; + parse_buffer(outfile, incremental, ++filesuffix); + mark_dirty(); + if (totalLines <= 0) + break; + } + print_buffer(currentLine, (size_t)(displayLines + 1)); + } + + delwin(mywin); + endwin(); + + free_buffers_actions(); + mywin = NULL; + + return EXIT_SUCCESS; +} -- cgit v1.2.3