commit 9f7d7167e8b3d62111fe8b928c3a41094c6d004c from: Stefan Sperling date: Sun Apr 29 11:45:53 2018 UTC add skeleton for tog(1) commit - 0c048b1581c5801a4fd5bf5b68d120bf8ed430a0 commit + 9f7d7167e8b3d62111fe8b928c3a41094c6d004c blob - /dev/null blob + 32ef4f60f86dd8444f47226580f56befe43bd4b9 (mode 644) --- /dev/null +++ tog/Makefile @@ -0,0 +1,27 @@ +.PATH:${.CURDIR}/../lib + +PROG= tog +SRCS= tog.c error.c + +CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib +LDADD = -lpanel -lcurses -lutil -lz +DPADD = ${LIBZ} ${LIBUTIL} +.if defined(PROFILE) +CC = gcc +CPPFLAGS += -DPROFILE +DEBUG = -O0 -pg +.else +DEBUG = -O0 -g +.endif +CFLAGS += -Werror -Wall -Wstrict-prototypes -Wunused-variable + +# For now, default to installing binary in ~/bin +GROUP!=id -g -n +install: + ${INSTALL} ${INSTALL_COPY} -o ${USER} -g ${GROUP} \ + -m ${BINMODE} ${PROG} ${HOME}/bin/${PROG} + +# Don't install man pages yet +NOMAN = Yes + +.include blob - /dev/null blob + a8f5dbd3311889f67f5115b5a71a36ad83b8779c (mode 644) --- /dev/null +++ tog/tog.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2018 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "got_error.h" + +#ifndef nitems +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + +enum tog_view_id { + TOG_VIEW_LOG, + TOG_VIEW_DIFF, + TOG_VIEW_BLAME, +}; + +struct tog_cmd { + const char *cmd_name; + const struct got_error *(*cmd_main)(int, char *[]); + void (*cmd_usage)(void); + enum tog_view_id view; + const char *cmd_descr; +}; + +__dead void usage(void); +__dead void usage_log(void); +__dead void usage_diff(void); +__dead void usage_blame(void); + +const struct got_error* cmd_log(int, char *[]); +const struct got_error* cmd_diff(int, char *[]); +const struct got_error* cmd_blame(int, char *[]); + +struct tog_cmd tog_commands[] = { + { "log", cmd_log, usage_log, TOG_VIEW_LOG, + "show repository history" }, + { "diff", cmd_diff, usage_diff, TOG_VIEW_DIFF, + "compare files and directories" }, + { "blame", cmd_blame, usage_blame, TOG_VIEW_BLAME, + "show line-by-line file history" }, +}; + +/* globals */ +enum tog_view_id tog_view_id; +WINDOW *tog_main_win; +PANEL *tog_main_panel; + +__dead void +usage_log(void) +{ + fprintf(stderr, "usage: %s log [repository-path]\n", + getprogname()); + exit(1); +} + +const struct got_error * +cmd_log(int argc, char *argv[]) +{ + return got_error(GOT_ERR_NOT_IMPL); +} + +__dead void +usage_diff(void) +{ + fprintf(stderr, "usage: %s diff [repository-path] object1 object2\n", + getprogname()); + exit(1); +} + +const struct got_error * +cmd_diff(int argc, char *argv[]) +{ + return got_error(GOT_ERR_NOT_IMPL); +} + +__dead void +usage_blame(void) +{ + fprintf(stderr, "usage: %s blame [repository-path] blob-object\n", + getprogname()); + exit(1); +} + +const struct got_error * +cmd_blame(int argc, char *argv[]) +{ + return got_error(GOT_ERR_NOT_IMPL); +} + +static const struct got_error * +init_curses(void) +{ + initscr(); + cbreak(); + noecho(); + nonl(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); + + tog_main_win = newwin(0, 0, 0, 0); + if (tog_main_win == NULL) + return got_error_from_errno(); + tog_main_panel = new_panel(tog_main_win); + if (tog_main_panel == NULL) + return got_error_from_errno(); + + return NULL; +} + +__dead void +usage(void) +{ + int i; + + fprintf(stderr, "usage: %s [-h] command [arg ...]\n\n" + "Available commands:\n", getprogname()); + for (i = 0; i < nitems(tog_commands); i++) { + struct tog_cmd *cmd = &tog_commands[i]; + fprintf(stderr, " %s: %s\n", cmd->cmd_name, cmd->cmd_descr); + } + exit(1); +} + +int +main(int argc, char *argv[]) +{ + const struct got_error *error = NULL; + struct tog_cmd *cmd = NULL; + int ch, hflag = 0; + + setlocale(LC_ALL, ""); + + while ((ch = getopt(argc, argv, "h")) != -1) { + switch (ch) { + case 'h': + hflag = 1; + break; + default: + usage(); + /* NOTREACHED */ + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc == 0) + cmd = &tog_commands[0]; + else { + int i; + + for (i = 0; i < nitems(tog_commands); i++) { + if (strncmp(tog_commands[i].cmd_name, argv[0], + strlen(argv[0])) == 0) { + cmd = &tog_commands[i]; + if (hflag) + tog_commands[i].cmd_usage(); + break; + } + } + if (cmd == NULL) { + fprintf(stderr, "%s: unknown command '%s'\n", + getprogname(), argv[0]); + return 1; + } + } + + error = init_curses(); + if (error) { + fprintf(stderr, "Cannot initialize ncurses: %s\n", error->msg); + return 1; + } + + error = cmd->cmd_main(argc, argv); + if (error) + goto done; +done: + endwin(); + if (error) + fprintf(stderr, "%s: %s\n", getprogname(), error->msg); + return 0; +}