]> git.mdlowis.com Git - projs/alib.git/commitdiff
Updated license text and reworked stdc.h
authorMichael D. Lowis <mike.lowis@gentex.com>
Thu, 30 Mar 2017 17:11:08 +0000 (13:11 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Thu, 30 Mar 2017 17:11:08 +0000 (13:11 -0400)
.gitignore [new file with mode: 0644]
Makefile
src/ansivt.h [new file with mode: 0644]
src/ini.h
src/stdc.h
tests/main.c

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..ba4b54f
--- /dev/null
@@ -0,0 +1,2 @@
+*.o
+runtests
index ba5118fa3b27b911a8cd1fcd50a25243feb14dc7..7bbbeb7e3a6efb27a87f8dab50bc30f515db7c4d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 CC     = c99
 CFLAGS = 
-INCS   = -Isource/
+INCS   = -Isrc/
 SRCS   = $(wildcard tests/*.c)
 OBJS   = $(SRCS:.c=.o)
 
diff --git a/src/ansivt.h b/src/ansivt.h
new file mode 100644 (file)
index 0000000..44efe0d
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+    Minimal set of routines for working with ANSI terminal escape codes for 
+    controlling terminal operation on POSIX systems.
+        
+    Copyright 2017, Michael D. Lowis
+    
+    Permission to use, copy, modify, and/or 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 <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+
+static void ttyresp(char* buf, int bufsz) {
+    for (int i = 0; i < bufsz; i++) {
+        if (read(STDIN_FILENO, buf+i, 1) != 1) break;
+        if (buf[i] == 'R') break;
+    }
+}
+
+static void ttysendrecv(const char* req, const char* resp, ...) {
+    char buf[32] = {0};
+    (void)write(STDOUT_FILENO, req, strlen(req));
+    ttyresp(buf, sizeof(buf)-1);
+    va_list args;
+    va_start(args, resp);
+    vsscanf(buf, resp, args);
+    va_end(args);
+}
+
+static bool ttyrawmode(bool enable) {
+    static bool enabled = false;
+    static struct termios orig_termios;
+    if (enabled && !enable) {
+        tcsetattr(STDOUT_FILENO, TCSAFLUSH, &orig_termios);
+    } else if (!enabled && enable){
+        if (tcgetattr(STDOUT_FILENO, &orig_termios) < 0) goto done;
+        struct termios raw = orig_termios;
+        raw.c_iflag    &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+        raw.c_oflag    &= ~(OPOST);
+        raw.c_cflag    |= (CS8);
+        raw.c_lflag    &= ~(ECHO | ICANON | IEXTEN | ISIG);
+        raw.c_cc[VMIN]  = 0;
+        raw.c_cc[VTIME] = 1;
+        if (tcsetattr(STDOUT_FILENO,TCSAFLUSH, &raw) < 0) goto done;
+        enabled = true;
+    }
+done:
+    return enabled;
+}
+
+enum {
+    /* Special Keys */
+    KEY_F1               = (0xFFFF-0),
+    KEY_F2               = (0xFFFF-1),
+    KEY_F3               = (0xFFFF-2),
+    KEY_F4               = (0xFFFF-3),
+    KEY_F5               = (0xFFFF-4),
+    KEY_F6               = (0xFFFF-5),
+    KEY_F7               = (0xFFFF-6),
+    KEY_F8               = (0xFFFF-7),
+    KEY_F9               = (0xFFFF-8),
+    KEY_F10              = (0xFFFF-9),
+    KEY_F11              = (0xFFFF-10),
+    KEY_F12              = (0xFFFF-11),
+    KEY_INSERT           = (0xFFFF-12),
+    KEY_DELETE           = (0xFFFF-13),
+    KEY_HOME             = (0xFFFF-14),
+    KEY_END              = (0xFFFF-15),
+    KEY_PGUP             = (0xFFFF-16),
+    KEY_PGDN             = (0xFFFF-17),
+    KEY_ARROW_UP         = (0xFFFF-18),
+    KEY_ARROW_DOWN       = (0xFFFF-19),
+    KEY_ARROW_RIGHT      = (0xFFFF-20),
+    KEY_ARROW_LEFT       = (0xFFFF-21),
+    KEY_MOUSE_LEFT       = (0xFFFF-22),
+    KEY_MOUSE_RIGHT      = (0xFFFF-23),
+    KEY_MOUSE_MIDDLE     = (0xFFFF-24),
+    KEY_MOUSE_RELEASE    = (0xFFFF-25),
+    KEY_MOUSE_WHEEL_UP   = (0xFFFF-26),
+    KEY_MOUSE_WHEEL_DOWN = (0xFFFF-27),
+
+    /* ASCII Control Characters */
+    KEY_CTRL_TILDE       = 0x00,
+    KEY_CTRL_2           = 0x00,
+    KEY_CTRL_A           = 0x01,
+    KEY_CTRL_B           = 0x02,
+    KEY_CTRL_C           = 0x03,
+    KEY_CTRL_D           = 0x04,
+    KEY_CTRL_E           = 0x05,
+    KEY_CTRL_F           = 0x06,
+    KEY_CTRL_G           = 0x07,
+    KEY_BACKSPACE        = 0x08,
+    KEY_CTRL_H           = 0x08,
+    KEY_TAB              = 0x09,
+    KEY_CTRL_I           = 0x09,
+    KEY_CTRL_J           = 0x0A,
+    KEY_CTRL_K           = 0x0B,
+    KEY_CTRL_L           = 0x0C,
+    KEY_ENTER            = 0x0D,
+    KEY_CTRL_M           = 0x0D,
+    KEY_CTRL_N           = 0x0E,
+    KEY_CTRL_O           = 0x0F,
+    KEY_CTRL_P           = 0x10,
+    KEY_CTRL_Q           = 0x11,
+    KEY_CTRL_R           = 0x12,
+    KEY_CTRL_S           = 0x13,
+    KEY_CTRL_T           = 0x14,
+    KEY_CTRL_U           = 0x15,
+    KEY_CTRL_V           = 0x16,
+    KEY_CTRL_W           = 0x17,
+    KEY_CTRL_X           = 0x18,
+    KEY_CTRL_Y           = 0x19,
+    KEY_CTRL_Z           = 0x1A,
+    KEY_ESC              = 0x1B,
+    KEY_CTRL_LSQ_BRACKET = 0x1B,
+    KEY_CTRL_3           = 0x1B,
+    KEY_CTRL_4           = 0x1C,
+    KEY_CTRL_BACKSLASH   = 0x1C,
+    KEY_CTRL_5           = 0x1D,
+    KEY_CTRL_RSQ_BRACKET = 0x1D,
+    KEY_CTRL_6           = 0x1E,
+    KEY_CTRL_7           = 0x1F,
+    KEY_CTRL_SLASH       = 0x1F,
+    KEY_CTRL_UNDERSCORE  = 0x1F,
+    KEY_SPACE            = 0x20,
+    KEY_BACKSPACE2       = 0x7F,
+    KEY_CTRL_8           = 0x7F,
+};
+
+static int readkey(void) {
+    int nread;
+    char c, seq[3];
+    while ((nread = read(STDIN_FILENO,&c,1)) == 0);
+    if (nread < 0) return EOF;
+    if (c != KEY_ESC) return c;
+    /* Otherwise parse the escape sequence */
+    while (true) {
+        /* If this is just an ESC, we'll timeout here. */
+        if (read(STDIN_FILENO, seq,   1) == 0) return KEY_ESC;
+        if (read(STDIN_FILENO, seq+1, 1) == 0) return KEY_ESC;
+        /* Parse the escape sequence */
+        if ('[' == seq[0]) {
+            if ((seq[1] >= '0') && (seq[1] <= '9')) {
+                /* Extended escape, read additional byte. */
+                if (read(STDIN_FILENO, seq+2, 1) == 0) return KEY_ESC;
+                if (seq[2] == '~') {
+                    switch(seq[1]) {
+                        case '3': return KEY_DELETE;
+                        case '5': return KEY_PGUP;
+                        case '6': return KEY_PGDN;
+                    }
+                }
+            } else {
+                switch(seq[1]) {
+                    case 'A': return KEY_ARROW_UP;
+                    case 'B': return KEY_ARROW_DOWN;
+                    case 'C': return KEY_ARROW_RIGHT;
+                    case 'D': return KEY_ARROW_LEFT;
+                    case 'H': return KEY_HOME;
+                    case 'F': return KEY_END;
+                }
+            }
+        } else if ('O' == seq[0]) {
+            switch(seq[1]) {
+                case 'H': return KEY_HOME;
+                case 'F': return KEY_END;
+            }
+        }
+    }
+    /* should never get here */
+    return EOF;
+}
+
+/* Screen Buffer Handling
+ *****************************************************************************/
+static struct {
+    size_t capacity;
+    size_t length;
+    char* buffer;
+} ScreenBuf;
+
+static void scrsize(int* rows, int* cols) {
+    /* save cursor pos, try to move to lower right, read pos, restore pos */
+    ttysendrecv("\033[s\033[999;999H\033[6n\033[u", "\033[%d;%dR", rows, cols);
+}
+
+static void scrdraw(void) {
+    write(STDOUT_FILENO, ScreenBuf.buffer, ScreenBuf.length);
+    ScreenBuf.length = 0;
+}
+
+static void scrputc(char ch) {
+    /* Make sure there's space for the new char */
+    if (ScreenBuf.buffer == NULL) {
+        ScreenBuf.capacity = 8u;
+        ScreenBuf.buffer   = (char*)calloc(ScreenBuf.capacity, 1u);
+    } else if (ScreenBuf.length+1u >= ScreenBuf.capacity) {
+        ScreenBuf.capacity = ScreenBuf.capacity << 1u;
+        ScreenBuf.buffer = (char*)realloc(ScreenBuf.buffer, ScreenBuf.capacity);
+    }
+    /* Append the char */
+    ScreenBuf.buffer[ScreenBuf.length++] = ch;
+    ScreenBuf.buffer[ScreenBuf.length]   = '\0';
+}
+
+static int scrputs(char* str) {
+    int nwrite = 0;
+    while (*str) {
+        scrputc(*(str++));
+        nwrite++;
+    }
+    return nwrite;
+}
+
+static int scrprintf(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    size_t strsz = vsnprintf(NULL, 0, fmt, args);
+    va_end(args);
+    char* str = malloc(strsz+1);
+    va_start(args, fmt);
+    int nwrite = vsnprintf(str, strsz+1, fmt, args);
+    va_end(args);
+    scrputs(str);
+    free(str);
+    return nwrite;
+}
+
+static void scrclrup(void) {
+    scrputs("\033[0J");
+}
+
+static void scrclrdn(void) {
+    scrputs("\033[1J");
+}
+
+static void scrclr(void) {
+    scrputs("\033[2J");
+}
+
+static void scrclrlnl(void) {
+    scrputs("\033[0K");
+}
+
+static void scrclrlnr(void) {
+    scrputs("\033[1K");
+}
+
+static void scrclrln(void) {
+    scrputs("\033[2K");
+}
+
+/* Cursor Handling
+ *****************************************************************************/
+static void csrhome(void) {
+    scrputs("\033[H");
+}
+
+static void csrmove(int l, int c) {
+    scrprintf("\033[%d;%dH", l, c);
+}
+
+static void csrup(int n) {
+    scrprintf("\033[%dA", n);
+}
+
+static void csrdn(int n) {
+    scrprintf("\033[%dB", n);
+}
+
+static void csrleft(int n) {
+    scrprintf("\033[%dC", n);
+}
+
+static void csrright(int n) {
+    scrprintf("\033[%dD", n);
+}
+
+static void csrsave(void) {
+    scrputs("\033[s");
+}
+
+static void csrrestore(void) {
+    scrputs("\033[u");
+}
+
+static void csrhide(void) {
+    scrputs("\033[?25l");
+}
+
+static void csrshow(void) {
+    scrputs("\033[?25h");
+}
+
+/* Attribute Handling
+ *****************************************************************************/
+enum {
+    NORMAL   = 0,
+    BOLD     = 1,
+    UNDRLINE = 4,
+    BLINK    = 5,
+    REVERSE  = 7,
+    CONCEAL  = 8,
+};
+
+enum {
+    BLACK   = 0,
+    RED     = 1,
+    GREEN   = 2,
+    YELLOW  = 3,
+    BLUE    = 4,
+    MAGENTA = 5,
+    CYAN    = 6,
+    WHITE   = 7,
+};
+
+static void attrset(int a, int fg, int bg) {
+    scrprintf("\033[%d;%d;%dm",a, 30+fg, 40+bg);
+}
+
+static void attrclr(void) {
+    scrputs("\033[m");
+}
+
+static void attrsetstyle(int a) {
+    scrprintf("\033[%dm", a);
+}
+
+static void attrsetfg(int fg) {
+    scrprintf("\033[%dm", fg + 30);
+}
+
+static void attrsetbg(int bg) {
+    scrprintf("\033[%dm", bg + 40);
+}
index b2bfdaab5823d309441d836f8b70a453be27ace9..ac5d14963ce751fdc372494a490788666a8f0651 100644 (file)
--- a/src/ini.h
+++ b/src/ini.h
@@ -17,9 +17,6 @@
     TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     PERFORMANCE OF THIS SOFTWARE.
 */
-#ifndef INI_H
-#define INI_H
-
 #include <stdio.h>
 #include <stdbool.h>
 #include <string.h>
@@ -108,5 +105,3 @@ static bool iniparse(inifile_t* inifile, inientry_t* entry)
     inifile->file = NULL;
     return false;
 }
-
-#endif /* INI_H */
index 3124f0be7ffae004cbb1d80d5647f69dad534449..af56db5c17bd9bf522db454287218b0dc9a9a1a2 100644 (file)
@@ -1,7 +1,22 @@
-/**
-  @brief Collection of useful C types and functions.
-  @author Michael D. Lowis
-  @license BSD 2-clause License
+/*
+    Setup common ANSI C environment with common includes, functions, typedefs, 
+    and macros.
+    
+    Copyright 2017, Michael D. Lowis
+    
+    Permission to use, copy, modify, and/or 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.
 */
 
 /* Standard Macros and Types */
@@ -19,8 +34,8 @@
 #include <stdarg.h>
 #include <string.h>
 
-/* Type Definitions
- *****************************************************************************/
+/* Type and Variable Definitions
+ ******************************************************************************/
 typedef unsigned short ushort;
 typedef unsigned char uchar;
 typedef unsigned long ulong;
@@ -42,81 +57,106 @@ typedef int64_t int64;
 typedef uintptr_t uintptr;
 typedef intptr_t  intptr;
 
-/* Generic Death Function
- *****************************************************************************/
-static void die(const char* msgfmt, ...) {
+/* This variable contains the value of argv[0] so that it can be referenced
+ * again once the option parsing is done. This variable must be defined by the
+ * program.
+ *
+ * NOTE: Ensure that you define this variable with external linkage (i.e. not
+ * static) */
+extern char* ARGV0;
+
+/* Function Definitions
+ ******************************************************************************/
+/* print a fatal error message and exit the program */
+static void fatal(const char* fmt, ...) {
+    fflush(stdout);
+    if (ARGV0) fprintf(stderr, "%s: ", ARGV0);
     va_list args;
-    va_start(args, msgfmt);
-    #ifdef CLEANUP_HOOK
-    CLEANUP_HOOK();
-    #endif
-    fprintf(stderr, "Error: ");
-    vfprintf(stderr, msgfmt, args);
-    fprintf(stderr, "\n");
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
     va_end(args);
+    if (*fmt && fmt[strlen(fmt)-1] == ':')
+        fprintf(stderr, " %s", strerror(errno));
+    fprintf(stderr, "\n");
     exit(EXIT_FAILURE);
 }
 
-/* Generic Warning Function
- *****************************************************************************/
-static void warn(const char* msgfmt, ...) {
+/* print a warning message to stderr */
+static void warn(const char* fmt, ...) {
     va_list args;
-    va_start(args, msgfmt);
-    fprintf(stderr, "Warning: ");
-    vfprintf(stderr, msgfmt, args);
+    va_start(args, fmt);
+    fprintf(stderr, "warning: ");
+    vfprintf(stderr, fmt, args);
     fprintf(stderr, "\n");
     va_end(args);
 }
 
-/* Signal Handling
- *****************************************************************************/
+/* Install a signal handler. Om failure, print a fatal error */
 static void esignal(int sig, void (*func)(int)) {
     errno = 0;
     func  = signal(sig, func);
     if (func == SIG_ERR || errno > 0)
-        die("failed to register signal handler for signal %d", sig);
+        fatal("failed to register signal handler for signal %d", sig);
 }
 
+/* Raise a signal. On failure, print a fatal error. */
 static int eraise(int sig) {
     int ret;
     if ((ret = raise(sig)) != 0)
-        die("failed to raise signal %d", sig);
+        fatal("failed to raise signal %d", sig);
     return ret;
 }
 
-/* Dynamic Allocation
*****************************************************************************/
+/* Allocate a zero-initialized block of memory on the heap. On failure, print a 
  fatal error. */
 static void* ecalloc(size_t num, size_t size) {
     void* ret;
     if (NULL == (ret = calloc(num,size)))
-        die("out of memory");
+        fatal("out of memory");
     return ret;
 }
 
+/* Allocate an uninitialized block of memory on the heap. On failure, print a 
+   fatal error. */
 static void* emalloc(size_t size) {
     void* ret;
     if (NULL == (ret = malloc(size)))
-        die("out of memory");
+        fatal("out of memory");
     return ret;
 }
 
+/* Resize a heap allocated block. On failure, print a fatal error. */
 static void* erealloc(void* ptr, size_t size) {
     void* ret;
     if (NULL == (ret = realloc(ptr,size)))
-        die("out of memory");
+        fatal("out of memory");
     return ret;
 }
 
-/* File Handling
- *****************************************************************************/
+/* Print to a malloced string. On failure, print a fatal error. */
+static char* smprintf(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    int strsz = vsnprintf(NULL, 0, fmt, args);
+    va_end(args);
+    char* str = emalloc(strsz+1);
+    va_start(args, fmt);
+    vsnprintf(str, strsz+1, fmt, args);
+    va_end(args);
+    return str;
+}
+
+/* Open the file with the specified mode. On failure, print a fatal error. */
 static FILE* efopen(const char* filename, const char* mode) {
     FILE* file;
     errno = 0;
     if (NULL == (file = fopen(filename, mode)) || errno != 0)
-        die("failed to open file: %s", filename);
+        fatal("failed to open file: %s", filename);
     return file;
 }
 
+/* Read an entire line of data from the provided file into a malloced string. On
+   failure, print a fatal error */
 static char* efreadline(FILE* input) {
     size_t size  = 8;
     size_t index = 0;
@@ -140,8 +180,8 @@ static char* efreadline(FILE* input) {
     return str;
 }
 
-/* String Handling
*****************************************************************************/
+/* Allocate a duplicate copy of the string on the heap. Signal fatal error on
  memory allocation failure. */
 static char* estrdup(const char *s) {
     char* ns = (char*)emalloc(strlen(s) + 1);
     strcpy(ns,s);
@@ -149,11 +189,11 @@ static char* estrdup(const char *s) {
 }
 
 /* Option Parsing
- *
+ *******************************************************************************
  * This following macros implement a simple POSIX-style option parsing strategy.
  * They are heavily influenced and inspired by the arg.h file from suckless.org
  * (http://git.suckless.org/libsl/tree/arg.h). That file is in turn inspired by
- * the corresponding macros defined in plan9.
+ * the corresponding macros defined in plan9 libc.h.
  *
  * The interface assumes that the main function will have the following
  * prototype:
@@ -173,14 +213,6 @@ static char* estrdup(const char *s) {
  * }
  */
 
-/* This variable contains the value of argv[0] so that it can be referenced
- * again once the option parsing is done. This variable must be defined by the
- * program.
- *
- * NOTE: Ensure that you define this variable with external linkage (i.e. not
- * static) */
-extern char* ARGV0;
-
 /* This is a helper function used by the following macros to parse the next
  * option from the command line. */
 static inline char* _getopt_(int* p_argc, char*** p_argv) {
@@ -247,8 +279,8 @@ static inline char* _getopt_(int* p_argc, char*** p_argv) {
 #define OPTLONG \
     case '-'
 
-/* Error Handling
- *****************************************************************************/
+/* Error Handling Macros
+ ******************************************************************************/
 #ifdef NDEBUG
     #define debug(msg, ...) \
         ((void)0)
@@ -269,8 +301,8 @@ static inline char* _getopt_(int* p_argc, char*** p_argv) {
 #define sentinel(msg, ...) \
     { print_error(msg, ##__VA_ARGS__); errno=0; goto error; }
 
-/* Miscellaneous
- *****************************************************************************/
+/* Miscellaneous Macros
+ ******************************************************************************/
 #ifndef nelem
     #define nelem(x) \
         (sizeof(x)/sizeof((x)[0]))
index 4e941c460a446c797e008087562852175a92af4b..6b92ea55d689fc61ab355a93b3b6e68d3444bfe7 100644 (file)
@@ -2,6 +2,8 @@
 #include <stdc.h>
 #include <time.h>
 
+char* ARGV0;
+
 int main(int argc, char** argv)
 {
     (void)argc;