Initial import, non-compilable, stripped down m1d/common.[ch] version. m1d
authorshort <>
Sun, 16 Jan 2000 16:11:42 +0000 (16:11 +0000)
committershort <>
Sun, 16 Jan 2000 16:11:42 +0000 (16:11 +0000)
vblib.c [new file with mode: 0644]
vblib.h [new file with mode: 0644]

diff --git a/vblib.c b/vblib.c
new file mode 100644 (file)
index 0000000..61017c7
--- /dev/null
+++ b/vblib.c
@@ -0,0 +1,985 @@
+#include <stdlib.h>
+#include <syslog.h>
+#include <signal.h>
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <netinet/in.h>
+#include <linux/un.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <slang.h>
+#include <time.h>
+#include <sys/time.h>
+#include <limits.h>
+#include <sys/file.h>
+#include <sys/resource.h>
+#include <fnmatch.h>
+#include <setjmp.h>
+#include <sys/socket.h>
+#include <stddef.h>
+#include <pthread.h>
+
+#include "common.h"
+#include "dataserv.h"
+
+const int safesigs[]={SIGQUIT,SIGINT,SIGTERM,SIGIOT,SIGALRM,-1}; //SIGCHLD->childsignal anyway
+char vbnexact;
+const char *upsc_sshpath="/usr/bin/ssh"; /* upsetupconn()... */
+const char *upsc_dstport=DS_PORT;
+
+void chk(const void *p)
+{
+       vbsanity();
+       if (p) return;
+       FATAL(CRIT,"NULL-check failure, memory exhausted? FATAL: %m");
+}
+
+#ifndef NDEBUG
+static void *vbchecknull=NULL;
+static struct varbuf *vbcheckhead=(struct varbuf *)&vbchecknull;
+static unsigned vbchecknum;
+#ifdef FATALSIG_INSANE
+static char vbcheckno;
+#else
+#define vbcheckno (0)
+#endif
+pthread_mutex_t vbcheckmx=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
+static void vbchecklock  (void)
+{ if (pthread_mutex_lock  (&vbcheckmx)) FATAL(CRIT,"Mutex ""lock on vbcheck mx"); }
+static void vbcheckunlock(void)
+{ if (pthread_mutex_unlock(&vbcheckmx)) FATAL(CRIT,"Mutex unlock on vbcheck mx"); }
+
+static char vbchecklist(struct varbuf *vb)
+{
+struct varbuf *vbs;
+unsigned tot=0;
+
+       vbchecklock();
+       assert(!vbchecknull);
+       assert(!!vb);
+       for (vbs=vbcheckhead;vbs;vbs=vbs->checknext,tot++)
+               if (vb==vbs) break;
+       if (!vbs) {
+               vbcheckunlock();
+               return(0);
+               }
+       assert(vb->checknext);
+       while (tot++,(vbs=vbs->checknext)!=vbchecknull) assert(vb!=vbs);
+       assert(tot==vbchecknum+1);
+       vbcheckunlock();
+       return(1);
+}
+
+void vbcheck(struct varbuf *vb)
+{
+struct varbufnode *vbn;
+char *s;
+volatile char touch;
+
+       if (vbcheckno) return; vbchecklock();
+       assert(vbchecklist(vb));
+       if (vb->done) assert(!!vb->f);
+       if (vb->free) assert(!!vb->l);
+       assert((!vb->f)==(!vb->f));
+       for (vbn=vb->f;vbn;vbn=vbn->next) {
+               if (vbn==vb->f) assert(vb->done<=vbn->size);
+               if (vbn==vb->l) assert(vb->free<=vbn->size);
+               for (s=vbn->buf;s<vbn->buf+vbn->size;s++) touch=*s;
+               }
+       vbcheckunlock();
+}
+
+void vbsanity(void)
+{
+struct varbuf *vb;
+       dbg("vbsanity()\n");
+       if (vbcheckno) return; vbchecklock();
+       assert(!vbchecknull);
+       for (vb=vbcheckhead;vb!=(struct varbuf *)&vbchecknull;vb=vb->checknext) vbcheck(vb);
+       vbcheckunlock();
+}
+#endif
+
+#ifdef VBDEBUG
+void vbdebug(struct varbuf *vb,const char *msg)
+{
+struct varbufnode *vbn;
+       fprintf(stderr,"vbdebug(%s): vb=%p",msg,vb);
+       vbcheck(vb);
+       if (!vb) {
+               fprintf(stderr,"\n");
+               return;
+               }
+       fprintf(stderr,", first=%p, last=%p, done=%u, free=%u\n",vb->f,vb->l,vb->done,vb->free);
+       for (vbn=vb->f;vbn;vbn=vbn->next) {
+size_t i;
+               fprintf(stderr," *VBN: %p: size=%u, buf:",vbn,vbn->size);
+               for (i=0;i<vbn->size;i++) {
+char c=vbn->buf[i];
+                       if (isprint(c)) fprintf(stderr," '%c'",c);
+                       else fprintf(stderr," %02x",(unsigned char)c);
+                       }
+               fprintf(stderr,"\n");
+               }
+       fprintf(stderr,"vbdebug(%s): finishing...\n",msg);
+}
+#endif
+
+struct varbufnode *vbnnew(size_t sugsize)
+{
+struct varbufnode *r;
+       if (!vbnexact && sugsize<VB_DEFSIZE) sugsize=VB_DEFSIZE;
+       chk(r=malloc(sizeof(*r)+sugsize));
+       r->next=NULL;
+       r->size=sugsize;
+       return(r);
+}
+
+void vbgrow(struct varbuf *vb,size_t sugsize)
+{
+struct varbufnode *vbn;
+       vbdebug(vb,"vbgrow");
+       assert(!vb->free);
+       if (!vbnexact) {
+               if (vb->l && vb->l->size>sugsize) sugsize=vb->l->size;
+               if (sugsize*2<=VB_MAXSIZE) sugsize*=2;
+               else if (sugsize<VB_MAXSIZE) sugsize=VB_MAXSIZE;
+               }
+       vbn=vbnnew(sugsize);
+       if (vb->l) vb->l->next=vbn;
+       else vb->f=vbn;
+       vb->l=vbn;
+       vb->free=vbn->size;
+}
+
+void vbinit(struct varbuf *vb)
+{
+#ifndef NDEBUG
+       if (!vbcheckno) assert(!vbchecklist(vb));
+#endif
+       bzero(vb,sizeof(*vb));
+#ifndef NDEBUG
+       vbchecklock();
+       vb->checknext=vbcheckhead;
+       vbcheckhead=vb;
+       vbchecknum++;
+       vbcheckunlock();
+#endif
+       vbcheck(vb);
+}
+
+struct varbufnode *vbremone(struct varbuf *vb)
+{
+struct varbufnode *r;
+       vbdebug(vb,"vbremone");
+       assert(vb->f);
+       r=vb->f->next;
+       free(vb->f);
+       vb->done=0;
+       if (!(vb->f=r)) {
+               vb->l=NULL;
+               vb->free=0;
+               }
+       return(r);
+}
+
+void vbclear(struct varbuf *vb)
+{
+       vbdebug(vb,"vbclear");
+       while (vb->f) vbremone(vb);
+}
+
+void vbrem(struct varbuf *vb)
+{
+#ifndef NDEBUG
+struct varbuf **vbp;
+#endif
+
+       vbdebug(vb,"vbrem");
+       vbclear(vb);
+#ifndef NDEBUG
+       vbchecklock();
+       assert(vbchecknum>0);
+       for (vbp=&vbcheckhead;*vbp;vbp=&(*vbp)->checknext)
+               if (*vbp==vb) break;
+       *vbp=vb->checknext;
+       vbchecknum--;
+       bzero(vb,sizeof(*vb));
+       vbcheckunlock();
+#endif
+}
+
+size_t vbsize(struct varbuf *vb,size_t maxsize)
+{
+size_t size=0;
+struct varbufnode *vbn=vb->f;
+
+       vbdebug(vb,"vbsize");
+       while (vbn && (!maxsize || size<maxsize)) {
+               size+=VBNSIZE(vb,vbn);
+               vbn=vbn->next;
+               }
+       return(size);
+}
+
+#define GENVARBUFC(argmid) \
+       void vbput##argmid(struct varbuf *vb,const argmid arg) \
+       { vbwrite(vb,&arg,sizeof(arg)); } \
+       char vbget##argmid(struct varbuf *vb,argmid *argp) \
+       { if (sizeof(*argp)>1 && !VBCHKSIZE(vb,sizeof(*argp))) return(0); \
+       return(vbread(vb,argp,sizeof(*argp))); }
+
+#ifndef INLINE_PUTGETCHAR
+GENVARBUFC(char)
+#endif
+GENVARBUFC(short)
+GENVARBUFC(int)
+
+#undef GENVARBUFC
+
+void vbwrite(struct varbuf *vb,const void *buf,size_t count)
+{
+size_t now;
+
+       vbdebug(vb,"vbwrite");
+       if (!count) return;
+       if (vb->free) {
+               assert(vb->l);
+               memcpy(vb->l->buf+VBNSIZEL(vb,vb->l),buf,(now=min(vb->free,count)));
+               count-=now;
+               vb->free-=now;
+               if (!count) return;
+               buf+=now;
+               }
+       vbgrow(vb,count);
+       assert(vb->free>=count);
+       assert(vb->l&&vb->l->size==vb->free);
+       memcpy(vb->l->buf,buf,count);
+       vb->free-=count;
+       assert(vb->free>=0);
+}
+
+extern size_t vbputstring(struct varbuf *vb,const char *s)
+{
+size_t l=strlen(s);
+       vbwrite(vb,s,l);
+       return(l);
+}
+
+ssize_t vbwritefd(struct varbuf *vb,int fd)
+{
+ssize_t now,got=0;
+
+       vbdebug(vb,"vbwritefd");
+       for (;;) {
+               if (!vb->free) vbgrow(vb,0);
+               now=read(fd,vb->l->buf+vb->l->size-vb->free,vb->free);
+               dbg("vbwritefd: now=%d\n",now);
+               if (now<0) {
+                       if (errno==EAGAIN) break;
+                       return(now);
+                       }
+               if (!now) {
+                       errno=ENODATA;
+                       return(-1);
+                       }
+               vb->free-=now;
+               assert(vb->free>=0);
+       }
+       return(got);
+}
+
+size_t vbpeek(struct varbuf *vb,ssize_t offs,void *buf,size_t count)
+{
+size_t got=0,now,size;
+char doread;
+struct varbufnode *vbn=vb->f;
+
+       vbdebug(vb,"vbpeek");
+       if ((doread=(offs==-1))) offs=0;
+       offs+=vb->done;
+       while (vbn && count) {
+               size=VBNSIZEL(vb,vbn);
+               if (offs<size) {
+                       memcpy(buf,vbn->buf+offs,(now=min(count,size-offs)));
+                       buf+=now;
+                       count-=now;
+                       got+=now;
+                       offs+=now;
+                       if (doread) {
+                               assert(vbn==vb->f);
+                               vb->done+=now;
+                               }
+                       }
+               offs-=size;
+               if (!VBNSIZE(vb,vb->f)) {
+                       assert(doread);
+                       vbremone(vb);
+                       vbn=vb->f;
+                       }
+               else vbn=vbn->next;
+               }
+       return(got);
+}
+
+ssize_t vbchrn(struct varbuf *vb,ssize_t offs,char c,char dir)
+{
+struct vbl {
+       struct vbl *next;
+       struct varbufnode *vbn;
+       } *vbl=NULL,*vbl2;
+struct varbufnode *vbn;
+ssize_t distoffs=0,size=vbsize(vb,0);
+
+       assert(!!dir);
+       if (offs==-1 || offs>=size) {
+               if (dir>0) return(-1);
+               else offs=size-1;
+               }
+       if (offs<0) return(-1);
+       vbn=vb->f;
+       offs+=vb->done;
+       distoffs=-vb->done;
+       while (vbn && offs>=vbn->size) {
+               if (dir<0) {
+                       chk(vbl2=alloca(sizeof(*vbl2)));
+                       vbl2->next=vbl;
+                       vbl2->vbn=vbn;
+                       vbl=vbl2;
+                       }
+               offs-=vbn->size;
+               assert(offs>=0);
+               distoffs+=vbn->size;
+               vbn=vbn->next;
+               }
+       if (dir<0) for (;;) {
+               if (vbn && offs<VBNSIZEL(vb,vbn)) {
+ssize_t start=VBNSTART(vb,vbn); // FIXME: not really - GCC bug! (size_t crashes)
+                       dbg("seeking back... start=%u,offs=%d,vbn->size=%u\n",start,offs,vbn->size);
+                       while (offs>=start&&vbn->buf[offs]!=c) offs--;
+                       if (offs>=start) return(distoffs+offs);
+                       }
+               if (!vbl) break;
+               vbn=vbl->vbn;
+               vbl=vbl->next;
+               distoffs-=vbn->size;
+               offs=vbn->size-1;
+               assert(offs>=0);
+               }
+       if (dir>0) while (vbn) {
+size_t size=VBNSIZEL(vb,vbn);
+char *s;
+               dbg("vbn=%p,offs=%d,size=%d\n",vbn,offs,size);
+               assert(offs<=size);
+               if ((s=memchr(vbn->buf+offs,c,size-offs)))
+                       return(distoffs+(s-vbn->buf));
+               distoffs+=vbn->size;
+               vbn=vbn->next;
+               offs=0;
+               }
+       return(-1);
+}
+
+ssize_t vbreadfd(struct varbuf *vb,int fd)
+{
+ssize_t now,got=0;
+
+       vbdebug(vb,"vbreadfd");
+       dbg("entering vbreadfd(fd=%d)\n",fd);
+       while (vb->f) {
+size_t size=VBNSIZE(vb,vb->f);
+               now=write(fd,vb->f->buf+vb->done,size);
+               dbg("vbreadfd: now=%d\n",now);
+               if (now<0 && errno!=EAGAIN) return(now);
+               if (now<=0) return(got);
+               vb->done+=now;
+               assert(vb->done<=size);
+               got+=now;
+               if (!VBNSIZE(vb,vb->f))
+                       vbremone(vb);
+               }
+       return(got);
+}
+
+char quiet_null;
+
+static void fixupnulls(char *s,size_t len,const char *fname)
+{
+unsigned tot=0;
+char *d;
+
+       for (d=s;(d=memchr(d,'\0',s+len-d));) { *d++=' '; tot++; }
+       if (tot) logmsg((quiet_null?MYLOG_DEBUG:MYLOG_ERR),
+               "%s() replaced %u '\\0's by ' ' in: %.*s",fname,tot,(int)len,s);
+}
+
+char *vbgetline(struct varbuf *vb,char term)
+{
+size_t len,r;
+char *s;
+
+       if (!(len=vbchrn(vb,0,term,1)+1)) return(NULL);
+       assert(len>0);
+       chk(s=malloc(len));
+       r=vbread(vb,s,len); assert(r==len);
+       assert(s[len-1]==term);
+       s[len-1]='\0';
+       fixupnulls(s,len-1,"vbgetline");
+       return(s);
+}
+
+size_t chkvsprintf(char **sp,const char *fmt,va_list ap)
+{
+size_t bufsize=VB_DEFSIZE;
+int i;
+
+       for (*sp=NULL;;) {
+               chk(*sp=realloc(*sp,bufsize));
+               i=vsnprintf(*sp,bufsize,fmt,ap);
+               dbg("chkvsprintf: bufsize=%u,i=%d,fmt:%s\n",bufsize,i,fmt);
+               if (i>=0&&i<bufsize) break;
+               bufsize*=2;
+               }
+       assert(i>=0);
+       return(i);
+}
+
+size_t vbvprintf(struct varbuf *vb,const char *fmt,va_list ap,char remlf)
+{
+char *buf=NULL;
+size_t len;
+
+       len=chkvsprintf(&buf,fmt,ap);
+       if (remlf) {
+char *s,c;
+               for (s=buf;(c=*s);s++) {
+                       if (c<0 || (c>=' '&&c!='\\')) {
+                               vbputchar(vb,c);
+                               continue;
+                               }
+                       vbputchar(vb,'\\');
+                       switch (c) {
+                               case '\n'     : vbputchar(vb,'n');      break;
+                               case '\r'     : vbputchar(vb,'r');      break;
+                               case  1 ...  9: //FALLTHRU
+                               case 11 ... 12: //FALLTHRU
+                               case 14 ... 31: vbprintf(vb,"x%02X",c); break;
+                               case '\\'    :  vbputchar(vb,'\\');     break;
+                               default: assert(0);
+                               }
+                       }
+               }
+       else vbwrite(vb,buf,len);
+       free(buf);
+       return(len);
+}
+
+size_t vbprintf(struct varbuf *vb,const char *fmt,...) //stub
+{
+va_list ap;
+size_t r;
+
+       va_start(ap,fmt);
+       r=vbvprintf(vb,fmt,ap,0);
+       va_end(ap);
+       return(r);
+}
+
+#ifdef PSTR_16BIT
+#define PSTR_MAX 65535
+#define PSTR_TYPE short
+#else
+#define PSTR_MAX 255
+#define PSTR_TYPE char
+#endif
+
+#define PSTR_PUTLEN2(vb,len,type) vbput##type((vb),(type)(len))
+#define PSTR_PUTLEN1(vb,len,type) PSTR_PUTLEN2(vb,len,type)
+#define PSTR_PUTLEN(vb,len) PSTR_PUTLEN1((vb),(len),PSTR_TYPE)
+
+void vbpstrputstring(struct varbuf *vb,const char *s)
+{
+size_t len=strlen(s);
+       if (len>PSTR_MAX) {
+               LOG(CRIT,"String longer (%u) than PSTRing max (%u)",len,PSTR_MAX);
+               len=PSTR_MAX;
+               dbg("vbpstrputstring-longer than MAX: \"%s\"\n",s);
+               }
+       PSTR_PUTLEN(vb,len);
+       vbwrite(vb,s,len);
+}
+
+size_t vbpstrcopy(struct varbuf *vbd,struct varbuf *vbs,ssize_t len)
+{
+size_t size,was;
+       if (len==-1) len=vbsize(vbs,0);
+       else if ((size=vbsize(vbs,len))<len) len=size;
+       was=len;
+       if (len>PSTR_MAX) {
+               LOG(CRIT,"String longer (%u) than PSTRing max (%u)",len,PSTR_MAX);
+               len=PSTR_MAX;
+               vbdebug(vbs,"vbpstrputstring-longer than MAX");
+               }
+       PSTR_PUTLEN(vbd,len);
+       vbcopy(vbd,vbs,len);
+       if (was!=len) vbdrop(vbs,was-len);
+       return(was);
+}
+
+void vbpstrprintf(struct varbuf *vb,const char *fmt,...)
+{
+va_list ap;
+char buf[PSTR_MAX+1];
+int i;
+
+       va_start(ap,fmt);
+       i=vsnprintf(buf,sizeof(buf),fmt,ap);
+       va_end(ap);
+       if (i==-1) {
+               LOG(CRIT,"Buffer overflow (max=%u) during PSTR printf",PSTR_MAX);
+               i=PSTR_MAX;
+               }
+       assert(i>=0 && i<=PSTR_MAX && !buf[i]);
+       vbpstrputstring(vb,buf);
+}
+
+char *vbpstrread(struct varbuf *vb)
+{
+unsigned PSTR_TYPE len,scan,chgd=0;
+char *buf;
+size_t r;
+
+       if (!vbpeek(vb,0,&len,sizeof(len))) return(NULL);
+       if (!VBCHKSIZE(vb,1+len)) return(NULL);
+       chk(buf=malloc(len+1));
+       vbdrop(vb,sizeof(len));
+       r=vbread(vb,buf,len); assert(r==len);
+       buf[len]='\0';
+       for (scan=0;scan<len;scan++)
+               if (!buf[scan]) {
+                       buf[scan]='?';
+                       chgd++;
+                       }
+       if (chgd)
+               LOG(CRIT,"'\\0's found (%u total) in read PSTR \"%s\", changed to '?'",chgd,buf);
+       return(buf);
+}
+
+size_t vbcopy(struct varbuf *vbd,struct varbuf *vbs,ssize_t count)
+{
+size_t now,got,r;
+
+       vbdebug(vbd,"vbcopy-dest");
+       vbdebug(vbs,"vbcopy-src");
+       dbg("vbcopy-count=%d\n",count);
+       got=vbsize(vbs,(count==-1?0:count));
+       if (count==-1 || count>got) count=got;
+       else got=count;
+       dbg("got=%u, vbd->free=%u, count=%d\n",got,vbd->free,count);
+       if (!count) return(got);
+       if (vbd->free) {
+               dbg("vbd->free=%d path\n",vbd->free);
+               vbdebug(vbd,"vbd->free-s:vbd");
+               assert(vbd->f && vbd->l);
+               r=vbread(vbs,vbd->l->buf+VBNSIZEL(vbd,vbd->l),(now=min(count,vbd->free))); assert(r==now);
+               dbg("now=%u,vbd->free=%u,count=%u\n",now,vbd->free,count);
+               vbd->free-=now;
+               count-=now;
+               vbdebug(vbd,"vbd->free-e:vbd");
+               if (!count) return(got);
+               assert(!vbd->free);
+               }
+       dbg("vbs->done=%u\n",vbs->done);
+       assert(!vbd->free);
+       assert(!VBEMPTY(vbs));
+       if (vbs->done) {
+               dbg("vbs->done=%d path\n",vbs->done);
+               vbdebug(vbs,"vbs->done-s:vbs");
+               vbdebug(vbd,"vbs->done-s:vbd");
+               vbnexact=1;
+               vbgrow(vbd,(now=min(count,VBNSIZE(vbs,vbs->f))));
+               vbnexact=0;
+               assert(vbd->l && vbd->l->size==now && vbd->free==now);
+               r=vbread(vbs,vbd->l->buf,now); assert(r==now);
+               vbd->free=0;
+               count-=now;
+               assert(count>=0);
+               dbg("in vbs->done: count=%d, now=%u\n",count,now);
+               vbdebug(vbs,"vbs->done-e:vbs");
+               vbdebug(vbd,"vbs->done-e:vbd");
+               if (!count) return(got);
+               }
+       assert(!vbs->done);
+       vbdebug(vbs,"relink:vbs");
+       vbdebug(vbd,"relink:vbd");
+       while (count && VBNSIZEL(vbs,vbs->f)<=count) {
+struct varbufnode *vbn=vbs->f;
+               assert(!vbd->free);
+               if (!(vbs->f=vbn->next)) {
+                       vbs->l=NULL;
+                       count+=(vbd->free=vbs->free);
+                       vbs->free=0;
+                       }
+               count-=vbn->size;
+               if (vbd->l) {
+                       vbd->l->next=vbn;
+                       vbd->l=vbn;
+                       }
+               else {
+                       assert(!vbd->f);
+                       vbd->f=vbd->l=vbn;
+                       }
+               vbn->next=NULL;
+               }
+       if (!count) return(got);
+       assert(!vbd->free);
+       vbdebug(vbs,"final:vbs");
+       vbdebug(vbd,"final:vbd");
+       vbgrow(vbd,count);
+       assert(vbd->l && vbd->l->size>=count && vbd->free==vbd->l->size);
+       vbread(vbs,vbd->l->buf,count);
+       vbd->free-=count;
+       assert(vbd->free>=0);
+       return(got);
+}
+
+unsigned short vbxsum(struct varbuf *vb)
+{
+unsigned short xsum=0;
+size_t offs;
+struct varbufnode *vbn;
+
+       vbdebug(vb,"vbxsum");
+       vbn=vb->f;
+       offs=vb->done;
+       while (vbn) {
+size_t size=VBNSIZEL(vb,vbn);
+               assert(offs<size);
+               xsum+=(unsigned char)vbn->buf[offs];
+               if (++offs>=size) {
+                       vbn=vbn->next;
+                       offs=0;
+                       }
+               }
+       dbg("vbxsum=%u\n",(unsigned)xsum);
+       return(xsum);
+}
+
+char vbremlast(struct varbuf *vb)
+{
+struct varbufnode *vbn;
+
+       vbdebug(vb,"vbremlast");
+       if (VBEMPTY(vb)) return(0);
+       assert(vb->l&&vb->free<=vb->l->size);
+       if (vb->free<vb->l->size) {
+               vb->free++;
+               vbdebug(vb,"vbremlast-stdend");
+               return(1);
+               }
+       assert(vb->f!=vb->l);
+       for (vbn=vb->f;vbn->next!=vb->l;vbn=vbn->next)
+               assert(vbn->next);
+       vbn->next=NULL;
+       free(vb->l);
+       vb->l=vbn;
+       assert(vb->l->size);
+       vb->free=1;
+       vbdebug(vb,"vbremlast-blasting-end");
+       return(1);
+}
+
+void vbdrop(struct varbuf *vb,size_t len)
+{
+struct varbufnode *vbn;
+
+       assert(VBCHKSIZE(vb,len));
+       vb->done+=len;
+       while (vb->f&&vb->done>=VBNSIZEL(vb,vb->f)) {
+               vb->done-=VBNSIZEL(vb,vb->f);
+               vbn=vb->f;
+               if (!(vb->f=vbn->next)) {
+                       assert(vbn==vb->l);
+                       vb->l=NULL;
+                       vb->free=0;
+                       }
+               free(vbn);
+               }
+       if (!vb->f) assert(!vb->done&&!vb->free&&!vb->l);
+}
+
+void vbgetlinef(struct varbuf *vb,FILE *f)
+{
+char buf[LOGF_FGETS_BUF],*s;
+
+       dbg("vbgetlinef(), tell=0x%lx\n",ftell(f));
+       for (;;) {
+               if (!fgets(buf,sizeof(buf),f)) {
+                       dbg("vbgetlinef: fgets=NULL\n");
+                       if (feof(f)) return;
+                       FATAL(ERR,"linereading fail: %m");
+                       }
+               dbg("vbgetlinef: fgets: %s\n",buf);
+               if ((s=strchr(buf,'\n'))) break;
+               vbputstring(vb,buf);
+               }
+       vbwrite(vb,buf,s-buf);
+       dbg("vbgetlinef(f), ftell=0x%lx\n",ftell(f));
+}
+
+ssize_t vbcopyline(struct varbuf *vbd,struct varbuf *vbs)
+{
+ssize_t len,r;
+       if ((len=vbchrn(vbs,0,'\n',1))==-1) return(-1);
+       r=vbcopy(vbd,vbs,len); assert(r==len);
+       vbdrop(vbs,1);
+       return(len);
+}
+
+char vbdropline(struct varbuf *vb)
+{
+ssize_t len;
+       if ((len=vbchrn(vb,0,'\n',1))==-1) return(0);
+       vbdrop(vb,len+1);
+       return(1);
+}
+
+char *vbmemorize(struct varbuf *vb,unsigned flg,size_t *sizep)
+{
+ssize_t len=vbsize(vb,0),r;
+char *s;
+       if (sizep) *sizep=len;
+       chk(s=malloc(len+!!(flg&VBMEM_ZERO)));
+       r=vbpeek(vb,(flg&VBMEM_REM?-1:0),s,len); assert(r==len);
+       if (flg&VBMEM_ZERO) {
+                       s[len]='\0';
+               fixupnulls(s,len,"vbmemorize");
+               }
+       if (flg&VBMEM_REM) assert(VBEMPTY(vb));
+       return(s);
+}
+
+char *vbstringify(struct varbuf *vb,char rem)
+{ return vbmemorize(vb,VBMEM_ZERO|(rem?VBMEM_REM:0),NULL); }
+
+const char *signames[]={
+       "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "IOT", "BUS", "FPE", "KILL",
+       "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM", "STKFLT", "CHLD", "CONT",
+       "STOP", "TSTP", "TTIN", "TTOU", "URG", "XCPU", "XFSZ", "VTALRM", "PROF",
+       "WINCH", "IO", "PWR", "UNUSED" };
+
+void abortsignal(int signo)
+{ //no reinstall! (deadlock!)
+#ifdef FATALSIG_INSANE
+       vbcheckno=1;
+#endif
+       signal(signo,SIG_DFL);
+       dbg("Got signal %d\n",signo);
+       exit(EXIT_FAILURE);
+}
+
+struct varbuf *chat_vbout;
+int chat_cmdpar;
+char *chat_cmdpars[CHAT_CMD_MAXPARS];
+
+static void chatfn_help(void);
+
+static const struct chat_cmdtab  chat_cmdint[]={
+       {"help"    ,0,chatfn_help    ,"This help"},
+       {"quit"    ,0,chatfn_quit    ,"Close connection"},
+       {"exit"    ,0,chatfn_quit    ,"Close connection"},
+};
+
+static void chatfn_help(void)
+{
+int i;
+const struct chat_cmdtab *cmd,*cmdt;
+
+       vbputstring(chat_vbout,"000 Available commands:\n");
+       cmdt=chat_cmdtable;
+       for (i=0;i<NELEM(chat_cmdint);) {
+               if (cmdt->name) cmd=cmdt++;
+               else cmd=&chat_cmdint[i++];
+               vbprintf(chat_vbout,"000 %-10s[%d] - %s\n",cmd->name,(int)cmd->npars,cmd->help);
+               }
+       vbputstring(chat_vbout,"102 Help end.\n");
+}
+
+static inline void chat_parsepars(char *s)
+{
+char c,*d,quote;
+
+       chat_cmdpar=0;
+       if (*s) for (*s++='\0';*s&&isspace(*s);s++);
+       for (c=*s;c&&chat_cmdpar<CHAT_CMD_MAXPARS;chat_cmdpar++) {
+               quote=0;
+               for (chat_cmdpars[chat_cmdpar]=d=s;*s&&(quote||(!quote&&*s!=','));s++) {
+                       if (*s=='"'||*s=='\'') {
+                               if (quote==*s) { quote=0; continue; }
+                               if (!quote) { quote=*s; continue; }
+                               }
+                       if (*s=='\\'&&s[1]) s++;
+                       *d++=*s;
+                       }
+               c=*s++; *d='\0';
+               }
+}
+
+void chat_proccmd(const char *who,char *buf)
+{
+char *s,*cmds;
+int i;
+const struct chat_cmdtab *cmd,*cmdt;
+
+       for (cmds=buf;*cmds&&isspace(*cmds);cmds++);
+       for (s=cmds;*s&&!isspace(*s);s++);
+       if (s==cmds) {
+               vbputstring(chat_vbout,"104 Empty command.\n");
+               return;
+               }
+       chat_parsepars(s);
+       cmdt=chat_cmdtable;
+       for (i=0;i<NELEM(chat_cmdint);) {
+               if (cmdt->name) cmd=cmdt++;
+               else cmd=&chat_cmdint[i++];
+               assert(cmd->npars<=CHAT_CMD_MAXPARS);
+               if (!strcmp(cmd->name,cmds)) break;
+               }
+       if (i<NELEM(chat_cmdint)) {
+               if (cmd->npars!=chat_cmdpar)
+                       vbprintf(chat_vbout,"205 %d parameter%s found, %d expected!\n",chat_cmdpar,(chat_cmdpar==1?"":"s"),cmd->npars);
+               else {
+                       vbprintf(chat_vbout,"001 Running command: %s\n",cmds);
+                       LOG(DEBUG,"%s is executing user command \"%s\"",who,cmds);
+                       (*cmd->fnc)();
+                       }
+               }
+       else vbprintf(chat_vbout,"206 Unknown command \"%s\"!\n",cmds);
+}
+
+void crfilter(char *sr)
+{
+char *sw;
+       for (sw=sr;*sr;sr++)
+               if (*sr!='\r') *sw++=*sr;
+       *sw='\0';
+}
+
+static void tzchange(const char *tz)
+{
+static char *otz=NULL;
+
+       if (tz) {
+               free(otz);
+               if ((otz=getenv("TZ"))) chk(otz=strdup(otz));
+               setenv("TZ",tz,1);
+               }
+       else {
+               if (otz) {
+                       setenv("TZ",otz,1);
+                       free(otz); otz=NULL;
+                       }
+               else unsetenv("TZ");
+               }
+       tzset();
+}
+
+char *gmctime(time_t tm)
+{
+char *r,*s;
+
+       tzchange("GMT");
+       r=ctime(&tm);
+       tzchange(NULL);
+       if ((s=strchr(r,'\n')))
+               *s='\0';
+       chk(r=strdup(r));
+       return(r);
+}
+
+unsigned char *bitshuffle(unsigned char *dst,unsigned char dstb,const unsigned char *src,unsigned char srcb,size_t bits,char lr)
+{
+unsigned char dstrem,*dstp,srcrem,now;
+const unsigned char *srcp;
+
+       if (!dst) chk(dst=malloc((bits+dstb-1)/dstb));
+       dstrem=0; dstp=dst-1;
+       srcrem=0; srcp=src-1;
+       while (bits) {
+               if (!dstrem) {
+                       *++dstp=0;
+                       dstrem=dstb;
+                       }
+               if (!srcrem) {
+                       srcp++;
+                       srcrem=srcb;
+                       }
+               dbg("dstrem=%u,srcrem=%u,bits=%u\n",dstrem,srcrem,bits);
+               assert(dstrem&&srcrem);
+               now=min(dstrem,srcrem);
+               assert(bits>=now);
+               dbg("1:*dstp=0x%02x,*srcp=0x%02x,dstrem=%u,srcrem=%u,now=%u\n",*dstp,*srcp,dstrem,srcrem,now);
+               *dstp|=((*srcp>>(lr?srcrem-now:srcb-srcrem))&((1U<<now)-1))<<(lr?dstrem-now:dstb-dstrem);
+               dstrem-=now;
+               srcrem-=now;
+               bits  -=now;
+               dbg("2:*dstp=0x%02x,*srcp=0x%02x,dstrem=%u,srcrem=%u,now=%u\n",*dstp,*srcp,dstrem,srcrem,now);
+               }
+       return(dst);
+}
+
+char *enbase64(char *dst,const unsigned char *src,size_t bits)
+{
+char *s,*d;
+
+       if (!dst) chk(dst=malloc(((bits+23)/24)*4+1));
+       d=bitshuffle(dst,6,src,8,bits,1); assert(d==dst);
+       d=dst+(bits=(bits+5)/6);
+       for (s=dst;s<d;s++) switch (*s) {
+               case  0 ... 25: *s+='A'- 0; break;
+               case 26 ... 51: *s+='a'-26; break;
+               case 52 ... 61: *s+='0'-52; break;
+               case 62       : *s ='+'   ; break;
+               case 63       : *s ='/'   ; break;
+               default: assert(0);
+               }
+       while (bits++%4) *s++='=';
+       *s='\0';
+       return(dst);
+}
+
+unsigned char *debase64(unsigned char *dst,const char *src,size_t *dstlp)
+{
+size_t srcl,dstl;
+char *src2,*sd;
+const char *s;
+unsigned char *d;
+
+       chk(src2=alloca(strlen(src))); /* +1 not needed */
+       for (sd=src2,s=src;*s;s++) switch (*s) {
+               case 'A' ... 'Z': *sd++=*s-('A'- 0); break;
+               case 'a' ... 'z': *sd++=*s-('a'-26); break;
+               case '0' ... '9': *sd++=*s-('0'-52); break;
+               case '+'        : *sd++=   (    62); break;
+               case '/'        : *sd++=   (    63); break;
+               case '='        :
+                       /* only 0, 1 or 2 '='(s) permitted */
+                       if (!s[1] || (s[1]=='=' && (!s[2] || (s[2]=='=' && !s[3]))))
+                               goto out;
+                       /* FALLTHRU */
+               default: return(NULL);
+               }
+out:
+       srcl=sd-src2; if ((srcl%4)==1) return(NULL);
+       dstl=(srcl*6)/8;
+       if (!dst) chk(dst=malloc(dstl));
+       d=bitshuffle(dst,8,src2,6,dstl*8,1); assert(d==dst);
+       if (dstlp) *dstlp=dstl;
+       return(dst);
+}
diff --git a/vblib.h b/vblib.h
new file mode 100644 (file)
index 0000000..8ee18bc
--- /dev/null
+++ b/vblib.h
@@ -0,0 +1,181 @@
+#ifndef _M1D_COMMON_H
+#define _M1D_COMMON_H 1
+
+#include <string.h>
+#include <ctype.h>
+#include <slang.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/poll.h>
+#include <setjmp.h>
+
+/********************************
+ * Configuration section follows
+ */
+
+//#define PSTR_16BIT
+#define INLINE_PUTGETCHAR
+//#define FATALSIG_INSANE
+
+#define VB_DEFSIZE 256 //>=min of n in vsnprintf()
+#define VB_MAXSIZE 128*1024 //recommended limit, not hard (probably)
+
+#define CHAT_CMD_MAXPARS 10
+
+/*
+ * Configuration section ends
+ ****************************/
+
+#define strncpydst(d,s) strncpy(d,s,sizeof(d))
+#ifdef NDEBUG
+#undef DEBUG
+#endif
+#ifdef DEBUG
+#define dbg(msg...) fprintf(stderr, ##msg)
+#else
+#define dbg(msg...)
+#endif
+
+#ifndef max
+#define max(a,b) ((a)>(b)?(a):(b))
+#endif
+#ifndef min
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif
+#ifndef __NORETURN
+#define __NORETURN __attribute__((__noreturn__))
+#endif
+
+#define NELEM(a) (sizeof((a))/sizeof(*(a)))
+#define XRAWDIGITI(n) ((n)-'0'-((n)>='A'?'A'-('9'+1):0))
+#define XRAWDIGITO(n) ((n)+'0'+((n)>=0xA?'A'-('9'+1):0))
+#define PK __attribute__((packed))
+
+extern const int safesigs[];
+
+struct varbufnode {
+       struct varbufnode *next;
+       size_t size;
+       char buf[0];
+       };
+struct varbuf {
+#ifndef NDEBUG
+       struct varbuf *checknext; //MUST be first in the struct
+#endif
+       struct varbufnode *f,*l;
+       size_t done,free;
+       };
+
+#define VBNSIZEL(vb,vbn) ((vbn)->size-((vb)->l==(vbn)?(vb)->free:0))
+#define VBNSTART(vb,vbn)              ((vb)->f==(vbn)?(vb)->done:0)
+#define VBNSIZE(vb,vbn) (VBNSIZEL((vb),(vbn))-VBNSTART((vb),(vbn)))
+
+#define VBEMPTY(vb) (!(vb)->f || ((vb)->l==(vb)->f&&(vb)->l->size==(vb)->free))
+
+#ifndef NDEBUG
+extern void vbcheck(struct varbuf *vb);
+extern void vbsanity(void);
+#else
+#define vbcheck(vb)
+#define vbsanity()
+#endif
+
+#ifdef VBDEBUG
+extern void vbdebug(struct varbuf *vb,const char *msg);
+#else
+#define vbdebug(vb,msg) vbcheck(vb)
+#endif
+
+struct chat_cmdtab {
+       const char *name;
+       const unsigned char npars;
+       void (*fnc)(void);
+       const char *help;
+};
+
+#define VBMEM_REM  (1<<0)
+#define VBMEM_ZERO (1<<1)
+
+extern void chk(const void *p);
+
+extern struct varbufnode *vbnnew(size_t sugsize);
+extern void vbgrow(struct varbuf *vb,size_t sugsize);
+extern void vbinit(struct varbuf *vb);
+extern struct varbufnode *vbremone(struct varbuf *vb);
+extern void vbclear(struct varbuf *vb);
+extern void vbrem(struct varbuf *vb);
+extern size_t vbsize(struct varbuf *vb,size_t maxsize);
+extern void vbwrite(struct varbuf *vb,const void *buf,size_t count);
+extern size_t vbputstring(struct varbuf *vb,const char *s);
+extern ssize_t vbwritefd(struct varbuf *vb,int fd);
+extern size_t vbpeek(struct varbuf *vb,ssize_t offs,void *buf,size_t count);
+#define vbread(vbp,buf,count) vbpeek(vbp,-1,buf,count)
+extern ssize_t vbchrn(struct varbuf *vb,ssize_t offs,char c,char dir);
+extern ssize_t vbreadfd(struct varbuf *vb,int fd);
+extern char *vbgetline(struct varbuf *vb,char term);
+extern size_t chkvsprintf(char **sp,const char *fmt,va_list ap);
+extern size_t vbvprintf(struct varbuf *vb,const char *fmt,va_list ap,char remlf) __attribute__((format(printf,2,0)));
+extern size_t vbprintf(struct varbuf *vb,const char *fmt,...) __attribute__((format(printf,2,3)));
+extern void vbpstrputstring(struct varbuf *vb,const char *s);
+extern void vbpstrprintf(struct varbuf *vb,const char *fmt,...) __attribute__((format(printf,2,3)));
+extern char *vbpstrread(struct varbuf *vb);
+extern size_t vbcopy(struct varbuf *vbd,struct varbuf *vbs,ssize_t count);
+extern unsigned short vbxsum(struct varbuf *vb);
+extern char vbremlast(struct varbuf *vb);
+extern void vbdrop(struct varbuf *vb,size_t len);
+extern void vbgetlinef(struct varbuf *vb,FILE *f);
+extern ssize_t vbcopyline(struct varbuf *vbd,struct varbuf *vbs);
+extern char vbdropline(struct varbuf *vb);
+extern char *vbmemorize(struct varbuf *vb,unsigned flg,size_t *sizep);
+extern char *vbstringify(struct varbuf *vb,char rem);
+extern void chat_proccmd(const char *who,char *buf);
+extern void crfilter(char *sr);
+extern char *gmctime(time_t tm);
+extern unsigned char *bitshuffle(unsigned char *dst,unsigned char dstb,const unsigned char *src,unsigned char srcb,size_t bits,char lr);
+extern char *enbase64(char *dst,const unsigned char *src,size_t bits);
+extern unsigned char *debase64(unsigned char *dst,const char *src,size_t *dstlp);
+
+extern char vbnexact,quiet_null;
+
+extern struct varbuf *chat_vbout;
+extern int chat_cmdpar;
+extern char *chat_cmdpars[CHAT_CMD_MAXPARS];
+extern const struct chat_cmdtab chat_cmdtable[];
+
+extern const char *signames[];
+extern void abortsignal(int signo);
+
+#define VBCHKSIZE(vb,size) (vbsize((vb),(size))>=(size))
+
+#define GENVARBUFP(argmid) \
+       extern void vbput##argmid(struct varbuf *vb,const argmid arg); \
+       extern char vbget##argmid(struct varbuf *vb,argmid *argp);
+
+#ifndef INLINE_PUTGETCHAR
+GENVARBUFP(char)
+#endif
+GENVARBUFP(short)
+GENVARBUFP(int)
+
+#undef GENVARBUFP
+
+#ifdef INLINE_PUTGETCHAR
+static inline void vbputchar(struct varbuf *vb,const char arg) __attribute__((unused));
+static inline void vbputchar(struct varbuf *vb,const char arg)
+{
+       vbcheck(vb);
+       if (vb->free) vb->l->buf[vb->l->size-(vb->free--)]=arg;
+       else vbwrite(vb,&arg,sizeof(arg));
+}
+
+static inline char vbgetchar(struct varbuf *vb,char *argp) __attribute__((unused));
+static inline char vbgetchar(struct varbuf *vb,char *argp)
+{
+       vbcheck(vb);
+       if (vb->f && vb->done+1<VBNSIZEL(vb,vb->f)) { *argp=vb->f->buf[vb->done++]; return(1); }
+       else return vbread(vb,argp,sizeof(*argp));
+}
+#endif
+
+#endif /* !_M1D_COMMON_H */