#include "../external/cbs/cbs.c"
-#define SRC1 "context", "history"
-#define SRC2 "input", "main", "options", "parse", "run", "utils"
+#define SRC1 "context", "history", "input", "signals"
+#define SRC2 "main", "options", "parse", "run", "utils"
int main(void) {
char **src;
#include "bg.h"
#include "builtin.h"
#include "context.h"
-#include "input.h"
#include "options.h"
+#include "signals.h"
#include "utils.h"
-int sigquit, sigint;
static struct {
pid_t id;
int status, done;
} fgjob;
-static sigset_t shellsigmask;
static struct sigaction fgaction;
-struct sigaction defaultaction;
static pid_t pgid;
-sigset_t childsigmask;
struct termios canonical;
static struct termios raw;
-static void sigquithandler(int sig) {
- (void)sig;
-
- sigquit = 1;
-}
-
-static void siginthandler(int sig) {
- (void)sig;
-
- sigint = 1;
-}
-
static void sigchldfghandler(int sig) {
int e, s;
pid_t id;
errno = e;
}
-void setsig(int sig, struct sigaction *act) {
- if (sigaction(sig, act, NULL) == -1)
- fatal("Unable to install %s handler", strsignal(sig));
-}
-
static int setconfig(struct termios *mode) {
if (tcsetattr(STDIN_FILENO, TCSANOW, mode) == -1) {
note("Unable to configure TTY");
}
void initfg(void) {
- struct sigaction action;
pid_t pid;
- sigemptyset(&shellsigmask);
- sigaddset(&shellsigmask, SIGTSTP);
- sigaddset(&shellsigmask, SIGTTIN);
- sigaddset(&shellsigmask, SIGTTOU);
-
- action = (struct sigaction){.sa_handler = sigquithandler};
- setsig(SIGHUP, &action);
- setsig(SIGQUIT, &action);
- setsig(SIGTERM, &action);
-
- action = (struct sigaction){.sa_handler = siginthandler};
- setsig(SIGINT, &action);
-
fgaction = (struct sigaction){.sa_handler = sigchldfghandler};
- defaultaction = (struct sigaction){.sa_handler = SIG_DFL};
- setsig(SIGTSTP, &defaultaction);
- setsig(SIGTTOU, &defaultaction);
- setsig(SIGTTIN, &defaultaction);
-
pid = getpid();
pgid = getpgrp();
if (login && pid != pgid && setpgid(0, pgid = pid) == -1) exit(errno);
- if (sigprocmask(SIG_BLOCK, &shellsigmask, &childsigmask) == -1
- || tcsetpgrp(STDIN_FILENO, pgid) == -1)
+ if (tcsetpgrp(STDIN_FILENO, pgid) == -1)
exit(errno);
if (tcgetattr(STDIN_FILENO, &canonical) == -1) exit(errno);
-extern int sigquit, sigint;
-extern struct sigaction defaultaction;
-extern sigset_t childsigmask;
extern struct termios canonical;
-void setsig(int sig, struct sigaction *act);
void initfg(void);
int runfg(pid_t id);
void deinitfg(void);
return 1;
}
-void sethistory(char *buffer) {
- strcpy(history.entries[history.t], buffer);
- history.c = INC(t);
- if (history.t == history.b) INC(b);
- if (history.t == history.s) INC(s);
- *history.entries[history.t] = '\0';
+void addhistory(char *buffer) {
+ if (buffer) {
+ strcpy(history.entries[history.t], buffer);
+ if (INC(t) == history.b) INC(b);
+ if (history.t == history.s) INC(s);
+ }
+ *history.entries[history.c = history.t] = '\0';
}
static void writehistory(FILE *file) {
void inithistory(void);
int gethistory(int back, char *buffer);
-void sethistory(char *buffer);
+void addhistory(char *buffer);
void deinithistory(void);
#include <fcntl.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include "context.h"
-#include "fg.h"
#include "history.h"
+#include "signals.h"
#include "utils.h"
+#define OFFSET(x) ((promptlen + (x) - start) % window.ws_col)
+
enum {
CTRLD = '\004',
CLEAR = '\014',
DEL = '\177',
};
+static struct winsize window;
+static char *start, *cursor, *end;
+static size_t promptlen;
+
+void getcolumns(void) {
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &window) == -1 && window.ws_col == 0)
+ window.ws_col = 80;
+}
+
int stringinput(struct context *c) {
- char *end;
size_t l;
if (!c->string[0]) {
return c->input(c);
}
+static void moveright(void) {
+ putchar(*cursor);
+ if (OFFSET(cursor++) == window.ws_col - 1) putchar('\n');
+}
+
static void prompt(void) {
- char *p;
+ char *p, *oldstart, *oldcursor;
- if (!(p = getenv("PROMPT")) && setenv("PROMPT", p = ">", 1) == -1)
+ if (!(p = getenv("PROMPT")) && setenv("PROMPT", p = "> ", 1) == -1)
note("Unable to update $PROMPT$ environment variable");
- printf("%s ", p);
+
+ oldstart = start;
+ oldcursor = cursor;
+
+ promptlen = 0;
+ cursor = start = p;
+ while (*cursor) moveright();
+ promptlen = cursor - start;
+
+ cursor = oldcursor;
+ start = oldstart;
+}
+
+static void moveleft(void) {
+ if (OFFSET(cursor--)) putchar('\b');
+ else printf("\033[A\033[%dC", window.ws_col - 1);
+}
+
+static void newline(void) {
+ size_t i;
+
+ for (i = (promptlen + end - cursor) / window.ws_col; i > 0; --i) putchar('\n');
+ if (OFFSET(cursor) > OFFSET(end)) putchar('\n');
+ if (OFFSET(end)) putchar('\n');
+ putchar('\r');
}
int userinput(struct context *c) {
- char *start, *cursor, *end;
- int current, i;
- size_t oldlen, newlen;
+ int current;
+ char *oldcursor, *oldend;
clear(c);
end = cursor = start = c->buffer;
while (start == end) {
prompt();
- while ((current = getchar()) != '\n') switch (current) {
- default:
- if (current >= ' ' && current <= '~') {
- if (end - start == MAXCHARS) break;
- memmove(cursor + 1, cursor, end - cursor);
- *cursor++ = current;
- *++end = '\0';
-
- putchar(current);
- fputs(cursor, stdout);
- for (i = end - cursor; i > 0; --i) putchar('\b');
- }
- break;
- case EOF:
- if (sigquit) {
- case CTRLD:
- putchar('\n');
- return 0;
- }
- if (sigint) {
- sigint = 0;
- putchar('\n');
+ while ((current = getchar()) != '\n') {
+ switch (current) {
+ default:
+ if (current >= ' ' && current <= '~') {
+ if (end - start == MAXCHARS) break;
+ memmove(cursor + 1, cursor, end - cursor);
+ *cursor = current;
+ *++end = '\0';
+
+ oldcursor = cursor + 1;
+ while (cursor != end) moveright();
+ while (cursor != oldcursor) moveleft();
+ }
+ break;
+ case EOF:
+ if (sigquit) {
+ case CTRLD:
+ newline();
+ return 0;
+ }
+ if (sigint) {
+ sigint = 0;
+
+ newline();
+ prompt();
+
+ end = cursor = start;
+ *start = '\0';
+
+ addhistory(NULL);
+ }
+ if (sigwinch) {
+ sigwinch = 0;
+
+ getcolumns();
+ }
+ break;
+ case CLEAR:
+ fputs("\033[H\033[J", stdout);
prompt();
- }
- break;
- case CLEAR:
- fputs("\033[H\033[J", stdout);
- prompt();
- fputs(c->buffer, stdout);
- break;
-
- /* This is a very minimal way to handle arrow keys. All modifiers except for
- * the ALT key are processed but ignored.
- *
- * See "Terminal Input Sequences" reference in `README.md'. */
- case ESCAPE:
- if ((current = getchar()) == '[') {
- while ((current = getchar()) >= '0' && current <= '9');
- if (current == ';') {
- if ((current = getchar()) == ALT) switch ((current = getchar())) {
+ oldcursor = cursor;
+ cursor = start;
+ while (cursor != end) moveright();
+ while (cursor != oldcursor) moveleft();
+ break;
+
+ /* This is a very minimal way to handle arrow keys. All modifiers except for
+ * the ALT key are processed but ignored.
+ *
+ * See "Terminal Input Sequences" reference in `README.md'. */
+ case ESCAPE:
+ if ((current = getchar()) == '[') {
+ while ((current = getchar()) >= '0' && current <= '9');
+ if (current == ';') {
+ if ((current = getchar()) == ALT) switch ((current = getchar())) {
+ case LEFT:
+ current = BACKWARD;
+ break;
+ case RIGHT:
+ current = FORWARD;
+ break;
+ } else if ((current = getchar()) >= '0' && current <= '6')
+ current = getchar();
+ }
+ switch (current) {
+ case UP:
+ case DOWN:
+ oldend = end;
+
+ oldcursor = cursor;
+ if (!gethistory(current == UP, c->buffer)) break;
+ end = cursor = start + strlen(start);
+ while (cursor < oldend) *cursor++ = ' ';
+ cursor = oldcursor;
+
+ while (cursor != start) moveleft();
+ while (cursor < end || cursor < oldend) moveright();
+ while (cursor != end) moveleft();
+
+ *end = '\0';
+
+ break;
case LEFT:
- current = BACKWARD;
+ if (cursor > start) moveleft();
break;
case RIGHT:
- current = FORWARD;
+ if (cursor < end) moveright();
break;
- } else if ((current = getchar()) >= '0' && current <= '6')
- current = getchar();
+ }
}
switch (current) {
- case UP:
- case DOWN:
- oldlen = strlen(c->buffer);
- if (!gethistory(current == UP, c->buffer)) break;
- newlen = strlen(c->buffer);
- end = cursor = start + newlen;
-
- putchar('\r');
- prompt();
- fputs(c->buffer, stdout);
- for (i = oldlen - newlen; i > 0; --i) putchar(' ');
- for (i = oldlen - newlen; i > 0; --i) putchar('\b');
-
+ case FORWARD:
+ while (cursor != end && *cursor != ' ') moveright();
+ while (cursor != end && *cursor == ' ') moveright();
break;
- case LEFT:
- if (cursor > start) putchar((--cursor, '\b'));
- break;
- case RIGHT:
- if (cursor < end) putchar(*cursor++);
+ case BACKWARD:
+ while (cursor != start && *(cursor - 1) == ' ') moveleft();
+ while (cursor != start && *(cursor - 1) != ' ') moveleft();
break;
}
- }
- switch (current) {
- case FORWARD:
- while (cursor != end && *cursor != ' ') putchar(*cursor++);
- while (cursor != end && *cursor == ' ') putchar(*cursor++);
break;
- case BACKWARD:
- while (cursor != start && *(cursor - 1) == ' ') putchar((--cursor, '\b'));
- while (cursor != start && *(cursor - 1) != ' ') putchar((--cursor, '\b'));
- break;
- }
- break;
+ case DEL:
+ if (cursor == start) break;
+ memmove(oldcursor = cursor - 1, cursor, end - cursor);
+ *(end - 1) = ' ';
- case DEL:
- if (cursor == start) break;
- memmove(cursor - 1, cursor, end - cursor);
- --cursor;
- *--end = '\0';
+ moveleft();
+ while (cursor != end) moveright();
+ while (cursor != oldcursor) moveleft();
- putchar('\b');
- fputs(cursor, stdout);
- putchar(' ');
- for (i = end - cursor + 1; i > 0; --i) putchar('\b');
+ *--end = '\0';
- break;
+ break;
+ }
}
- putchar('\n');
+ newline();
}
while (*start == ' ') ++start;
if (start == end) return quit(c);
+ while (*(end - 1) == ' ') --end;
+ *end = '\0';
- sethistory(c->buffer);
+ addhistory(start);
*end++ = ';';
*end = '\0';
+void getcolumns(void);
int stringinput(struct context *c);
int scriptinput(struct context *c);
int userinput(struct context *c);
#include "context.h"
#include "fg.h"
#include "parse.h"
+#include "signals.h"
#include "utils.h"
#include "which.h"
--- /dev/null
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/errno.h>
+
+#include "utils.h"
+
+int sigquit, sigint, sigwinch;
+sigset_t shellsigmask, childsigmask;
+struct sigaction defaultaction;
+
+void setsig(int sig, struct sigaction *act) {
+ if (sigaction(sig, act, NULL) == -1)
+ fatal("Unable to install %s handler", strsignal(sig));
+}
+
+static void sigquithandler(int sig) {
+ (void)sig;
+
+ sigquit = 1;
+}
+
+static void siginthandler(int sig) {
+ (void)sig;
+
+ sigint = 1;
+}
+
+static void sigwinchhandler(int sig) {
+ (void)sig;
+
+ sigwinch = 1;
+}
+
+void initsignals(void) {
+ struct sigaction action;
+
+ sigemptyset(&shellsigmask);
+ sigaddset(&shellsigmask, SIGTSTP);
+ sigaddset(&shellsigmask, SIGTTIN);
+ sigaddset(&shellsigmask, SIGTTOU);
+
+ action = (struct sigaction){.sa_handler = sigquithandler};
+ setsig(SIGHUP, &action);
+ setsig(SIGQUIT, &action);
+ setsig(SIGTERM, &action);
+
+ action = (struct sigaction){.sa_handler = siginthandler};
+ setsig(SIGINT, &action);
+
+ action = (struct sigaction){.sa_handler = sigwinchhandler};
+ setsig(SIGWINCH, &action);
+
+ defaultaction = (struct sigaction){.sa_handler = SIG_DFL};
+ setsig(SIGTSTP, &defaultaction);
+ setsig(SIGTTOU, &defaultaction);
+ setsig(SIGTTIN, &defaultaction);
+
+ if (sigprocmask(SIG_BLOCK, &shellsigmask, &childsigmask) == -1) exit(errno);
+}
--- /dev/null
+extern int sigquit, sigint, sigwinch;
+extern sigset_t shellsigmask, childsigmask;
+extern struct sigaction defaultaction;
+
+void setsig(int sig, struct sigaction *act);
+void initsignals(void);
#include <limits.h>
+#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "bg.h"
+#include "context.h"
#include "fg.h"
#include "history.h"
+#include "input.h"
+#include "signals.h"
int argcount, status;
char **arglist, *home;
"/usr/bin/:/usr/sbin/:/bin/:/sbin/", 1) == -1)
note("Unable to initialize $PATH$");
+ getcolumns();
+
+ initsignals();
initfg();
initbg();
inithistory();