started the implementation
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 17 Nov 2019 15:43:41 +0000 (17:43 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 17 Nov 2019 15:43:41 +0000 (17:43 +0200)
libvisor/Makefile
libvisor/include/visor.h
libvisor/src/vilibc.c [new file with mode: 0644]
libvisor/src/vilibc.h [new file with mode: 0644]
libvisor/src/vimpl.h
libvisor/src/viprintf.c [new file with mode: 0644]
libvisor/src/visor.c

index 095481e..757ab30 100644 (file)
@@ -4,7 +4,7 @@ dep = $(obj:.o=.d)
 
 liba = libvisor.a
 
-CFLAGS = -pedantic -Wall -g
+CFLAGS = -pedantic -Wall -g -Iinclude
 
 $(liba): $(obj)
        $(AR) rcs $@ $<
index 165e2b2..4c8d1f1 100644 (file)
@@ -60,6 +60,11 @@ enum vi_motdir {
 
 #define VI_MOTION(d, n) (((long)(n) << 8) | ((long)(d)))
 
+struct vi_alloc {
+       void *(*malloc)(unsigned long);
+       void (*free)(void*);
+       void *(*realloc)(void*, unsigned long); /* can be null, will use malloc/free */
+};
 
 struct vi_fileops {
        void *(*open)(const char *path);
@@ -69,6 +74,7 @@ struct vi_fileops {
        void (*unmap)(void *file);
        long (*read)(void *file, void *buf, long count);
        long (*write)(void *file, void *buf, long count);
+       long (*seek)(void *file, long offs, int whence);
 };
 
 struct vi_ttyops {
@@ -84,9 +90,14 @@ struct vi_ttyops {
        void (*status)(char *s, void *cls);
 };
 
-
-struct visor *vi_init(void);
-void vi_cleanup(struct visor *vi);
+/* Create a new instance of the visor editor.
+ * The alloc argument can be used to provide custom memory allocation
+ * functions. It can be null in a hosted build, or if you set the HAVE_LIBC
+ * preprocessor macro, in which case the standard library allocator will be
+ * used.
+ */
+struct visor *vi_create(struct vi_alloc *mm);
+void vi_destroy(struct visor *vi);
 
 void vi_set_fileops(struct visor *vi, struct vi_fileops *fop);
 
diff --git a/libvisor/src/vilibc.c b/libvisor/src/vilibc.c
new file mode 100644 (file)
index 0000000..6c021b0
--- /dev/null
@@ -0,0 +1,77 @@
+#include "vilibc.h"
+#include "vimpl.h"
+
+#ifndef HAVE_LIBC
+
+void *memset(void *s, int c, unsigned long n)
+{
+       char *p = s;
+       while(n--) *p++ = c;
+       return s;
+}
+
+void *memcpy(void *dest, const void *src, unsigned long n)
+{
+       char *d = dest;
+       const char *s = src;
+       while(n--) *d++ = *s++;
+       return dest;
+}
+
+void *memmove(void *dest, const void *src, unsigned long n)
+{
+       unsigned long i;
+       char *dptr;
+       const char *sptr;
+
+       if(dest <= src) {
+               /* forward copy */
+               dptr = dest;
+               sptr = src;
+               for(i=0; i<n; i++) {
+                       *dptr++ = *sptr++;
+               }
+       } else {
+               /* backwards copy */
+               dptr = (char*)dest + n - 1;
+               sptr = (const char*)src + n - 1;
+               for(i=0; i<n; i++) {
+                       *dptr-- = *sptr--;
+               }
+       }
+
+       return dest;
+}
+
+unsigned long strlen(const char *s)
+{
+       unsigned long len = 0;
+       while(*s++) len++;
+       return len;
+}
+
+int strcmp(const char *s1, const char *s2)
+{
+       while(*s1 && *s1 == *s2) {
+               s1++;
+               s2++;
+       }
+       return *s1 - *s2;
+}
+
+#endif /* !def HAVE_LIBC */
+
+static char errstr_buf[256];
+
+void vi_error(struct visor *vi, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vsnprintf(errstr_buf, sizeof errstr_buf, fmt, ap);
+       va_end(ap);
+
+       if(vi->tty.status) {
+               vi->tty.status(errstr_buf, vi->tty_cls);
+       }
+}
diff --git a/libvisor/src/vilibc.h b/libvisor/src/vilibc.h
new file mode 100644 (file)
index 0000000..881c6ed
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef VISOR_LIBC_H_
+#define VISOR_LIBC_H_
+
+/* XXX let's pretend we don't have a libc to test our own code
+#ifdef __STDC_HOSTED__
+#define HAVE_LIBC
+#endif
+*/
+
+#ifdef HAVE_LIBC
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#else
+
+void *memset(void *s, int c, unsigned long n);
+void *memcpy(void *dest, const void *src, unsigned long n);
+void *memmove(void *dest, const void *src, unsigned long n);
+unsigned long strlen(const char *s);
+int strcmp(const char *s1, const char *s2);
+
+#ifdef __GNUC__
+typedef __builtin_va_list va_list;
+#define va_start(v,l)  __builtin_va_start(v,l)
+#define va_end(v)      __builtin_va_end(v)
+#define va_arg(v,l)    __builtin_va_arg(v,l)
+#else  /* !def __GNUC__ */
+#error "stdargs implementation for this compiler missing (libvisor/src/vilibc.h)"
+#endif
+
+int sprintf(char *buf, const char *fmt, ...);
+int vsprintf(char *buf, const char *fmt, va_list ap);
+int snprintf(char *buf, unsigned long sz, const char *fmt, ...);
+int vsnprintf(char *buf, unsigned long sz, const char *fmt, va_list ap);
+
+#endif /* !HAVE_LIBC */
+
+struct visor;
+void vi_error(struct visor *vi, const char *fmt, ...);
+
+#endif /* VISOR_LIBC_H_ */
index 1e6d201..b2d978f 100644 (file)
@@ -6,6 +6,9 @@
 struct visor {
        struct vi_fileops fop;
        struct vi_buffer *buflist;      /* circular linked list of buffers cur first */
+       struct vi_alloc mm;
+       struct vi_ttyops tty;
+       void *tty_cls;
 };
 
 struct vi_buffer {
diff --git a/libvisor/src/viprintf.c b/libvisor/src/viprintf.c
new file mode 100644 (file)
index 0000000..5f2b312
--- /dev/null
@@ -0,0 +1,249 @@
+#include "vilibc.h"
+
+enum {
+       OUT_BUF
+};
+
+static int intern_printf(int out, char *buf, unsigned long sz, const char *fmt, va_list ap);
+static void bwrite(int out, char *buf, unsigned long buf_sz, char *str, int sz);
+
+int sprintf(char *buf, const char *fmt, ...)
+{
+       int res;
+       va_list ap;
+
+       va_start(ap, fmt);
+       res = intern_printf(OUT_BUF, buf, 0, fmt, ap);
+       va_end(ap);
+       return res;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list ap)
+{
+       return intern_printf(OUT_BUF, buf, 0, fmt, ap);
+}
+
+int snprintf(char *buf, unsigned long sz, const char *fmt, ...)
+{
+       int res;
+       va_list ap;
+
+       va_start(ap, fmt);
+       res = intern_printf(OUT_BUF, buf, sz, fmt, ap);
+       va_end(ap);
+       return res;
+}
+
+int vsnprintf(char *buf, unsigned long sz, const char *fmt, va_list ap)
+{
+       return intern_printf(OUT_BUF, buf, sz, fmt, ap);
+}
+
+/* intern_printf provides all the functionality needed by all the printf
+ * variants.
+ * - buf: optional buffer onto which the formatted results are written. If null
+ *   then the output goes to the terminal through putchar calls. This is used
+ *   by the (v)sprintf variants which write to an array of char.
+ * - sz: optional maximum size of the output, 0 means unlimited. This is used
+ *   by the (v)snprintf variants to avoid buffer overflows.
+ * The rest are obvious, format string and variable argument list.
+ */
+static char *convc = "dioxXucsfeEgGpn%";
+
+#define IS_CONV(c)     strchr(convc, c)
+
+#define BUF(x) ((x) ? (x) + cnum : (x))
+#define SZ(x)  ((x) ? (x) - cnum : (x))
+
+static int intern_printf(int out, char *buf, unsigned long sz, const char *fmt, va_list ap)
+{
+       char conv_buf[32];
+       char *str;
+       int i, slen;
+       const char *fstart = 0;
+
+       /* state */
+       int cnum = 0;
+       int base = 10;
+       int alt = 0;
+       int fwidth = 0;
+       int padc = ' ';
+       int sign = 0;
+       int left_align = 0;
+       int hex_caps = 0;
+       int unsig = 0;
+       int num, unum;
+
+       while(*fmt) {
+               if(*fmt == '%') {
+                       fstart = fmt++;
+                       continue;
+               }
+
+               if(fstart) {
+                       if(IS_CONV(*fmt)) {
+                               switch(*fmt) {
+                               case 'X':
+                                       hex_caps = 1;
+
+                               case 'x':
+                               case 'p':
+                                       base = 16;
+
+                                       if(alt) {
+                                               bwrite(out, BUF(buf), SZ(sz), "0x", 2);
+                                               cnum += 2;
+                                       }
+
+                               case 'u':
+                                       unsig = 1;
+
+                                       if(0) {
+                               case 'o':
+                                               base = 8;
+
+                                               if(alt) {
+                                                       bwrite(out, BUF(buf), SZ(sz), "0", 1);
+                                                       cnum++;
+                                               }
+                                       }
+
+                               case 'd':
+                               case 'i':
+                                       if(unsig) {
+                                               unum = va_arg(ap, unsigned int);
+                                               utoa(unum, conv_buf, base);
+                                       } else {
+                                               num = va_arg(ap, int);
+                                               itoa(num, conv_buf, base);
+                                       }
+                                       if(hex_caps) {
+                                               for(i=0; conv_buf[i]; i++) {
+                                                       conv_buf[i] = toupper(conv_buf[i]);
+                                               }
+                                       }
+
+                                       slen = strlen(conv_buf);
+
+                                       if(left_align) {
+                                               if(!unsig && sign && num >= 0) {
+                                                       bwrite(out, BUF(buf), SZ(sz), "+", 1);
+                                                       cnum++;
+                                               }
+                                               bwrite(out, BUF(buf), SZ(sz), conv_buf, slen);
+                                               cnum += slen;
+                                               padc = ' ';
+                                       }
+                                       for(i=slen; i<fwidth; i++) {
+                                               bwrite(out, BUF(buf), SZ(sz), (char*)&padc, 1);
+                                               cnum++;
+                                       }
+                                       if(!left_align) {
+                                               if(!unsig && sign && num >= 0) {
+                                                       bwrite(out, BUF(buf), SZ(sz), "+", 1);
+                                                       cnum++;
+                                               }
+                                               bwrite(out, BUF(buf), SZ(sz), conv_buf, slen);
+                                               cnum += slen;
+                                       }
+                                       break;
+
+                               case 'c':
+                                       {
+                                               char c = va_arg(ap, int);
+                                               bwrite(out, BUF(buf), SZ(sz), &c, 1);
+                                               cnum++;
+                                       }
+                                       break;
+
+                               case 's':
+                                       str = va_arg(ap, char*);
+                                       slen = strlen(str);
+
+                                       if(left_align) {
+                                               bwrite(out, BUF(buf), SZ(sz), str, slen);
+                                               cnum += slen;
+                                               padc = ' ';
+                                       }
+                                       for(i=slen; i<fwidth; i++) {
+                                               bwrite(out, BUF(buf), SZ(sz), (char*)&padc, 1);
+                                               cnum++;
+                                       }
+                                       if(!left_align) {
+                                               bwrite(out, BUF(buf), SZ(sz), str, slen);
+                                               cnum += slen;
+                                       }
+                                       break;
+
+                               case 'n':
+                                       *va_arg(ap, int*) = cnum;
+                                       break;
+
+                               default:
+                                       break;
+                               }
+
+                               /* restore default conversion state */
+                               base = 10;
+                               alt = 0;
+                               fwidth = 0;
+                               padc = ' ';
+                               hex_caps = 0;
+
+                               fstart = 0;
+                               fmt++;
+                       } else {
+                               switch(*fmt) {
+                               case '#':
+                                       alt = 1;
+                                       break;
+
+                               case '+':
+                                       sign = 1;
+                                       break;
+
+                               case '-':
+                                       left_align = 1;
+                                       break;
+
+                               case 'l':
+                               case 'L':
+                                       break;
+
+                               case '0':
+                                       padc = '0';
+                                       break;
+
+                               default:
+                                       if(isdigit(*fmt)) {
+                                               const char *fw = fmt;
+                                               while(*fmt && isdigit(*fmt)) fmt++;
+
+                                               fwidth = atoi(fw);
+                                               continue;
+                                       }
+                               }
+                               fmt++;
+                       }
+               } else {
+                       bwrite(out, BUF(buf), SZ(sz), (char*)fmt++, 1);
+                       cnum++;
+               }
+       }
+
+       return cnum;
+}
+
+/* bwrite is called by intern_printf to transparently handle writing into a
+ * buffer or to the terminal
+ */
+static void bwrite(int out, char *buf, unsigned long buf_sz, char *str, int sz)
+{
+       int i;
+
+       if(out == OUT_BUF) {
+               if(buf_sz && buf_sz <= sz) sz = buf_sz;
+               buf[sz] = 0;
+               memcpy(buf, str, sz);
+       }
+}
index c6388af..af79b4a 100644 (file)
@@ -1,2 +1,72 @@
+#include "vilibc.h"
 #include "visor.h"
+#include "vimpl.h"
 
+#define vi_malloc(s)   vi->mm.malloc(s)
+#define vi_free(p)             vi->mm.free(p)
+
+#ifdef HAVE_LIBC
+static const struct vi_alloc stdalloc = { malloc, free, realloc };
+#endif
+
+struct visor *vi_create(struct vi_alloc *mm)
+{
+       struct visor *vi;
+
+#ifdef HAVE_LIBC
+       if(!mm) mm = &stdalloc;
+#else
+       if(!mm) return 0;
+#endif
+
+       if(!(vi = mm->malloc(sizeof *vi))) {
+               return 0;
+       }
+       memset(vi, 0, sizeof *vi);
+       vi->mm = *mm;
+
+       return vi;
+}
+
+void vi_destroy(struct visor *vi)
+{
+       while(vi->buflist) {
+               vi_delete_buf(vi, vi->buflist);
+       }
+       vi_free(vi);
+}
+
+void vi_set_fileops(struct visor *vi, struct vi_fileops *fop)
+{
+       vi->fop = *fop;
+}
+
+struct vi_buffer *vi_new_buf(struct visor *vi, const char *path)
+{
+       struct vi_buffer *nb;
+
+       if(!(nb = vi_malloc(sizeof *nb))) {
+               vi_error(vi, "failed to allocate new buffer\n");
+               return 0;
+       }
+       memset(nb, 0, sizeof *nb);
+
+       if(path) {
+               if(vi_buf_read(nb, path) == -1) {
+                       vi_free(nb);
+                       return 0;
+               }
+       }
+
+       if(vi->buflist) {
+               struct vi_buffer *last = vi->buflist->prev;
+               nb->prev = last;
+               nb->next = vi->buflist;
+               last->next = nb;
+               vi->buflist->prev = nb;
+       } else {
+               nb->next = nb->prev = nb;
+               vi->buflist = nb;
+       }
+       return nb;
+}