commit 1a4256ef71ddba6c3cbb28861e0321184860653f
parent 9c7027fcbf86f3082bf0609a7784cc6f6cfa87c7
Author: Anselm R Garbe <anselm@garbe.us>
Date: Sat, 28 Nov 2009 12:16:35 +0000
merged kris' changes into mainstream sic
Diffstat:
M | LICENSE | | | 6 | +++--- |
M | config.mk | | | 2 | +- |
D | kris/Makefile | | | 2 | -- |
D | kris/config.mk | | | 2 | -- |
D | kris/sic.c | | | 215 | ------------------------------------------------------------------------------- |
D | kris/util.c | | | 86 | ------------------------------------------------------------------------------- |
M | sic.c | | | 308 | ++++++++++++++++++++++++++++++++++--------------------------------------------- |
A | util.c | | | 81 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
8 files changed, 218 insertions(+), 484 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -1,8 +1,8 @@
MIT/X Consortium License
-
-© 2005-2009 Anselm R Garbe <garbeam at gmail dot com>
-© 2008-2009 Jeroen Schot <schot at a-eskwadraat dot nl>
+© 2005-2009 Anselm R Garbe <anselm@garbe.us>
+© 2008-2009 Jeroen Schot <schot@a-eskwadraat.nl>
+© 2007-2009 Kris Maglione <maglione.k@gmail.com>
© 2005 Nico Golde <nico at ngolde dot de>
Permission is hereby granted, free of charge, to any person obtaining a
diff --git a/config.mk b/config.mk
@@ -1,5 +1,5 @@
# sic version
-VERSION = 1.0
+VERSION = 1.1
# Customize below to fit your system
diff --git a/kris/Makefile b/kris/Makefile
@@ -1 +0,0 @@
-../Makefile
-\ No newline at end of file
diff --git a/kris/config.mk b/kris/config.mk
@@ -1 +0,0 @@
-../config.mk
-\ No newline at end of file
diff --git a/kris/sic.c b/kris/sic.c
@@ -1,215 +0,0 @@
-/* ? 2005-2007 Anselm R. Garbe <garbeam at gmail dot com>
- * ? 2007 Kris Maglione <fbsdaemon@gmail.com>
- * ? 2005 Nico Golde <nico at ngolde dot de>
- * See LICENSE file for license details.
- */
-#include <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#define nil ((void*)0)
-typedef unsigned short ushort;
-
-#define PINGTIMEOUT 300
-
-static char* host = "irc.oftc.net";
-static char* port = "ircd";
-static char* password;
-static char nick[32];
-
-static char bufin[4096];
-static char bufout[4096];
-static char channel[256];
-static time_t trespond;
-static FILE *srv;
-
-#include "util.c"
-
-static void
-pout(char *channel, char *fmt, ...) {
- static char timestr[18];
- time_t t;
-
- va_buf(bufout, fmt);
-
- t = time(nil);
- strftime(timestr, sizeof timestr, "%D %R", localtime(&t));
- fprintf(stdout, "%-12s: %s %s\n", channel, timestr, bufout);
-}
-
-static void
-sout(char *fmt, ...) {
- va_buf(bufout, fmt);
- fprintf(srv, "%s\r\n", bufout);
-}
-
-static void
-privmsg(char *channel, char *msg) {
- if(channel[0] == '\0') {
- pout("", "No channel to send to");
- return;
- }
- pout(channel, "<%s> %s", nick, msg);
- sout("PRIVMSG %s :%s", channel, msg);
-}
-
-static void
-parsein(char *msg) {
- char *p;
- char c;
-
- if(msg[0] == '\0')
- return;
- msg = ctok(&msg, '\n');
- if(msg[0] != ':') {
- privmsg(channel, msg);
- return;
- }
- c = *++msg;
- if(!c || !isspace(msg[1]))
- sout("%s", msg);
- else {
- if(msg[1])
- msg += 2;
- switch(c) {
- case 'j':
- sout("JOIN %s", msg);
- if(channel[0] == '\0')
- strlcpy(channel, msg, sizeof channel);
- break;
- case 'l':
- p = tok(&msg);
- if(!*p)
- p = channel;
- if(!*msg)
- msg = "sic - 250 LOC are too much!";
- sout("PART %s :%s", p, msg);
- break;
- case 'm':
- p = tok(&msg);
- privmsg(p, msg);
- break;
- case 's':
- strlcpy(channel, msg, sizeof channel);
- break;
- default:
- sout("%c %s", c, msg);
- break;
- }
- }
-}
-
-static void
-parsesrv(char *msg) {
- char *cmd, *p, *usr, *txt;
-
- usr = host;
- if(!msg || !*msg)
- return;
- if(msg[0] == ':') {
- msg++;
- p = tok(&msg);
- if(!*msg)
- return;
- usr = ctok(&p, '!');
- }
- txt = ctok(&msg, '\r');
- msg = ctok(&txt, ':');
- cmd = tok(&msg);
- if(!strcmp("PONG", cmd))
- return;
- if(!strcmp("PRIVMSG", cmd))
- pout(msg, "<%s> %s", usr, txt);
- else if(!strcmp("PING", cmd))
- sout("PONG %s", txt);
- else {
- pout(usr, ">< %s: %s", cmd, txt);
- if(!strcmp("NICK", cmd) && !strcmp(usr, nick))
- strlcpy(nick, txt, sizeof nick);
- }
-}
-
-int
-main(int argc, char *argv[]) {
- int i, c;
- struct timeval tv;
- fd_set rd;
-
- strlcpy(nick, getenv("USER"), sizeof nick);
- for(i = 1; i < argc; i++) {
- c = argv[i][1];
- if(argv[i][0] != '-' || argv[i][2])
- c = -1;
- switch(c) {
- case 'h':
- if(++i < argc) host = argv[i];
- break;
- case 'p':
- if(++i < argc) port = argv[i];
- break;
- case 'n':
- if(++i < argc) strlcpy(nick, argv[i], sizeof nick);
- break;
- case 'k':
- if(++i < argc) password = argv[i];
- break;
- case 'v':
- eprint("sic-"VERSION", ©2005-2009 Kris Maglione, Anselm R. Garbe, Nico Golde\n");
- default:
- eprint("usage: sic [-h host] [-p port] [-n nick] [-k keyword] [-v]\n");
- }
- }
-
- /* init */
- i = dial(host, port);
- srv = fdopen(i, "r+");
-
- /* login */
- if(password)
- sout("PASS %s", password);
- sout("NICK %s", nick);
- sout("USER %s localhost %s :%s", nick, host, nick);
- fflush(srv);
-
- setbuf(stdout, nil);
- setbuf(srv, nil);
-
- for(;;) { /* main loop */
- FD_ZERO(&rd);
- FD_SET(0, &rd);
- FD_SET(fileno(srv), &rd);
- tv.tv_sec = 120;
- tv.tv_usec = 0;
- i = select(fileno(srv) + 1, &rd, 0, 0, &tv);
- if(i < 0) {
- if(errno == EINTR)
- continue;
- eprint("sic: error on select():");
- }
- else if(i == 0) {
- if(time(nil) - trespond >= PINGTIMEOUT)
- eprint("sic shutting down: parse timeout\n");
- sout("PING %s", host);
- continue;
- }
- if(FD_ISSET(fileno(srv), &rd)) {
- if(fgets(bufin, sizeof bufin, srv) == nil)
- eprint("sic: remote host closed connection\n");
- parsesrv(bufin);
- trespond = time(nil);
- }
- if(FD_ISSET(0, &rd)) {
- if(fgets(bufin, sizeof bufin, stdin) == nil)
- eprint("sic: broken pipe\n");
- parsein(bufin);
- }
- }
- return 0;
-}
-
-
diff --git a/kris/util.c b/kris/util.c
@@ -1,86 +0,0 @@
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-
-#define va_buf(buf, fmt) {\
- va_list ap; \
- va_start(ap, fmt); \
- vsnprintf(buf, sizeof buf, fmt, ap); \
- va_end(ap); \
-}
-
-static void
-eprint(const char *fmt, ...) {
-
- va_buf(bufout, fmt);
- fprintf(stderr, "%s", bufout);
-
- if(fmt[0] && fmt[strlen(fmt)-1] == ':')
- fprintf(stderr, " %s\n", strerror(errno));
- exit(1);
-}
-
-static int
-dial(char *host, char *port) {
- static struct addrinfo hints;
- struct addrinfo *res, *r;
- int srv;
-
- memset(&hints, 0, sizeof hints);
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- if(getaddrinfo(host, port, &hints, &res) != 0)
- eprint("error: cannot resolve hostname '%s':", host);
- for(r = res; r; r = r->ai_next) {
- if((srv = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1)
- continue;
- if(connect(srv, r->ai_addr, r->ai_addrlen) == 0)
- break;
- close(srv);
- }
- freeaddrinfo(res);
- if(!r)
- eprint("error: cannot connect to host '%s'\n", host);
- return srv;
-}
-
-#define strlcpy _strlcpy
-static void
-strlcpy(char *to, const char *from, int l) {
- memccpy(to, from, '\0', l);
- to[l-1] = '\0';
-}
-
-static void
-eat(char **s, int (*p)(int), int r) {
- char *q;
-
- for(q=*s; *q && p(*q) == r; q++)
- ;
- *s = q;
-}
-
-static char*
-tok(char **s) {
- char *p;
-
- eat(s, isspace, 1);
- p = *s;
- eat(s, isspace, 0);
- if(**s) *(*s)++ = '\0';
- return p;
-}
-
-static char*
-ctok(char **s, int c) {
- char *p, *q;
-
- q = *s;
- for(p=q; *p && *p != c; p++)
- ;
- if(*p) *p++ = '\0';
- *s = p;
- return q;
-}
-
-
diff --git a/sic.c b/sic.c
@@ -1,246 +1,204 @@
-/* See LICENSE file for license details. */
+ /* See LICENSE file for license details. */
+#include <ctype.h>
#include <errno.h>
-#include <netdb.h>
-#include <netinet/in.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#define PINGTIMEOUT 300
-#define MAXMSG 4096
-#ifndef VERSION
-#define VERSION "dev"
-#endif
-
-static void die(const char *errstr, ...);
-static void printl(char *channel, char *msg);
-static void privmsg(char *channel, char *msg);
-static void parsein(char *msg);
-static void parsesrv(char *msg);
-static int readl(int fd, unsigned int len, char *buf);
-
-static char *host = "irc6.oftc.net";
-static char *port = "6667";
+static char *host = "irc.oftc.net";
+static char *port = "ircd";
+static char *password;
static char nick[32];
-
-static char bufin[MAXMSG], bufout[MAXMSG];
+static char bufin[4096];
+static char bufout[4096];
static char channel[256];
-static int srv;
static time_t trespond;
+static FILE *srv;
+
+#include "util.c"
-void
-die(const char *errstr, ...) {
+static void
+pout(char *channel, char *fmt, ...) {
+ static char timestr[18];
+ time_t t;
va_list ap;
- va_start(ap, errstr);
- vfprintf(stderr, errstr, ap);
+
+ va_start(ap, fmt);
+ vsnprintf(bufout, sizeof bufout, fmt, ap);
va_end(ap);
- exit(EXIT_FAILURE);
+ t = time(NULL);
+ strftime(timestr, sizeof timestr, "%D %R", localtime(&t));
+ fprintf(stdout, "%-12s: %s %s\n", channel, timestr, bufout);
}
-void
-printl(char *channel, char *msg) {
- static char timestr[18];
- time_t t = time(0);
- strftime(timestr, sizeof timestr, "%D %R", localtime(&t));
- fprintf(stdout, "%-12.12s: %s %s\n", channel, timestr, msg);
+static void
+sout(char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(bufout, sizeof bufout, fmt, ap);
+ va_end(ap);
+ fprintf(srv, "%s\r\n", bufout);
+ fprintf(stderr, "debug: %s\n", bufout);
}
-void
+static void
privmsg(char *channel, char *msg) {
- if(channel[0] == '\0')
+ if(channel[0] == '\0') {
+ pout("", "No channel to send to");
return;
- snprintf(bufout, sizeof bufout, "<%s> %s", nick, msg);
- printl(channel, bufout);
- snprintf(bufout, sizeof bufout, "PRIVMSG %s :%s\r\n", channel, msg);
- write(srv, bufout, strlen(bufout));
+ }
+ pout(channel, "<%s> %s", nick, msg);
+ sout("PRIVMSG %s :%s", channel, msg);
}
-void
+static void
parsein(char *msg) {
- char *p = NULL;
+ char *p;
+ char c;
+
if(msg[0] == '\0')
return;
+ msg = ctok(&msg, '\n');
if(msg[0] != ':') {
privmsg(channel, msg);
return;
}
- if(strncmp(msg + 1, "j ", 2) == 0 && (msg[3] == '#'))
- snprintf(bufout, sizeof bufout, "JOIN %s\r\n", msg + 3);
- else if(strncmp(msg + 1, "l ", 2) == 0)
- snprintf(bufout, sizeof bufout, "PART %s :sic - 250 LOC are too much!\r\n", msg + 3);
- else if(strncmp(msg + 1, "m ", 2) == 0 && (p = strchr(msg + 3, ' '))) {
- *(p++) = '\0';
- privmsg(msg + 3, p);
- return;
- }
- else if(strncmp(msg + 1, "s ", 2) == 0) {
- strncpy(channel, msg + 3, sizeof channel - 1);
- return;
+ c = *++msg;
+ if(!c || !isspace(msg[1]))
+ sout("%s", msg);
+ else {
+ if(msg[1])
+ msg += 2;
+ switch(c) {
+ case 'j':
+ sout("JOIN %s", msg);
+ if(channel[0] == '\0')
+ strlcpy(channel, msg, sizeof channel);
+ break;
+ case 'l':
+ p = tok(&msg);
+ if(!*p)
+ p = channel;
+ if(!*msg)
+ msg = "sic - 250 LOC are too much!";
+ sout("PART %s :%s", p, msg);
+ break;
+ case 'm':
+ p = tok(&msg);
+ privmsg(p, msg);
+ break;
+ case 's':
+ strlcpy(channel, msg, sizeof channel);
+ break;
+ default:
+ sout("%c %s", c, msg);
+ break;
+ }
}
- else
- snprintf(bufout, sizeof bufout, "%s\r\n", msg + 1);
- write(srv, bufout, strlen(bufout));
}
-void
+static void
parsesrv(char *msg) {
- char *chan, *cmd, *p, *txt, *usr;
+ char *cmd, *p, *usr, *txt;
- txt = NULL;
usr = host;
- if(msg == NULL || *msg == '\0' )
+ if(!msg || !*msg)
return;
- if(msg[0] != ':')
- cmd = msg;
- else {
- if(!(p = strchr(msg, ' ')))
+ if(msg[0] == ':') {
+ msg++;
+ p = tok(&msg);
+ if(!*msg)
return;
- *p = '\0';
- usr = msg + 1;
- cmd = ++p;
- if((p = strchr(usr, '!')))
- *p = '\0';
+ usr = ctok(&p, '!');
}
- for(p = cmd; *p != '\0'; p++) /* remove CRLFs */
- if(*p == '\r' || *p == '\n')
- *p = '\0';
- if((p = strchr(cmd, ':'))) {
- *p = '\0';
- txt = ++p;
- }
- if(strncmp("PONG", cmd, 4) == 0)
+ txt = ctok(&msg, '\r');
+ msg = ctok(&txt, ':');
+ cmd = tok(&msg);
+ if(!strcmp("PONG", cmd))
return;
- if(strncmp("PRIVMSG", cmd, 7) == 0 && txt != NULL) {
- if(!(p = strchr(cmd, ' ')))
- return;
- *p = '\0';
- chan = ++p;
- for(; *p != '\0' && *p != ' '; p++);
- *p = '\0';
- snprintf(bufout, sizeof bufout, "<%s> %s", usr, txt);
- printl(chan, bufout);
- }
- else if(strncmp("PING", cmd, 4) == 0 && txt != NULL) {
- snprintf(bufout, sizeof bufout, "PONG %s\r\n", txt);
- write(srv, bufout, strlen(bufout));
- }
+ if(!strcmp("PRIVMSG", cmd))
+ pout(msg, "<%s> %s", usr, txt);
+ else if(!strcmp("PING", cmd))
+ sout("PONG %s", txt);
else {
- if (txt != NULL)
- (void) snprintf(bufout, sizeof bufout, ">< %s: %s", cmd, txt);
- else
- (void) snprintf(bufout, sizeof bufout, ">< %s: ", cmd);
- printl(usr, bufout);
- if(strncmp("NICK", cmd, 4) == 0 && strncmp(usr, nick, sizeof nick) == 0 && txt != NULL)
- strncpy(nick, txt, sizeof nick - 1);
+ pout(usr, ">< %s: %s", cmd, txt);
+ if(!strcmp("NICK", cmd) && !strcmp(usr, nick))
+ strlcpy(nick, txt, sizeof nick);
}
}
int
-readl(int fd, unsigned int len, char *buf) {
- unsigned int i = 0;
- char c = '\0';
-
- do {
- if(read(fd, &c, sizeof(char)) != (ssize_t) sizeof(char))
- return -1;
- buf[i++] = c;
- }
- while(c != '\n' && i < len);
- buf[i - 1] = '\0';
- return 0;
-}
-
-
-int
-main(const int argc, char *const argv[]) {
- int i;
+main(int argc, char *argv[]) {
+ int i, c;
struct timeval tv;
- static struct addrinfo hints, *res, *r;
- char ping[256];
fd_set rd;
- char *password = NULL;
- strncpy(nick, getenv("USER"), sizeof nick - 1);
- for(i = 1; i < argc; i++)
- if(strcmp(argv[i], "-h") == 0) {
+ strlcpy(nick, getenv("USER"), sizeof nick);
+ for(i = 1; i < argc; i++) {
+ c = argv[i][1];
+ if(argv[i][0] != '-' || argv[i][2])
+ c = -1;
+ switch(c) {
+ case 'h':
if(++i < argc) host = argv[i];
- }
- else if(strcmp(argv[i], "-p") == 0) {
+ break;
+ case 'p':
if(++i < argc) port = argv[i];
- }
- else if(strcmp(argv[i], "-n") == 0) {
- if(++i < argc) strncpy(nick, argv[i], sizeof nick - 1);
- }
- else if(strcmp(argv[i], "-k") == 0) {
+ break;
+ case 'n':
+ if(++i < argc) strlcpy(nick, argv[i], sizeof nick);
+ break;
+ case 'k':
if(++i < argc) password = argv[i];
- }
- else if(strcmp(argv[i], "-v") == 0)
- die("sic-%s, © 2005-2009 sic engineers\n", VERSION);
- else
- die("usage: sic [-h host] [-p port] [-n nick] [-k keyword] [-v]\n");
-
- /* init */
- memset(&hints, 0, sizeof hints);
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- if(getaddrinfo(host, port, &hints, &res) != 0)
- die("error: cannot resolve hostname '%s'\n", host);
- for(r = res; r; r = r->ai_next) {
- if((srv = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1)
- continue;
- if(connect(srv, r->ai_addr, r->ai_addrlen) == 0)
break;
- close(srv);
+ case 'v':
+ eprint("sic-"VERSION", © 2005-2009 Kris Maglione, Anselm R. Garbe, Nico Golde\n");
+ default:
+ eprint("usage: sic [-h host] [-p port] [-n nick] [-k keyword] [-v]\n");
+ }
}
- freeaddrinfo(res);
- if(!r)
- die("error: cannot connect to host '%s'\n", host);
-
+ /* init */
+ i = dial(host, port);
+ srv = fdopen(i, "r+");
/* login */
- if (password)
- snprintf(bufout, sizeof bufout,
- "PASS %s\r\nNICK %s\r\nUSER %s localhost %s :%s\r\n",
- password, nick, nick, host, nick);
- else
- snprintf(bufout, sizeof bufout, "NICK %s\r\nUSER %s localhost %s :%s\r\n",
- nick, nick, host, nick);
- write(srv, bufout, strlen(bufout));
- snprintf(ping, sizeof ping, "PING %s\r\n", host);
- channel[0] = '\0';
- setbuf(stdout, NULL); /* unbuffered stdout */
-
+ if(password)
+ sout("PASS %s", password);
+ sout("NICK %s", nick);
+ sout("USER %s localhost %s :%s", nick, host, nick);
+ fflush(srv);
+ setbuf(stdout, NULL);
+ setbuf(srv, NULL);
for(;;) { /* main loop */
FD_ZERO(&rd);
FD_SET(0, &rd);
- FD_SET(srv, &rd);
+ FD_SET(fileno(srv), &rd);
tv.tv_sec = 120;
tv.tv_usec = 0;
- i = select(srv + 1, &rd, 0, 0, &tv);
+ i = select(fileno(srv) + 1, &rd, 0, 0, &tv);
if(i < 0) {
if(errno == EINTR)
continue;
- die("error: error on select()\n");
+ eprint("sic: error on select():");
}
else if(i == 0) {
- if(time(NULL) - trespond >= PINGTIMEOUT)
- die("error: sic shutting down: parse timeout\n");
- write(srv, ping, strlen(ping));
+ if(time(NULL) - trespond >= 300)
+ eprint("sic shutting down: parse timeout\n");
+ sout("PING %s", host);
continue;
}
- if(FD_ISSET(srv, &rd) != 0) {
- if(readl(srv, sizeof bufin, bufin) == -1)
- die("error: remote host closed connection\n");
+ if(FD_ISSET(fileno(srv), &rd)) {
+ if(fgets(bufin, sizeof bufin, srv) == NULL)
+ eprint("sic: remote host closed connection\n");
parsesrv(bufin);
trespond = time(NULL);
}
- if(FD_ISSET(0, &rd) != 0) {
- if(readl(0, sizeof bufin, bufin) == -1)
- die("error: broken pipe\n");
+ if(FD_ISSET(0, &rd)) {
+ if(fgets(bufin, sizeof bufin, stdin) == NULL)
+ eprint("sic: broken pipe\n");
parsein(bufin);
}
}
diff --git a/util.c b/util.c
@@ -0,0 +1,81 @@
+/* See LICENSE file for license details. */
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+static void
+eprint(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(bufout, sizeof bufout, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "%s", bufout);
+ if(fmt[0] && fmt[strlen(fmt) - 1] == ':')
+ fprintf(stderr, " %s\n", strerror(errno));
+ exit(1);
+}
+
+static int
+dial(char *host, char *port) {
+ static struct addrinfo hints;
+ int srv;
+ struct addrinfo *res, *r;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ if(getaddrinfo(host, port, &hints, &res) != 0)
+ eprint("error: cannot resolve hostname '%s':", host);
+ for(r = res; r; r = r->ai_next) {
+ if((srv = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1)
+ continue;
+ if(connect(srv, r->ai_addr, r->ai_addrlen) == 0)
+ break;
+ close(srv);
+ }
+ freeaddrinfo(res);
+ if(!r)
+ eprint("error: cannot connect to host '%s'\n", host);
+ return srv;
+}
+
+#define strlcpy _strlcpy
+static void
+strlcpy(char *to, const char *from, int l) {
+ memccpy(to, from, '\0', l);
+ to[l-1] = '\0';
+}
+
+static void
+eat(char **s, int (*p)(int), int r) {
+ char *q;
+
+ for(q = *s; *q && p(*q) == r; q++)
+ ;
+ *s = q;
+}
+
+static char*
+tok(char **s) {
+ char *p;
+
+ eat(s, isspace, 1);
+ p = *s;
+ eat(s, isspace, 0);
+ if(**s)
+ *(*s)++ = '\0';
+ return p;
+}
+
+static char*
+ctok(char **s, int c) {
+ char *p, *q;
+
+ q = *s;
+ for(p = q; *p && *p != c; p++)
+ ;
+ if(*p) *p++ = '\0';
+ *s = p;
+ return q;
+}