commit 9787d16a53436f6c7bfeb54b03dd2b695981fa70
parent 54266ea5cdefc0a6f43401991033d6de035599ac
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date: Sat, 19 Dec 2020 13:20:34 -0800
Add proper argument evaluation
This simplifies everything and allows easy reuse with other commands.
The `g` command actually works now too.
Diffstat:
M | main.c | | | 133 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
1 file changed, 70 insertions(+), 63 deletions(-)
diff --git a/main.c b/main.c
@@ -30,6 +30,8 @@
#define LEN(X) (sizeof(X) / sizeof(*X))
#define PROTO_MAX 16
#define BUFSIZE 4096
+#define ARGV_MAX 16
+#define ARG_SEP ":\t "
static char *format_prog = "gophmt"; /* not released, costom formatter */
@@ -84,16 +86,14 @@ connect_to(const char *host, const char *proto)
return s;
}
-char *
+int
input(char *buf, int size, const char *prompt, FILE *fp)
{
int len;
- char *r;
fputs(prompt, stdout);
- r = fgets(buf, size, fp);
- if (r == NULL)
- return NULL;
+ if (fgets(buf, size, fp) == NULL)
+ return 1;
len = strlen(buf);
if (len >= size && buf[size - 1] != '\n')
@@ -101,7 +101,7 @@ input(char *buf, int size, const char *prompt, FILE *fp)
else if (len > 0)
buf[len - 1] = '\0';
- return r;
+ return 0;
}
int
@@ -134,33 +134,21 @@ newpath(char *path, char *newpath)
}
}
-void
-gawkparse(char *cmd, char *host, char *path, char *port)
+int
+argsplit(char **argv, int arg_max, char *s, const char *sep)
{
- int i;
- char *parts[3];
- char *nhost, *npath, *nport;
-
- nhost = host;
- npath = path;
- nport = port;
+ int argc;
- for (i = 0; i < 3; ++i)
- parts[i] = strsep(&cmd, ":");
-
- if (parts[1] == NULL) {
- if (parts[0] != NULL)
- npath = parts[0];
- } else {
- if (parts[2] != NULL)
- nport = parts[2];
- nhost = parts[0];
- npath = parts[1];
+ for (argc = 0; argc < arg_max &&
+ (argv[argc] = strsep(&s, sep)) != NULL;) {
+ if (*argv[argc] != '\0')
+ ++argc;
}
- strlcpy(host, nhost, HOST_NAME_MAX);
- newpath(path, npath);
- strlcpy(port, nport, PROTO_MAX);
+ if (argc == arg_max &&
+ argv[argc - 1][strcspn(argv[argc - 1], sep)] == '\0')
+ return -1;
+ return argc;
}
/* NOTE: implement caching */
@@ -235,14 +223,12 @@ gawkat(int sock, const char *path)
int
gawk(int sock, int depth, const char *host, const char *path, const char *port)
{
- int done;
- char cbuf[PATH_MAX + HOST_NAME_MAX + PROTO_MAX];
- char *cmd;
- int closeit;
- char npath[PATH_MAX];
- char nhost[HOST_NAME_MAX];
- char nport[PROTO_MAX];
+ char *argv[ARGV_MAX];
+ char inbuf[PATH_MAX + HOST_NAME_MAX + PROTO_MAX];
char prompt[64]; /* you wouldn't want it longer anyway */
+ const char *nreq[3];
+ int argc;
+ int closeit, done, newsock;
++depth;
@@ -258,52 +244,73 @@ gawk(int sock, int depth, const char *host, const char *path, const char *port)
snprintf(prompt, sizeof(prompt), "[%s] %s ", host, path);
done = 0;
- while (!done && (cmd = input(cbuf, sizeof(cbuf), prompt, stdin))) {
- /* `strcpy(cmd, "p")` works I suppose, but I like
- * goto and it's more efficient. */
- if (*cmd == '\0')
- goto gawk_at;
+ while (!done && input(inbuf, sizeof(inbuf), prompt, stdin) == 0) {
+ argc = argsplit(argv, LEN(argv), inbuf, ARG_SEP);
+ if (argc <= 0) {
+ if (argc < 0)
+ warn("Too many arguments");
+ continue;
+ }
- switch (*cmd++) {
+ if (strlen(*argv) > 1)
+ goto invalid_input;
+ switch (**argv) {
case 'q': /* quit */
+ if (argc > 1)
+ goto invalid_input;
done = depth;
break;
case 'p': /* print */
-gawk_at:
puts("gawking");
/* NOTE: SIGPIPE on second call.
* gawkat(sock, path); */
break;
case 'b': /* back */
- if (*cmd == '\0')
+ if (argc > 2)
+ goto invalid_input;
+ if (argc == 1)
done = 1;
- else {
- done = strtoui(cmd);
- if (done < 0) {
- warnx("invalid argument for 'b', '%s'", cmd);
- done = 0;
- }
- }
+ else if (argc == 2)
+ done = strtoui(argv[1]);
break;
case 'g': /* goto or gawk */
- if (*cmd == '\0') {
- warnx("'g': No arguments.");
- break;
+ if (argc > 4)
+ goto invalid_input;
+
+ newsock = 0;
+ nreq[0] = host;
+ nreq[1] = path;
+ nreq[2] = port;
+
+ /* NOTE: relative path's not implemented */
+ if (argc == 1)
+ nreq[1] = "/";
+ else if (argc == 2)
+ nreq[1]= argv[1];
+ else {
+ nreq[0] = argv[1];
+ nreq[1] = argv[2];
+ if (strcmp(host, nreq[0]) != 0)
+ newsock = -1;
+ if (argc == 3) {
+ nreq[2] = argv[3];
+ if (!newsock && strcmp(port, nreq[2]) != 0)
+ newsock = -1;
+ }
}
- gawkparse(cmd, nhost, npath, nport);
- if (strcmp(host, nhost) != 0 || strcmp(port, nport) != 0)
- done = gawk(-1, depth, nhost, npath, nport);
- else
- done = gawk(sock, depth, nhost, npath, nport);
+
+ if (!newsock)
+ newsock = sock;
+ done = gawk(newsock, depth, nreq[0], nreq[1], nreq[2]);
break;
default:
- warnx("invalid command '%c'", *--cmd);
+invalid_input:
+ warnc(EINVAL, "invalid command or arguments for '%s'", argv[0]);
}
}
- if (closeit)
- if (close(sock) == -1)
- warn("unable to disconnect");
+ if (closeit && close(sock) == -1)
+ warn("unable to disconnect from '%s'", host);
if (ferror(stdin)) {
warn("'stdin'");
return -1;