diff --git a/err.c b/err.c new file mode 100644 index 0000000..9d711d6 --- /dev/null +++ b/err.c @@ -0,0 +1,55 @@ +#define _POSIX_C_SOURCE 200809l + +#include +#include +#include +#include +#include + +#include "err.h" + +void die(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + vfprintf(stderr, fmt, ap); + + if (fmt[0] && fmt[strlen(fmt) - 1] == ':') + fprintf(stderr, " %s", strerror(errno)); + else + fputc('\n', stderr); + + va_end(ap); + exit(errno ? errno : EXIT_FAILURE); +} + +void *emalloc(size_t s) +{ + if (!s || s == (size_t)-1) + die("bad malloc: invalid size"); + void *p = malloc(s); + if (!p) + die("bad malloc:"); + return p; +} + +void *erealloc(void *p, size_t s) +{ + if (!s || s == (size_t)-1) + die("bad realloc: invalid size"); + void *r = realloc(p, s); + if (!r) + die("bad realloc:"); + return r; +} + +char *estrdup(const char *s) +{ + if (!s) + die("bad strdup: cannot duplicate NULL pointer"); + char *r = strdup(s); + if (!r) + die("bad strdup:"); + return r; +} diff --git a/err.h b/err.h new file mode 100644 index 0000000..aa3c406 --- /dev/null +++ b/err.h @@ -0,0 +1,16 @@ +#ifndef _ACRON_ERR_H +#define _ACRON_ERR_H + +/* Helper error/error-ing functions, like die() and dying versions of memory + * allocating functions */ + +#include + +void die(const char *, ...); + +/* Erroring functions */ +void *emalloc(size_t); +void *erealloc(void *, size_t); +char *estrdup(const char *); + +#endif diff --git a/fstr.c b/fstr.c index 0b9e3a8..4d25f87 100644 --- a/fstr.c +++ b/fstr.c @@ -3,11 +3,12 @@ #include #include "fstr.h" +#include "err.h" #include "config.h" void fstr_add_space(fstr_t *fs) { - erealloc(fs->s, fs->len + fs->space + DEF_CHUNKSIZE + 1); + fs->s = erealloc(fs->s, fs->len + fs->space + DEF_CHUNKSIZE + 1); fs->space += DEF_CHUNKSIZE; } @@ -17,7 +18,15 @@ void fstr_append_char(fstr_t *fs, char c) return; if (fs->space < 1) fstr_add_space(fs); - fs->s[fs->len++] = c; - fs->s[fs->len] = '\0'; + // I don't know if this is faster + if (fs->s[fs->len] != c) + fs->s[fs->len] = c; + fs->s[++fs->len] = '\0'; fs->space--; } + +void fstr_clear(fstr_t *fs) +{ + fs->space += fs->len; + fs->len = 0; +} diff --git a/fstr.h b/fstr.h index 635b103..ca4552d 100644 --- a/fstr.h +++ b/fstr.h @@ -10,5 +10,6 @@ typedef struct _fstr { } fstr_t; void fstr_append_char(fstr_t *, char); +void fstr_clear(fstr_t *); #endif diff --git a/makefile b/makefile index 769f902..713b10d 100644 --- a/makefile +++ b/makefile @@ -1,8 +1,8 @@ .POSIX: -CFLAGS = -Wall -Werror -pedantic -Wextra -std=c11 +CFLAGS = -Wall -Werror -pedantic -Wextra -std=c11 -O0 -g -msh: msh.c fstr.c +msh: msh.c fstr.c err.c clean: rm -f msh *.o diff --git a/msh b/msh new file mode 100755 index 0000000..1287695 Binary files /dev/null and b/msh differ diff --git a/msh.c b/msh.c index 374163a..c2b25f4 100644 --- a/msh.c +++ b/msh.c @@ -2,13 +2,15 @@ #include -#include #include +#include #include #include +#include #include "config.h" #include "fstr.h" +#include "err.h" fstr_t PS1 = {0}; unsigned int histsize = DEF_HISTSIZE; @@ -26,6 +28,12 @@ struct { char tag; } shinfo; +struct { + struct termios tio; + struct termios tio_before; +} terminfo; + +void sh_setup_terminal(void); void sh_update_uinfo(void); void sh_update_shinfo(void); void sh_update_ps1(void); @@ -35,19 +43,40 @@ int main(int argc, char **argv) { (void)argc; (void)argv; + char i; + sh_setup_terminal(); for (;;) { sh_update_uinfo(); sh_update_shinfo(); sh_update_ps1(); sh_print_ps1(); - for(;;); + fflush(stdout); + while (1) { + read(STDIN_FILENO, &i, 1); // This blocks + fputc(i, stdout); + fflush(stdout); + if (i == '\n') + break; + } } return EXIT_SUCCESS; } -void sh_fill_uinfo(void) +void sh_setup_terminal(void) +{ + if (tcgetattr(STDOUT_FILENO, &terminfo.tio_before) == -1) + die("tcgetattr:"); + terminfo.tio = terminfo.tio_before; + /* Do not echo and input is available immediately */ + terminfo.tio.c_lflag &= ~ECHO; + terminfo.tio.c_lflag &= ~ICANON; + if (tcsetattr(STDOUT_FILENO, TCSANOW, &terminfo.tio) == -1) + die("tcsetattr:"); +} + +void sh_update_uinfo(void) { struct passwd *pw; uid_t nuid; @@ -58,7 +87,7 @@ void sh_fill_uinfo(void) pw = getpwuid(uinfo.uid); // User not found if (!pw) - exit(EXIT_FAILURE); + die("getpwuid:"); uinfo.gid = pw->pw_gid; uinfo.name = estrdup(pw->pw_name); uinfo.home = estrdup(pw->pw_dir); @@ -69,13 +98,14 @@ void sh_update_shinfo(void) shinfo.tag = uinfo.uid ? '$' : '#'; } -inline void sh_print_ps1(void) +void sh_print_ps1(void) { - puts(PS1.s); + fputs(PS1.s, stdout); } void sh_update_ps1(void) { + fstr_clear(&PS1); fstr_append_char(&PS1, shinfo.tag); fstr_append_char(&PS1, ' '); }