"Fossies" - the Fresh Open Source Software Archive

Member "rgdbm-2.1.42/contrib/gdbmsql.y" (21 Jun 2007, 28264 Bytes) of package /linux/privat/old/rgdbm-2.1.42.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Bison source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 
    2 /*
    3  * This is a shell interpreter for rgbm/gdbm and the gdbmd daemon. It
    4  * provides a terminal interface to send queries to a remote gdbm
    5  * database with. It uses librgdbm, and might be said to be an example
    6  * application for that library.
    7  *
    8  * Copyright Peter T. Breuer June 2007.
    9  *
   10  * This is released under GNU Public License Version 2 OR LATER.
   11  * There's a copy of GPL_V@ in this directory. This file is metasource,
   12  * however, so exactly what there is to copyright is not exactly clear
   13  * to me. It needs to be processed into C by the PRECCX
   14  * compiler-compiler (search the web), and version 2.57 of preccx is 
   15  * what I used (I'm the author of preccx too, so license issues are not
   16  * a problem for me, but if anyone wants to know, it's GPL too,
   17  * apart from its library which is LGPL - not that that says anything
   18  * about the code it generates, which likely belongs to the person who
   19  * generates it; so I guess there is some point in stating the
   20  * licensing of this metasource for it).
   21  *
   22  */
   23 
   24 #include "config.h"
   25 #include <stdio.h>
   26 #include <readline/readline.h>
   27 #include <readline/history.h>
   28 
   29 #if STDC_HEADERS
   30 # include <stdlib.h>
   31 # include <string.h>
   32 #else
   33 # ifndef HAVE_STRCHR
   34 #  define strchr index
   35 #  define strrchr rindex
   36 # endif
   37 char *strchr (), *strrchr ();
   38 # ifndef HAVE_MEMCPY
   39 #  define memcpy(d, s, n) bcopy ((s), (d), (n))
   40 #  define memmove(d, s, n) bcopy ((s), (d), (n))
   41 # endif
   42 #endif          /* STDC_HEADERS */
   43 #ifdef HAVE_UNISTD_H
   44 # include <unistd.h>
   45 #endif /* HAVE_UNISTD_H */
   46 extern char *optarg;
   47 extern int optind, opterr, optopt;
   48 #include <getopt.h>
   49 
   50 #include <pwd.h>
   51 #ifdef HAVE_GDBM_H
   52 # include <gdbm.h>
   53 #elif defined(HAVE_NDBM_H)
   54 # include <ndbm.h>
   55 #elif defined(HAVE_DBM_H)
   56 # include <dbm.h>
   57 #endif /* HAVE_GDBM_H */
   58 #include <rgdbm.h>
   59 #include <errno.h>
   60 char *strndup(const char *s, size_t n);
   61 #include <ctype.h>
   62 
   63 /* this is run at the parser startup */
   64 #define START  ({ \
   65   int r = cmdline(p_argc, p_argv); \
   66   self->yylex = myylex; \
   67   mhelpdb(); \
   68   r;\
   69   })
   70 /* this is run at the parser shutdown */
   71 #define FINISH rgdbm_disconnect()
   72 #include <ccx.h>
   73 
   74 #define MAX_FILES 128
   75 
   76 /* globals set by cmdline */
   77 static char * host, *dir, *user;
   78 
   79 /* replace system fgets with readline (on a tty) for the lexer */
   80 char *myfgets(char *s, int size, FILE *f)
   81 {
   82 #ifndef HAVE_LIBREADLINE
   83    return fgets(s, size, f);
   84 #else
   85 
   86    static FILE *myf;
   87    char *buf;
   88    int n;
   89    static char *prompt;
   90    static int have_setup_history;
   91 
   92    if (!isatty(fileno(f))) {
   93        return fgets(s, size, f);
   94    }
   95 
   96    /* we are on a tty. Use readline */
   97 
   98    if (!prompt) {
   99        prompt = malloc((dir ? strlen(dir) : 0 ) + 16);
  100        if (prompt)
  101            sprintf(prompt, "%s> ", (dir ?: ""));
  102    }
  103 
  104    if (!have_setup_history) {
  105        using_history();
  106        have_setup_history = 1;
  107    }
  108 
  109    if (f != stdin) {
  110       if (myf != f) {
  111           int fd = fileno(f);
  112           dup2(fd, 0);
  113           myf = f;
  114       }
  115    }
  116 
  117    buf = readline(prompt);
  118    if (!buf)
  119        return NULL;
  120 
  121    n = strlen(buf);
  122 
  123    if (n + 1 < size) {
  124        // can fit buf chars, plus '\n', plus final nul, inside s
  125        strcpy(s, buf);
  126        strcpy(s + n, "\n");
  127    } else {
  128        // can only fit some buf chars plus final nul inside s
  129        strncpy(s, buf, size - 1);
  130        s[size - 1] = 0;
  131    }
  132    free(buf);
  133    return s;
  134 #endif /* HAVE_LIBREADLINE */
  135 }
  136 
  137 /* replace 1-char lexer with one that maybe uses readline */
  138 extern int             goteof;      /* EOF flag */
  139 extern int             yytchar;     /* the last char read */
  140 extern int             yylineno;    /* line count */
  141 extern int             yylen;       /* the length of the token we catch */
  142 extern char           *yylloc;      /* where the last token came from */
  143 extern VALUE           yylval;
  144 
  145 # define YYREADBUFFERSIZE 1024
  146 
  147 int myylex()
  148 /*
  149  * This is from preccx 2.57, slightly adapted to use myfgets instead of
  150  * fgets ...
  151  *
  152  * Just in case you don't have a lexer available.
  153  * 
  154  * Read in characters into yybuffer up to the next  EOL, but ignore escaped
  155  * End-Of-Lines, then dole them out one at a time.
  156  * 
  157  * Return 0!=token for a good read and 0=FAILURE when an EOF is encountered.
  158  * 
  159  * I'm not quite doing things right here, since yylen actually represents the
  160  * size of the readahead buffer store (and doesn't decrease as I dole out
  161  * TOKENs), but yylloc does point to the last character out.
  162  * 
  163  * I should have yylen as 1 always.
  164  */
  165 {
  166     /*
  167      * if we get an EOF not immediately after a LF, pretend we got a LF (so
  168      * the final line will be empty).
  169      */
  170 
  171     static char     vline[YYREADBUFFERSIZE+1];/* virtual line buffer   */
  172     static int      nvline;                   /* remaining in virtual line */
  173 
  174     char           *rline = (char *)vline;    /* pointer to real line  */
  175 
  176     static int      nrline;                   /* remaining in real line */
  177     static union {int i; VALUE v;}
  178                     yycast;                   /* casting hack */
  179     static int      yycont;                   /* this line extends previous */
  180 
  181     
  182     if (NULL != yylloc) {  /* tokens available */
  183 
  184       if (nvline > 0) {    /* we can use a token we read ahead for */
  185         yylen = 1;
  186         nvline--;
  187         nrline--;           /* this is just for accounting - no purpose */
  188         yytchar = * ++yylloc;
  189         yycast.i = yytchar; /* handle the 'cast' via union */
  190         yylval = yycast.v;
  191         return yytchar;     /* return a pre-read token */
  192 
  193       }
  194 
  195       /* nvline == 0 */
  196 
  197       if (yycont == 0) {
  198 
  199         /*
  200          * we ask for more TOKENS next time and return the EOL (0) now
  201          * It'll be used to terminate a TOKEN string, but we don't know
  202          * that.
  203          */
  204 
  205           yylloc = (char*)NULL; /* signal that next time we must read more */
  206           yylen = 0;
  207           nvline = 0;
  208           nrline = 0;       /* this is just for accounting - no purpose */
  209           yycast.i = 0;     /* casting hack */
  210           yylval = yycast.v;
  211           return yytchar = 0; /* return 0 token */
  212       } 
  213 
  214       /* we fake a reentry, and eventually return the first
  215        * next token. We haven't set anything yet, so reentry
  216        * can be faked by just continuing
  217        */
  218 
  219       yycont = 1;
  220 
  221     }
  222 
  223     /* yylloc == NULL signalled,  we have to load the readahead buff  */
  224 
  225     /* yylloc := vline - 1 for starters  (rline := vline on every entry) */
  226 
  227     yylloc = rline - 1;        /* we will return a token at *rline ... */
  228     *rline = yytchar = 0;      /* ... but we start clean               */
  229     nvline  = 0;               /* length of readahead buffer           */
  230     nrline  = 0;               /* just for accounts - no purpose       */
  231 
  232     /*
  233      * we're here because the readahead buffer was empty and so the
  234      * initialization conditions hold: yylloc=rline - 1, etc.
  235      */
  236 
  237     /* handle fixed length buffer and long input lines properly */
  238 
  239     while (myfgets(rline,(vline+YYREADBUFFERSIZE)-rline,stdin) != NULL) { 
  240       rline[YYREADBUFFERSIZE] = 0;               /* use the extra entry */
  241       yylineno++;
  242       nrline = (int) strlen((char *) rline);     /* count the booty */
  243 
  244     /* check that we didn't read past a newline */
  245 
  246     if (nrline > 0) {
  247         if (rline[nrline - 1] == '\n')  {
  248         --nrline;             /* we did, so null it out */
  249         yycont = 0;           /* next input is new line */
  250     } else  {
  251        /* we signal ahead not to believe that we saw an (extra) \n now.
  252        */
  253         yycont = 1;           /* signal that next input is same line */
  254     }
  255     }
  256     else {
  257        /* we hit eof without finding a \n */
  258        yycont = 0;
  259     }
  260 
  261     nvline += nrline ;
  262 
  263     /* just forget about detecting escaped linefeeds */
  264 
  265     /* nrline > 0 */
  266 
  267     if (nvline == 0) {
  268       /* we got a linefeed only */
  269 
  270       yylen = 0;
  271       yylloc = (char*)NULL; /* signal to read ahead again next time round */
  272       yycast.i = 0;         /* casting hack */
  273       yylval = yycast.v;
  274       return yytchar = 0;   /* return the 0 string terminator */
  275   
  276     }
  277 
  278     /* ordinary token return. just crank our buffer */
  279 
  280     nvline--;
  281     yylen = 1;
  282 
  283     /*
  284      * the absence of a reason to continue reading is a reason to cease
  285      * reading ahead
  286      */
  287 
  288     yytchar = * ++yylloc;
  289     yycast.i = yytchar;   /* casting hack */
  290     yylval = yycast.v;
  291     return yytchar;
  292 
  293     }                     /* endwhile */
  294 
  295     /* we're here because gets() failed */
  296     goteof = 1;
  297     yytchar = EOF;        /* EOF encountered */
  298     yylloc = (char*)NULL; /* signal that readahead buffer is empty */
  299     return 0;
  300 }
  301 
  302 
  303 
  304 /* list of open dbs and their names */
  305 struct file_entry { char *dbname; RGDBM_FILE dbf; };
  306 static struct file_entry file[MAX_FILES];
  307 
  308 /* manipulate list of open dbs */
  309 static int
  310 filecount;
  311 static int
  312 getfile(char *dbname) {
  313 
  314     int i;
  315 
  316     for (i = 0; i < filecount; i++) {
  317         if (file[i].dbname && strcmp(file[i].dbname, dbname) == 0) {
  318             return i;
  319         }
  320     }
  321     return -EINVAL;
  322 }
  323 static int
  324 newfile(char *dbname, RGDBM_FILE dbf) {
  325 
  326     int i;
  327 
  328     if (getfile(dbname) >= 0) {
  329         return -EINVAL;
  330     }
  331     for (i = 0; i < filecount; i++) {
  332         if (!file[i].dbname)
  333             break;
  334     }
  335     if (i >= MAX_FILES) {
  336         return -EINVAL;
  337     }
  338 
  339     file[i].dbname = dbname;
  340     file[i].dbf    = dbf;
  341 
  342     if (i >= filecount)
  343         filecount++;
  344 
  345     return 0;
  346 }
  347 static int
  348 delfile(int i) {
  349 
  350     if (i < 0)
  351         return -EINVAL;
  352     
  353     if (file[i].dbname)
  354         free(file[i].dbname);
  355     file[i].dbname = NULL;
  356     file[i].dbf    = NULL;
  357     return 0;
  358 }
  359 
  360 
  361 /* language commands */
  362 
  363 struct row {
  364   datum key;
  365   datum content;
  366 };
  367 
  368 struct tuple;
  369 struct expr {
  370   int type;
  371   union {
  372     struct tuple *tuple;
  373     int          val;
  374     char        *msg;
  375     int          field;
  376   } data;
  377 };
  378 
  379 struct tuple {
  380   struct expr  *first;
  381   struct tuple *next;
  382 };
  383 
  384 static struct tuple *
  385 constuple(struct expr *e, struct tuple *t) {
  386 
  387     struct tuple *ret = calloc(1, sizeof(*ret));
  388     if (!ret)
  389         return NULL;
  390     ret->first = e;
  391     ret->next = t;
  392     return ret;
  393 }
  394 
  395 enum {
  396     TUPLE,
  397     BOOL,
  398     MSG,
  399     FIELD,
  400 };
  401 
  402 static void
  403 free_expr(struct expr *e) {
  404 
  405     if (!e)
  406         return;
  407     switch(e->type) {
  408       case FIELD:
  409         free(e);
  410         return;
  411       case BOOL:
  412         free(e);
  413         return;
  414       case MSG:
  415         if (e->data.msg)
  416             free(e->data.msg);
  417         free(e);
  418         return;
  419       case TUPLE:
  420       {
  421         struct tuple *t = e->data.tuple;
  422 
  423         free(e);
  424         while (t) {
  425 
  426             struct tuple *next_t;
  427 
  428             free_expr(t->first);
  429             next_t = t->next;
  430             free(t);
  431             t = next_t;
  432         }
  433       }
  434         return;
  435     }
  436 }
  437 
  438 static struct expr *
  439 new_expr(int type, ...) {
  440 
  441     va_list ap;
  442     struct expr *e = calloc(1, sizeof(*e));
  443 
  444     if (!e)
  445         return NULL;
  446 
  447     e->type = type;
  448 
  449     va_start(ap, type);
  450 
  451     switch(type) {
  452 
  453       case FIELD:
  454         e->data.field = va_arg(ap, int);
  455         break;
  456       case BOOL:
  457         e->data.val = va_arg(ap, int);
  458         break;
  459       case MSG:
  460         e->data.msg = va_arg(ap, char *);
  461         break;
  462       case TUPLE:
  463         e->data.tuple = va_arg(ap, struct tuple *);
  464         break;
  465       default:
  466         fprintf(stderr, "unknown expr type %d\n", type);
  467         break;
  468     } // eswitch
  469 
  470     va_end(ap);
  471     return e;
  472 }
  473 
  474 static void fprintexpr (FILE * f, struct row *r, struct expr *e);
  475 
  476 static void
  477 fprintbool (FILE * f, struct row *r, int x)
  478 {
  479     if (!r)
  480         return;
  481 
  482     if (x >= 0)
  483         fprintf (f, "true");
  484     else
  485         fprintf (f, "false");
  486 }
  487 static void
  488 fprintmsg (FILE * f, struct row *r, char * x)
  489 {
  490     if (!r || !x)
  491         return;
  492     fprintf (f, "%s", x);
  493 }
  494 
  495 static void
  496 fprinttuple(FILE *f, struct row *r, struct tuple *t) {
  497 
  498     /*
  499      * this evaluates a tuple, coded in m, against a row.
  500      *
  501      * m is in groups of 3 bits. 
  502      *    1 is a key,
  503      *    2 is a content,
  504      *    3 is true,
  505      *    4 is false.
  506      */
  507     int i;
  508 
  509     if (!r || !t)
  510         return;
  511 
  512     for (i = 0; t ; i++, t = t->next) {
  513 
  514        struct expr *e = t->first;
  515 
  516        if (!e)
  517            continue;
  518 
  519        if (i > 0)
  520            fprintf(f, ", ");
  521        fprintexpr(f, r, e);
  522     }
  523 }
  524 
  525 static void
  526 fprintexpr (FILE * f, struct row *r, struct expr *e)
  527 {
  528     if (!r || !e)
  529         return;
  530 
  531     switch (e->type) {
  532       case FIELD:
  533           switch (e->data.field) {
  534             case 1: // key
  535                 if (r->key.dptr)
  536                     fprintf (f, "%s", r->key.dptr);
  537                 break;
  538             case 2: // content
  539                 if (r->content.dptr)
  540                     fprintf (f, "%s", r->content.dptr);
  541                 break;
  542           }
  543           break;
  544       case BOOL:
  545           fprintbool(f,r, e->data.val);
  546           break;
  547       case MSG:
  548           fprintmsg(f,r, e->data.msg);
  549           break;
  550       case TUPLE:
  551           fprinttuple(f,r, e->data.tuple);
  552           break;
  553     }
  554 
  555 }
  556 
  557 
  558 
  559 static int
  560 opendb(char *dbname, char *blocksize, int r_w, char *mode) {
  561 
  562     int bs, m;
  563     RGDBM_FILE dbf;
  564     int ret;
  565 
  566     bs = blocksize ? atoi(blocksize) : 1024;
  567     if (mode) {
  568         m = strtol(mode, NULL, 0);
  569     } else {
  570         m = 0640;
  571     }
  572     dbf = rgdbm_open(dbname, bs, r_w, m, NULL);
  573     if (dbf) {
  574         ret = newfile(dbname, dbf);
  575     } else {
  576         ret = -EINVAL;
  577     }
  578     return ret;
  579 }
  580 
  581 static int
  582 closedb(char *dbname) {
  583 
  584     int i;
  585 
  586     i = getfile(dbname);
  587     if (i < 0) {
  588         fprintf(stderr, "db '%s' not open\n", dbname);
  589         return -EINVAL;
  590     }
  591     rgdbm_close(file[i].dbf);
  592     delfile(i);
  593     return 0;
  594 }
  595 
  596 static char *
  597 versiondb(void) {
  598 
  599     char *msg = rgdbm_version();
  600     if (!msg) {
  601         fprintf(stderr, "no version info available!\n");
  602         return NULL;
  603     }
  604     return msg;
  605 }
  606 
  607 static char *
  608 lasterrdb(void) {
  609 
  610     rgdbm_error err;
  611     char *msg;
  612     
  613     err = rgdbm_errno();
  614     msg = rgdbm_strerror(err);
  615     if (!msg) {
  616         fprintf(stderr, "no error message available!\n");
  617         return NULL;
  618     }
  619     return msg;
  620 }
  621 
  622 static int
  623 syncdb(char *dbname) {
  624 
  625     int i;
  626 
  627     i = getfile(dbname);
  628     if (i < 0) {
  629         fprintf(stderr, "db '%s' not open\n", dbname);
  630         return -EINVAL;
  631     }
  632     rgdbm_sync(file[i].dbf);
  633     return 0;
  634 }
  635 
  636 static int
  637 reorganizedb(char *dbname) {
  638 
  639     int i;
  640     int ret;
  641 
  642     i = getfile(dbname);
  643     if (i < 0) {
  644         fprintf(stderr, "db '%s' not open\n", dbname);
  645         return -EINVAL;
  646     }
  647     ret = rgdbm_reorganize(file[i].dbf);
  648     return 0;
  649 }
  650 
  651 
  652 static int
  653 deletedb(char *dbname, char *k) {
  654 
  655     int i;
  656     datum key;
  657     int ret;
  658 
  659     i = getfile(dbname);
  660     if (i < 0) {
  661         fprintf(stderr, "db '%s' not open\n", dbname);
  662         return -EINVAL;
  663     }
  664 
  665     key.dsize = strlen(k) + 1;
  666     key.dptr  = k;
  667     ret = rgdbm_delete(file[i].dbf, key);
  668     return ret;
  669 }
  670 
  671 static int
  672 existsdb(char *dbname, char *k) {
  673 
  674     int i;
  675     datum key;
  676     int ret;
  677 
  678     i = getfile(dbname);
  679     if (i < 0) {
  680         fprintf(stderr, "db '%s' not open\n", dbname);
  681         return -EINVAL;
  682     }
  683 
  684     key.dsize = strlen(k) + 1;
  685     key.dptr  = k;
  686     ret = rgdbm_exists(file[i].dbf, key);
  687     return ret != 0 ? 0 : -EINVAL;
  688 }
  689 
  690 
  691 static struct row *
  692 fetchdb(char *dbname, char *k) {
  693 
  694     int i;
  695     struct row *r = calloc(1, sizeof(*r));
  696 
  697     if (!r)
  698         return NULL;
  699 
  700     i = getfile(dbname);
  701     if (i < 0) {
  702         fprintf(stderr, "db '%s' not open\n", dbname);
  703         free(r);
  704         return NULL;
  705     }
  706 
  707     r->key.dsize = strlen(k) + 1;
  708     r->key.dptr = k;
  709 
  710     r->content = rgdbm_fetch(file[i].dbf, r->key);
  711     return r;
  712 }
  713 
  714 static struct row *
  715 firstdb(char *dbname) {
  716 
  717     int i;
  718     struct row *r = calloc(1, sizeof(*r));
  719 
  720     if (!r)
  721         return NULL;
  722 
  723     i = getfile(dbname);
  724     if (i < 0) {
  725         fprintf(stderr, "db '%s' not open\n", dbname);
  726         free(r);
  727         return NULL;
  728     }
  729 
  730     r->key = rgdbm_firstkey(file[i].dbf); 
  731     if (r->key.dptr)
  732         r->content = rgdbm_fetch(file[i].dbf, r->key);
  733     else
  734         r->content = (datum){ .dsize = 0, .dptr = NULL, };
  735     return r;
  736 }
  737 
  738 static struct row *
  739 nextdb(char *dbname, char *k) {
  740 
  741     int i;
  742     datum key;
  743     struct row *r = calloc(1, sizeof(*r));
  744 
  745     if (!r)
  746         return NULL;
  747 
  748     i = getfile(dbname);
  749     if (i < 0) {
  750         fprintf(stderr, "db '%s' not open\n", dbname);
  751         free(r);
  752         return NULL;
  753     }
  754 
  755     key.dsize = strlen(k) + 1;
  756     key.dptr  = k;
  757 
  758     r->key = rgdbm_nextkey(file[i].dbf, key);
  759     if (r->key.dptr)
  760         r->content = rgdbm_fetch(file[i].dbf, r->key);
  761     else
  762         r->content = (datum){ .dsize = 0, .dptr = NULL, };
  763     return r;
  764 }
  765 
  766 static int
  767 insertdb(char *dbname, char *k, char *c) {
  768 
  769     int i;
  770     datum key, content;
  771     int ret;
  772 
  773     i = getfile(dbname);
  774     if (i < 0) {
  775         fprintf(stderr, "db '%s' not open\n", dbname);
  776         return -EINVAL;
  777     }
  778 
  779     key.dsize = strlen(k) + 1;
  780     key.dptr  = k;
  781 
  782     content.dsize = strlen(c) + 1;
  783     content.dptr  = c;
  784 
  785     ret = rgdbm_store(file[i].dbf, key, content, RGDBM_INSERT);
  786     return ret == 0 ? 0 : -EINVAL;
  787 }
  788 
  789 static int
  790 replacedb(char *dbname, char *k, char *c) {
  791 
  792     int i;
  793     datum key, content;
  794     int ret;
  795 
  796     i = getfile(dbname);
  797     if (i < 0) {
  798         fprintf(stderr, "db '%s' not open\n", dbname);
  799         return -EINVAL;
  800     }
  801 
  802     key.dsize = strlen(k) + 1;
  803     key.dptr  = k;
  804 
  805     content.dsize = strlen(c) + 1;
  806     content.dptr  = c;
  807 
  808     ret = rgdbm_store(file[i].dbf, key, content, RGDBM_REPLACE);
  809     return ret;
  810 }
  811 
  812 static int
  813 setoptdb(char *dbname, int option, char *v) {
  814 
  815     int i, val;
  816     int ret;
  817 
  818     i = getfile(dbname);
  819     if (i < 0) {
  820         fprintf(stderr, "db '%s' not open\n", dbname);
  821         return -EINVAL;
  822     }
  823     val = atoi(v);
  824     ret = rgdbm_setopt(file[i].dbf, option, &val, sizeof(val));
  825     return ret;
  826 }
  827 
  828 static int
  829 disconnectdb(void) {
  830     rgdbm_disconnect();
  831     exit(0);
  832     return 0;
  833 }
  834 
  835 static void
  836 mhelpdb(void) {
  837     fprintf(stderr, "\t\\? for help\n");
  838     fprintf(stderr, "\t\\q to quit\n");
  839 }
  840 
  841 static void
  842 helpdb(void) {
  843     fprintf(stderr, "metacommands (begin with a '\\'):\n");
  844     mhelpdb();
  845     fprintf(stderr, "commands (end with a ';'):\n");
  846     fprintf(stderr, "\tinsert (k, c) in db;\n");
  847     fprintf(stderr, "\treplace (k, c) in db;\n");
  848     fprintf(stderr, "\t(in the following 'e' may be key or key,content, or content)\n");
  849     fprintf(stderr, "\tfetch (e) from db where key = k;\n");
  850     fprintf(stderr, "\tfetch first (e) from db;\n");
  851     fprintf(stderr, "\tfetch next (e) from db after key = k;\n");
  852     fprintf(stderr, "\texists (e) in db where key = k;\n");
  853     fprintf(stderr, "\tdelete from db where key = k;\n");
  854     fprintf(stderr, "\tversion;\n");
  855     fprintf(stderr, "\tsync db;\n");
  856     fprintf(stderr, "\treorganize db;\n");
  857     fprintf(stderr, "\tlasterr;\n");
  858     fprintf(stderr, "\t(in the following 'opt' may be cachesize, fastmode, ... )\n");
  859     fprintf(stderr, "\tsetopt opt = val for db;\n");
  860     fprintf(stderr, "\t(in the following 'who' may be reader, writer, ... )\n");
  861     fprintf(stderr, "\topen db as who [ with mode = val ];\n");
  862     fprintf(stderr, "\tclose db;\n");
  863 }
  864 
  865 /*
  866  * lexer begins here
  867  *
  868  * skip to grammar section for more meaningful stuff
  869  */
  870 
  871 // make a string attibute out of chars seen by parser p and attach here
  872 @ getstr(p)
  873 @       = {@ (long)pstr @}\x p {@ (long)pstr @}\y
  874 @         {@ (long)strndup(x, y - x) @}
  875 
  876 // chars that can appear inside double quotes
  877 @ schr
  878 @       = '\\' ?
  879 @       | >'\"'<
  880 
  881 
  882 // chars that can appear inside single quotes
  883 @ cchr
  884 @       = '\\' ?
  885 @       | >'\''<
  886 
  887 // alphanumeric characters that do not need quoting
  888 @ alnum = (isalnum) | '_'
  889 
  890 // strings can be just single alnum words, or can have quotes around them
  891 @ rawstr
  892 @       = '\'' cchr*\x '\'' {@ x @}
  893 @       | '\"' schr*\x '\"' {@ x @}
  894 @       | alnum+
  895 
  896 // attach the string representing it to a parse of a string 
  897 @ str   = getstr(rawstr)
  898 
  899 @ key(x) /* proto */
  900 
  901 // recognize a given keyword
  902 @ key(x)
  903 @       = {)!*(char *)x(}
  904 @       | {)*(char *)x(} <*(char *)x> key(x+1)
  905 
  906 // single space
  907 @ space = (isspace) | $
  908 
  909 // some (nonzero) whitespace
  910 @ ss    = space+
  911 
  912 // some (possibly zero) whitespace
  913 @ ws    = space*
  914 
  915 /* lexer ends here */
  916 
  917 /* fake result for use in printouts */
  918 static struct row fakerow;
  919 
  920 /*
  921  * Here be grumma and other strangenesses!
  922  */
  923 @ _insert
  924 @       = key("insert")
  925 @                       ws '(' ws  str\k ws ',' ws str\c ws ')'
  926 @                       ws key("in") ss str\dbname
  927 @         {@ insertdb(dbname, k, c) @}\r
  928 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
  929 
  930 @ _replace
  931 @       = key("replace")
  932 @                       ws '(' ws  str\k ws ',' ws str\c ws ')'
  933 @                       ws key("in") ss str\dbname
  934 @         {@ replacedb(dbname, k, c) @}\r
  935 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
  936 
  937 @ _field
  938 @       = key("key")     {@ new_expr(FIELD, 1) @}
  939 @       | key("content") {@ new_expr(FIELD, 2) @}
  940 @       | key("true")    {@ new_expr(BOOL, 0)  @}
  941 @       | key("false")   {@ new_expr(BOOL, -EINVAL) @}
  942 @       | str\x          {@ new_expr(MSG, (char *)x) @}
  943 
  944 @ _fields /* proto */
  945 
  946 @ _fields
  947 @       = _field\x ws
  948 @         {
  949 @          ',': ?  ws _fields\y {@ constuple((struct expr *)x, (struct tuple *)y) @}
  950 @         ;
  951 @            ::                 {@ constuple((struct expr *)x, NULL) @}
  952 @         ;
  953 @         }
  954 
  955 @ _expr
  956 @       = '(' ws _fields\x ws ')' {@ new_expr(TUPLE, (struct tuple *)x) @}
  957 @       | _field
  958 
  959 @ _fetch
  960 @       = key("fetch")  ss _expr\e
  961 @                       ss { key("from") | key("in") } ss str\dbname
  962 @                       ss key("where") ss key("key") ws '=' ws str\k
  963 @         {@ fetchdb(dbname, k) @}\r
  964 @         {: fprintexpr(stdout, (struct row *)r, (struct expr *)e); fprintf(stdout, "\n"); free(r); free_expr((struct expr *)e); :}
  965 @       | key("fetch")  ss key("first") ss _expr\e
  966 @                       ss { key("from") | key("in") } ss str\dbname
  967 @         {@ firstdb(dbname) @}\r
  968 @         {: fprintexpr(stdout, (struct row *)r, (struct expr *)e); fprintf(stdout, "\n"); free(r); free_expr((struct expr *)e);  :}
  969 @       | key("fetch")  ss key("next")  ss _expr\e
  970 @                       ss { key("from") | key("in") } ss str\dbname
  971 @                       ss key("after") ss key("key") ws '=' ws str\k
  972 @         {@ nextdb(dbname, k) @}\r
  973 @         {: fprintexpr(stdout, (struct row *)r, (struct expr *)e); fprintf(stdout, "\n"); free(r); free_expr((struct expr *)e);  :}
  974 
  975 @ _exists
  976 @       = key("exists") ss _expr\e
  977 @                       ss key("in") ss str\dbname
  978 @                       ss key("where") ss key("key") ws '=' ws str\k
  979 @         {@ existsdb(dbname, k) @}\r
  980 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
  981 
  982 @ _delete
  983 @       = key("delete") [ ss key("entry") ]
  984 @                       ss { key("from") | key("in") } ss str\dbname
  985 @                       ss key("where") ss key("key") ws '=' ws str\k
  986 @         {@ deletedb(dbname, k) @}\r
  987 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
  988 
  989 @ _version
  990 @       = key("version")
  991 @         {@ versiondb() @}\r
  992 @         {: fprintmsg(stdout, &fakerow, r); fprintf(stdout, "\n"); :}
  993 
  994 @ _sync
  995 @       = key("sync") ss str\dbname
  996 @         {@ syncdb(dbname) @}\r
  997 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
  998 
  999 @ _reorganize
 1000 @       = key("reorganize") ss str\dbname
 1001 @         {@ reorganizedb(dbname) @}\r
 1002 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
 1003 
 1004 @ _lasterr
 1005 @       = key("lasterr")
 1006 @         {@ lasterrdb() @}\r
 1007 @         {: fprintmsg(stdout, &fakerow, (char *)r); fprintf(stdout, "\n"); :}
 1008 
 1009 @ _setopt
 1010 @       = key("setopt") ss key("cachesize") ws '=' ws str\v
 1011 @                       ss key("for") ss str\dbname
 1012 @         {@ setoptdb(dbname, RGDBM_CACHESIZE, v) @}\r
 1013 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
 1014 @       | key("setopt") ss key("fastmode") ws '=' ws str\v
 1015 @                       ss key("for") ss str\dbname
 1016 @         {@ setoptdb(dbname, RGDBM_FASTMODE, v) @}\r
 1017 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
 1018 @       | key("setopt") ss key("syncmode") ws '=' ws str\v
 1019 @                       ss key("for") ss str\dbname
 1020 @         {@ setoptdb(dbname, RGDBM_SYNCMODE, v) @}\r
 1021 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
 1022 @       | key("setopt") ss key("centfree") ws '=' ws str\v
 1023 @                       ss key("for") ss str\dbname
 1024 @         {@ setoptdb(dbname, RGDBM_CENTFREE, v) @}\r
 1025 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
 1026 @       | key("setopt") ss key("coalesceblks") ws '=' ws str\v
 1027 @                       ss key("for") ss str\dbname
 1028 @         {@ setoptdb(dbname, RGDBM_COALESCEBLKS, v) @}\r
 1029 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
 1030 @       | key("setopt") ss key("rdonly") ws '=' ws str\v
 1031 @                       ss key("for") ss str\dbname
 1032 @         {@ setoptdb(dbname, RGDBM_RDONLY, v) @}\r
 1033 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
 1034 
 1035 
 1036 @ _open = key("open")   ss str\dbname
 1037 @                       [ ss key("blocksize") ws '=' ws str ]\blocksize
 1038 @                       [ ss key("as")
 1039 @                         ss { key("reader") {@ RGDBM_READER  @}
 1040 @                          | key("writer")   {@ RGDBM_WRITER  @}
 1041 @                          | key("wrcreat")  {@ RGDBM_WRCREAT @}
 1042 @                          | key("newdb")    {@ RGDBM_NEWDB   @}
 1043 @                          }
 1044 @                       ]\rw
 1045 @                       [ [ ss key("with") ] ss  key("mode") ws '=' ws  str ]\mode
 1046 @         {@ opendb(dbname, blocksize, (int)rw, mode) @}\r
 1047 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
 1048 
 1049 @ _close
 1050 @       = key("close")  ss str\dbname
 1051 @         {@ closedb(dbname) @}\r
 1052 @         {: fprintbool(stdout, &fakerow, (int)r); fprintf(stdout, "\n"); :}
 1053 
 1054 @ _mquit
 1055 @       = key("\\q")
 1056 @         {: disconnectdb(); :}
 1057 
 1058 @ _mhelp
 1059 @       = key("\\?")
 1060 @         {: helpdb(); :}
 1061 
 1062 @ sentence 
 1063 @       = _insert
 1064 @       | _replace
 1065 @       | _fetch
 1066 @       | _open
 1067 @       | _close
 1068 @       | _delete
 1069 @       | _version
 1070 @       | _exists
 1071 @       | _sync
 1072 @       | _reorganize
 1073 @       | _setopt
 1074 @       | _lasterr
 1075 
 1076 @ meta  = _mhelp
 1077 @       | _mquit
 1078 
 1079 @ gdbmsql
 1080 @       = { ws
 1081 @           {
 1082 @             '\\': meta ?* ! $
 1083 @           ;
 1084 @             ::    sentence ws ';' !
 1085 @           ;
 1086 @           }
 1087 @         }*
 1088 
 1089 /* end of grammar */
 1090 
 1091 static void
 1092 usage(char *name) {
 1093     fprintf(stderr, "usage: %s [ -H host ] [ -U user[/pass] ] [ dir ]\n", name);
 1094 }
 1095 
 1096 static char *
 1097 getuser(void) {
 1098     struct passwd *pwe = getpwuid(geteuid());
 1099     if (!pwe) {
 1100         return strdup("nobody");
 1101     }
 1102     return strdup(pwe->pw_name);
 1103 }
 1104 
 1105 static int
 1106 cmdline(int argc, char **argv) {
 1107 
 1108     int c;
 1109     int ret;
 1110 
 1111     while (1) {
 1112 
 1113         c = getopt(argc, argv, "H:U:");
 1114         if (c < 0)
 1115             break;
 1116 
 1117         switch(c) {
 1118 
 1119           case 'H':
 1120             host = optarg;
 1121             break;
 1122           case 'U':
 1123             user = optarg;
 1124             break;
 1125 
 1126           case '?':
 1127             fprintf (stderr, "getopt detected option '-%c'\n", optopt);
 1128             usage(argv[0]);
 1129             exit(1); 
 1130             return -EINVAL;
 1131 
 1132           default:
 1133             fprintf (stderr, "getopt returned code 0%o\n", c);
 1134             usage(argv[0]);
 1135             exit(1); 
 1136             return -EINVAL;
 1137         }
 1138     }
 1139 
 1140     if (optind < argc) {
 1141         dir = argv[optind++];
 1142         if (optind < argc) {
 1143             usage(argv[0]);
 1144             exit(1); 
 1145             return -EINVAL;
 1146         }
 1147     }
 1148 
 1149     if (!host) {
 1150         host = strdup("localhost");
 1151     }
 1152     if (!user) {
 1153         user = getuser();
 1154     }
 1155     if (!dir) {
 1156         dir = user;
 1157     }
 1158 
 1159     ret = rgdbm_connect(host, dir, user, 0);
 1160     if (ret < 0) {
 1161         char *pass = strrchr(user, '/');
 1162         if (pass) {
 1163             *pass++ = 0;
 1164         }
 1165         fprintf(stderr, "connection to %s@%s/%s failed\n", user, host, dir);
 1166         exit(2);
 1167     }
 1168     if (isatty(2))
 1169         fprintf(stderr, "Welcome to gdbmsql, the gdbm interactive terminal.\n\n");
 1170     return 0;
 1171 }
 1172 
 1173 MAIN(gdbmsql)
 1174