OSSP CVS Repository

ossp - Difference in ossp-pkg/lmtp2nntp/lmtp2nntp_option.c versions 1.16 and 1.17
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [History

ossp-pkg/lmtp2nntp/lmtp2nntp_option.c 1.16 -> 1.17

--- lmtp2nntp_option.c   2002/03/06 14:25:39     1.16
+++ lmtp2nntp_option.c   2002/03/07 16:03:56     1.17
@@ -127,142 +127,127 @@
 }
 
 
-lmtp2nntp_option_rc_t option_register(lmtp2nntp_option_t *o, char *longname, char shortname, optiontype_t type, char *def, char *descrip, char *argdescrip, optionloop_cb_t *cb, char *cbctx)
+static void option_register(lmtp2nntp_option_t *o, char *longname, char shortname, optiontype_t type, char *def, char *descrip, char *argdescrip, optionloop_cb_t *cb, char *cbctx)
 {
-    lmtp2nntp_option_rc_t rc = VAL_OK;
-    optionval_t *oc;
+    volatile struct {
+        optionval_t *oc;
+    } v;
+    ex_t ex;
     
-    //printf("DEBUG: enter option_register(%.8lx, \"%s\", '%c', %d, %.8lx, %.8lx, \"%s\", \"%s\")\n", (long)o, longname, shortname, type, (long)cb, (long)cbctx, descrip, argdescrip);
-
-    if (o == NULL || longname == NULL)
-        return OPTION_ERR_ARG;
-
-    /* create a optionval_t structure */
-    if ((oc = (optionval_t *)malloc(sizeof(optionval_t))) == NULL)
-        return OPTION_ERR_MEM;
-    //printf("DEBUG: optionval_t structure malloc'ed\n");
-    oc->next         = NULL;
-    oc->parent       = o;
-    oc->longname     = strdup(longname);
-    oc->shortname    = shortname;
-    oc->descrip      = descrip == NULL ? NULL : strdup(descrip);
-    oc->argdescrip   = argdescrip == NULL ? NULL : strdup(argdescrip);
-    oc->type         = type;
-    oc->cb           = cb;
-    oc->cbctx        = cbctx;
-    oc->val          = o->vo;
-    oc->number       = o->pi + 1; /* 0 is a reserved val in popt, so offset 1 */
-    switch (type) {
-        case OPT_FLAG:   oc->data.f       = 0;
-            break;
-        case OPT_SINGLE: oc->data.s       = def == NULL ? NULL : strdup(def);
-            break;
-        case OPT_MULTI:  oc->data.m       = NULL;
-            break;
-    }
-    oc->ndata        = (type == OPT_SINGLE && def != NULL) ? 1 : 0;
-    if (   (                                            oc->longname   == NULL)
-        || (                      descrip    != NULL && oc->descrip    == NULL)
-        || (                      argdescrip != NULL && oc->argdescrip == NULL)
-        || (type == OPT_SINGLE && def        != NULL && oc->data.s     == NULL)
-          )
-        CU(OPTION_ERR_MEM);
-
-    //printf("DEBUG: optionval_t structure created, oc at %.8lx is %.8lx\n", (long)&oc, (long)oc);
-
-    /* feed lib_val */
-    if (val_reg(oc->val, oc->longname, VAL_TYPE_PTR, oc->descrip, NULL) != VAL_OK)
-        CU(OPTION_ERR_USE);
-    if (val_set(oc->val, oc->longname, oc) != VAL_OK)
-        CU(OPTION_ERR_USE);
-    //printf("DEBUG: val_reg'ed\n");
-
-#if 0
-    {
-        optionval_t *ov = 0x12345678;
+    v.oc = NULL;
+    try {
+        if (o == NULL || longname == NULL)
+            throw(option_register, o, OPTION_ERR_ARG);
 
-        if (val_get(oc->val, oc->longname, &ov) == VAL_OK)
-            printf("DEBUG: oc->val %.8lx %s in %.8lx d = \"s\"\n", (long)oc->val, oc->longname, (long)(oc));
-        if (val_get(o->vo,   oc->longname, &ov) == VAL_OK)
-            printf("DEBUG: o->vo   %.8lx %s in %.8lx d = \"s\"\n", (long)o->vo,   oc->longname, (long)(ov));
-        printf("DEBUG: val_get'ed\n");
-    }
-#endif
-
-    /* feed lib_popt */
-    //printf("DEBUG: o->pi=%d, o->pn=%d\n", o->pi, o->pn);
-    if (o->pi >= (o->pn-2)) { /* correction by two here, in malloc and realloc is for AUTOHELP and TABLEEND */
-        if (o->pt == NULL) {
-            //printf("DEBUG: malloc\n");
-            o->pt = (struct popt_option *)malloc(                (1 + 2) * sizeof(struct popt_option));
-            o->pn = 1;
+        /* create a optionval_t structure and initialize exception-uncritical data */
+        v.oc = (optionval_t *)mallocex(sizeof(optionval_t));
+        v.oc->next       = NULL;
+        v.oc->parent     = o;
+        v.oc->longname   = NULL;
+        v.oc->shortname  = shortname;
+        v.oc->descrip    = NULL;
+        v.oc->argdescrip = NULL;
+        v.oc->type       = type;
+        v.oc->cb         = cb;
+        v.oc->cbctx      = cbctx;
+        v.oc->val        = o->vo;
+        v.oc->number     = o->pi + 1; /* 0 is a reserved val in popt, so offset 1 */
+        switch (type) {
+            case OPT_FLAG:   v.oc->data.f = 0;    break;
+            case OPT_SINGLE: v.oc->data.s = NULL; break;
+            case OPT_MULTI:  v.oc->data.m = NULL; break;
+        }
+        v.oc->ndata      = 0;
+        /* preinitialization complete, now initialize exception-critical data*/
+        v.oc->longname = strdupex(longname);
+        if (descrip != NULL)
+            v.oc->descrip = strdupex(descrip);
+        if (argdescrip != NULL)
+            v.oc->argdescrip = strdupex(argdescrip);
+        if (type == OPT_SINGLE && def != NULL) {
+            v.oc->data.s = strdupex(def);
+            v.oc->ndata = 1;
+        }
+
+        /* feed lib_val */
+        if (val_reg(v.oc->val, v.oc->longname, VAL_TYPE_PTR, v.oc->descrip, NULL) != VAL_OK)
+            throw(option_register, o, OPTION_ERR_USE);
+        if (val_set(v.oc->val, v.oc->longname, v.oc) != VAL_OK)
+            throw(option_register, o, OPTION_ERR_USE);
+
+        /* feed lib_popt */
+        if (o->pi >= (o->pn-2)) { /* correction by two here, in mallv.oc and reallv.oc is for AUTOHELP and TABLEEND */
+            if (o->pt == NULL) {
+                o->pt = (struct popt_option *)mallocex(                (1 + 2) * sizeof(struct popt_option));
+                o->pn = 1;
+            }
+            else {
+                o->pt = (struct popt_option *)reallocex(o->pt, (o->pn * 2 + 2) * sizeof(struct popt_option));
+                o->pn = o->pn * 2;
+            }
+        }
+        o->pt[o->pi].longName   = v.oc->longname;
+        o->pt[o->pi].shortName  = v.oc->shortname;
+        o->pt[o->pi].argInfo    = v.oc->type == OPT_FLAG ? POPT_ARG_NONE : POPT_ARG_STRING;
+        o->pt[o->pi].arg        = NULL;
+        o->pt[o->pi].val        = v.oc->number;
+        o->pt[o->pi].descrip    = v.oc->descrip;
+        o->pt[o->pi].argDescrip = v.oc->argdescrip;
+
+        /* append POPT_AUTOHELP */
+        o->pt[o->pi+1].longName   = NULL;
+        o->pt[o->pi+1].shortName  = '\0';
+        o->pt[o->pi+1].argInfo    = POPT_ARG_INCLUDE_TABLE;
+        o->pt[o->pi+1].arg        = popt_helpoptions;
+        o->pt[o->pi+1].val        = 0;
+        o->pt[o->pi+1].descrip    = "Help options:";
+        o->pt[o->pi+1].argDescrip = NULL;
+
+        /* append POPT_TABLEEND */
+        o->pt[o->pi+2].longName   = NULL;
+        o->pt[o->pi+2].shortName  = '\0';
+        o->pt[o->pi+2].argInfo    = 0;
+        o->pt[o->pi+2].arg        = 0;
+        o->pt[o->pi+2].val        = 0;
+        o->pt[o->pi+2].descrip    = NULL;
+        o->pt[o->pi+2].argDescrip = NULL;
+        o->pi++;
+
+        /* link in this new optionval_t structure */
+        if (o->first == NULL) {
+            o->first = v.oc;
+            o->last  = v.oc;
         }
         else {
-            //printf("DEBUG: realloc\n");
-            o->pt = (struct popt_option *)realloc(o->pt, (o->pn * 2 + 2) * sizeof(struct popt_option));
-            o->pn = o->pn * 2;
-        }
-    }
-    if (o->pt == NULL)
-        CU(OPTION_ERR_MEM);
-    o->pt[o->pi].longName   = oc->longname;
-    o->pt[o->pi].shortName  = oc->shortname;
-    o->pt[o->pi].argInfo    = oc->type == OPT_FLAG ? POPT_ARG_NONE : POPT_ARG_STRING;
-    o->pt[o->pi].arg        = NULL;
-    o->pt[o->pi].val        = oc->number;
-    o->pt[o->pi].descrip    = oc->descrip;
-    o->pt[o->pi].argDescrip = oc->argdescrip;
-
-    /* append POPT_AUTOHELP */
-    o->pt[o->pi+1].longName   = NULL;
-    o->pt[o->pi+1].shortName  = '\0';
-    o->pt[o->pi+1].argInfo    = POPT_ARG_INCLUDE_TABLE;
-    o->pt[o->pi+1].arg        = popt_helpoptions;
-    o->pt[o->pi+1].val        = 0;
-    o->pt[o->pi+1].descrip    = "Help options:";
-    o->pt[o->pi+1].argDescrip = NULL;
-
-    /* append POPT_TABLEEND */
-    o->pt[o->pi+2].longName   = NULL;
-    o->pt[o->pi+2].shortName  = '\0';
-    o->pt[o->pi+2].argInfo    = 0;
-    o->pt[o->pi+2].arg        = 0;
-    o->pt[o->pi+2].val        = 0;
-    o->pt[o->pi+2].descrip    = NULL;
-    o->pt[o->pi+2].argDescrip = NULL;
-    o->pi++;
-    //printf("DEBUG: popt'ed\n");
-
-    /* link in this new optionval_t structure */
-    if (o->first == NULL) {
-        o->first = oc;
-        o->last  = oc;
-    }
-    else {
-        o->last->next = oc; 
-        o->last       = oc;
+            o->last->next = v.oc; 
+            o->last       = v.oc;
+        }
     }
-    //printf("DEBUG: linked\n");
-
-    return rc;
-
-    CUS:
-    if (oc != NULL) {
-        if (oc->argdescrip != NULL) free(oc->argdescrip);
-        if (oc->descrip    != NULL) free(oc->descrip);
-        if (oc->longname   != NULL) free(oc->longname);
-        free(oc);
+    catch(ex) {
+        if (v.oc != NULL) {
+            if (type == OPT_SINGLE && v.oc->data.s != NULL)
+                free(v.oc->data.s);
+            if (v.oc->argdescrip != NULL)
+                free(v.oc->argdescrip);
+            if (v.oc->descrip != NULL)
+                free(v.oc->descrip);
+            if (v.oc->longname != NULL)
+                free(v.oc->longname);
+            free(v.oc);
+        }
+        rethrow;
     }
-    return rc;
+    return;
 }
 
+/* this public function catches all underlying exceptions and properly returns a code */
 lmtp2nntp_option_rc_t option_create(lmtp2nntp_option_t **op, val_t *parent)
 {
     ex_t ex;
 
     try {
-        if (op == NULL)
-            throw(option_create, NULL, OPTION_ERR_ARG);
+        if (op == NULL || parent == NULL)
+            return OPTION_ERR_ARG;
 
         (*op = (lmtp2nntp_option_t *)mallocex(sizeof(lmtp2nntp_option_t)));
         (*op)->first = NULL;
@@ -273,10 +258,10 @@
         (*op)->pt = NULL;
 
         if (val_create(&((*op)->vo)) != VAL_OK)
-            throw(option_create, NULL, OPTION_ERR_VAL);
+            return OPTION_ERR_VAL;
 
         if (val_reg(parent, "option", VAL_TYPE_VAL, "option", (void *)&((*op)->vo)) != VAL_OK)
-            throw(option_create, NULL, OPTION_ERR_VAL);
+            return OPTION_ERR_VAL;
     }
     catch(ex) {
         if (*op != NULL) {
@@ -284,7 +269,9 @@
                 val_unreg(parent, "option");
             free(*op);
         }
-        rethrow;
+        if (ex.ex_class == (void *)option_create)
+            return (lmtp2nntp_option_rc_t)ex.ex_value;
+        return OPTION_ERR_TRY;
     }
     return OPTION_OK;
 }
@@ -296,14 +283,20 @@
     int i;
     char *cp;
     optionval_t *ocp;
-    popt_context poptCon;   /* context for parsing command-line options */
+    popt_context poptCon;
+
+    /* internal function trusts args */
 
+    /* init lib_popt */
     poptCon = popt_getcontext(NULL, argc, (const char **)argv, o->pt, 0);
     popt_setotheroptionhelp(poptCon, "[OPTIONS]* [newsgroup ...]");
+
+    /* print usage if too few argv's */
     if (argc < 2) {
         popt_printusage(poptCon, stderr, 0);
-        exit(1); //FIXME
+        return OPTION_ERR_USE;
     }
+    /* parse every option, continue when optarg missing or bad option found */
     while ((i = popt_getnextopt(poptCon)) >= 0 || i == POPT_ERROR_NOARG || i == POPT_ERROR_BADOPT) {
         if (i == POPT_ERROR_NOARG || i == POPT_ERROR_BADOPT) {
             fprintf(stderr, "ERROR: %s (%d) \"%s\"\n", popt_strerror(i), i, popt_badoption(poptCon, POPT_BADOPTION_NOALIAS));
@@ -317,27 +310,41 @@
         }
     }
 
+    /* create a "--newsgroup" argc/argv for every leftover argument */
     {
-        int largc;
-        char **largv;
-        char *cpNew;
-
-        largv = (char **)mallocex((1 + 1) * sizeof(char **));
-        largc = 0;
-        largv[largc++] = "leftover";
-        largv[largc] = NULL;
-        while ((cp = (char *)popt_getarg(poptCon)) != NULL) {
-            largv = (char **)reallocex(largv, (largc + 2) * sizeof(char **));
-            largv[largc++] = "--newsgroup";
-            largv[largc] = NULL;
-            cpNew = strdupex(cp);
-            largv[largc++] = cpNew;
-            largv[largc] = NULL;
+        ex_t ex;
+        volatile struct {
+            char **largv;
+            } v;
+
+        try {
+            int largc;
+            char *cpNew;
+
+            v.largv = (char **)mallocex((1 + 1) * sizeof(char **));
+            largc = 0;
+            v.largv[largc++] = "leftover";
+            v.largv[largc] = NULL;
+            while ((cp = (char *)popt_getarg(poptCon)) != NULL) {
+                v.largv = (char **)reallocex(v.largv, (largc + 2) * sizeof(char **));
+                v.largv[largc++] = "--newsgroup";
+                v.largv[largc] = NULL;
+                cpNew = strdupex(cp);
+                v.largv[largc++] = cpNew;
+                v.largv[largc] = NULL;
+            }
+            if (largc > 1) {
+                rv = option_parse_internal(o, largc, v.largv);
+                if (rc == OPTION_OK)
+                    rc = rv;
+            }
         }
-        if (largc > 1) {
-            rv = option_parse_internal(o, largc, largv);
-            if (rc == OPTION_OK)
-                rc = rv;
+        cleanup {
+            if (v.largv != NULL)
+                free(v.largv);
+        }
+        catch(ex) {
+            rethrow;
         }
     }
     popt_freecontext(poptCon);
@@ -346,12 +353,8 @@
 
 static lmtp2nntp_option_rc_t stdsyntax(optionval_t *oc, char *arg, char *cbctx)
 {
-    //printf("DEBUG: enter stdsyntax %.8lx, \"%s\", \"%s\"\n", (long)oc, arg, cbctx);
-
-    //printf("DEBUG: oc->type=%d\n", oc->type);
     switch (oc->type) {
         case OPT_FLAG:
-            //printf("DEBUG: flag   %20s = %s should match %s\n", oc->longname, arg, cbctx);
             if (arg != NULL || cbctx != NULL)
                 return OPTION_ERR_ARG;
             if (oc->ndata >= 1)
@@ -360,25 +363,22 @@
             oc->ndata = 1;
             break;
         case OPT_SINGLE:
-            //printf("DEBUG: single %20s = %s should match %s\n", oc->longname, arg, cbctx);
             if (arg == NULL)
                 return OPTION_ERR_ARG;
-            /* use this if repeated overwriting definitions are not allowed
-             *  if (oc->ndata >= 1 || oc->data.s != NULL)
-             *      return OPTION_ERR_USE;
-             */
+        /*  add this if repeated overwriting definitions of single values are not allowed
+         *  if (oc->ndata >= 1 || oc->data.s != NULL)
+         *      return OPTION_ERR_USE;
+         */
             if (cbctx != NULL)
                 if (str_parse(arg, cbctx) <= 0) {
                     fprintf(stderr, "ERROR: argument \"%s\" does NOT match syntax \"%s\"\n", arg, cbctx);
                     return OPTION_ERR_USE;
                 }
-            //printf("DEBUG: \"%s\" does match \"%s\"\n", arg, cbctx);
             if ((oc->data.s = strdup(arg)) == NULL)
                     return OPTION_ERR_MEM;
             oc->ndata = 1;
             break;
         case OPT_MULTI:
-            //printf("DEBUG: multi  %20s = %s should match %s\n", oc->longname, arg, cbctx);
             if (arg == NULL)
                 return OPTION_ERR_ARG;
             if (oc->ndata >= 1 && oc->data.m == NULL)
@@ -388,34 +388,13 @@
                     fprintf(stderr, "ERROR: argument \"%s\" does NOT match syntax \"%s\"\n", arg, cbctx);
                     return OPTION_ERR_USE;
                 }
-            //printf("DEBUG: \"%s\" does match \"%s\"\n", arg, cbctx);
-            /* malloc/realloc                                 existing + this new + terminating NULL */
-            if (oc->data.m == NULL) {
-                //printf("DEBUG: before  malloc, oc->data.m = %.8lx - ", (long)oc->data.m);
-                //printf("DEBUG: requesting %d bytes\n",         (        0 + 1 + 1) * sizeof(char **));
-                if ((oc->data.m = (char **)malloc(             (        0 + 1 + 1) * sizeof(char **))) == NULL)
-                    return OPTION_ERR_MEM;
-                //printf("DEBUG: after   malloc, oc->data.m = %.8lx\n", (long)oc->data.m);
-            }
-            else {
-                //printf("DEBUG: before realloc, oc->data.m = %.8lx\n", (long)oc->data.m);
-                //printf("DEBUG: requesting %d bytes\n",         (oc->ndata + 1 + 1) * sizeof(char **));
-                if ((oc->data.m = (char **)realloc(oc->data.m, (oc->ndata + 1 + 1) * sizeof(char **))) == NULL)
-                    return OPTION_ERR_MEM;
-                //printf("DEBUG: after  realloc, oc->data.m = %.8lx\n", (long)oc->data.m);
-            }
-            if ((oc->data.m[oc->ndata] = strdup(arg)) == NULL)
-                    return OPTION_ERR_MEM;
+            if (oc->data.m == NULL)                        /* existing + this new + terminating NULL */
+                oc->data.m = (char **)mallocex(             (        0 + 1 + 1) * sizeof(char **));
+            else
+                oc->data.m = (char **)reallocex(oc->data.m, (oc->ndata + 1 + 1) * sizeof(char **));
+            oc->data.m[oc->ndata] = strdupex(arg);
             oc->ndata++;
             oc->data.m[oc->ndata] = NULL;
-#if 0
-            {
-                int i;
-                printf("DEBUG: oc->ndata=%d\n", oc->ndata);
-                for (i=0; i<=oc->ndata; i++)
-                    printf("DEBUG: oc->data[%3d] at %.8lx points to  %.8lx = %s\n", i, (long)&oc->data.m[i], (long)oc->data.m[i], oc->data.m[i]);
-            }
-#endif
             break;
         default:
             return OPTION_ERR_ARG;
@@ -431,13 +410,10 @@
     int argc = 0;
     char **argv = NULL;
 
-    //printf("DEBUG: enter includeit %.8lx, \"%s\", \"%s\"\n", (long)oc, arg, cbctx);
-
     if ((o = oc->parent) == NULL)
         return OPTION_ERR_USE;
 
     stdsyntax(oc, arg, cbctx);
-    //printf("DEBUG: *** 1 *** file going to be read in now\n");
     {
         const char *filename = arg;
         struct stat sb;
@@ -445,21 +421,24 @@
         ex_t ex;
 
         try {
-            if (stat(filename, &sb) == -1) throw(0, 0, "stat");
-            if ((cpBuf = (char *)malloc((size_t)sb.st_size + 1)) == NULL) throw(0, 0, "malloc");
-            if ((fd = open(filename, O_RDONLY)) == -1) throw(0, 0, "open");
-            if (read(fd, (void *)cpBuf, (size_t)sb.st_size) != (ssize_t)sb.st_size) throw(0, 0, "read");
+            if (stat(filename, &sb) == -1)
+                throw(includeit, oc, "stat");
+            cpBuf = (char *)mallocex((size_t)sb.st_size + 1);
+            if ((fd = open(filename, O_RDONLY)) == -1)
+                throw(includeit, oc, "open");
+            if (read(fd, (void *)cpBuf, (size_t)sb.st_size) != (ssize_t)sb.st_size)
+                throw(includeit, oc, "read");
             cpBuf[(int)sb.st_size] = '\0';
         }
         cleanup {
             if (fd != -1) close(fd);
         }
         catch (ex) {
-            fprintf(stderr, "ERROR: caught %s\n", ex.ex_value == NULL ? "N/A" : (char *)ex.ex_value);
+            if (cpBuf != NULL)
+                free((char *)cpBuf);
             rethrow;
         }
     }
-    //printf("DEBUG: *** 2 *** file as it was just read in ***\n%s***\n", cpBuf);
 
     {
         char *cpI;  /* pointer to next character to be read */
@@ -560,51 +539,59 @@
     return option_parse_internal(o, argc, argv);
 }
 
+/* this public function catches all underlying exceptions and properly returns a code */
 lmtp2nntp_option_rc_t option_parse(lmtp2nntp_option_t *o, int argc, char **argv)
 {
-    if (o == NULL)
-        return OPTION_ERR_ARG;
+    ex_t ex;
 
-    (void)option_register(o, "childsmax",          'C', OPT_SINGLE,  "10",        "childs to spawn at max",            "childsmax",                  &stdsyntax, "m/\\d+/" ); //"m/[0-9]+/" );
-    (void)option_register(o, "daemonize",          'D', OPT_FLAG,    NULL,        "detach from terminal",              NULL,                         &stdsyntax, NULL );
-    (void)option_register(o, "kill",               'K', OPT_FLAG,    NULL,        "kill a previously run daemon",      NULL,                         &stdsyntax, NULL );
-    (void)option_register(o, "pidfile",            'P', OPT_SINGLE,  NULL,        "file containing pid",               "pidfile",                    &stdsyntax, "m/.*/" );
-    (void)option_register(o, "acl",                'a', OPT_MULTI,   NULL,        "LMTP server access control list",   "addr[/mask]",                &stdsyntax, "m/.*/" );
-    (void)option_register(o, "bind",               'b', OPT_SINGLE,  NULL,        "LMTP server bind",                  "addr[:port]|-|path[:perms]", &stdsyntax, "m/.*/" );
-    (void)option_register(o, "client",             'c', OPT_SINGLE,  NULL,        "NNTP client bind",                  "addr[:port]",                &stdsyntax, "m/.*/" );
-    (void)option_register(o, "destination",        'd', OPT_MULTI,   NULL,        "NNTP client destination",           "addr[:port]",                &stdsyntax, "m/.*/" );
-    (void)option_register(o, "groupmode",          'g', OPT_SINGLE,  "arg",       "arg|envelope|header",               "groupmode",                  &stdsyntax, "m/.*/" ); //"m/(arg|envelope|header)/" );
-    (void)option_register(o, "headerrule",         'h', OPT_MULTI,   NULL,        "header rewriting rule",             "[pri]:[regex]:header:[val]", &stdsyntax, "m/^[0-9]*:.*:.+:.*$/" );
-    (void)option_register(o, "include",            'i', OPT_MULTI,   NULL,        "configfile to include",             "configfile",                 &includeit, "m/.*/" );
-    (void)option_register(o, "timeoutlmtp",        NUL, OPT_SINGLE,  NULL,        "LMTP server default timeout",       "sec",                        &stdsyntax, "m/.*/" );
-    (void)option_register(o, "timeoutlmtpaccept",  NUL, OPT_SINGLE,  "0",         "LMTP server accept timeout",        "sec",                        &stdsyntax, "m/.*/" );
-    (void)option_register(o, "timeoutlmtpread",    NUL, OPT_SINGLE,  "10",        "LMTP server read timeout",          "sec",                        &stdsyntax, "m/.*/" );
-    (void)option_register(o, "timeoutlmtpwrite",   NUL, OPT_SINGLE,  "10",        "LMTP server write timeout",         "sec",                        &stdsyntax, "m/.*/" );
-    (void)option_register(o, "timeoutnntp",        NUL, OPT_SINGLE,  NULL,        "NNTP client default timeout",       "sec",                        &stdsyntax, "m/.*/" );
-    (void)option_register(o, "timeoutnntpconnect", NUL, OPT_SINGLE,  "360",       "NNTP client connect timeout",       "sec",                        &stdsyntax, "m/.*/" );
-    (void)option_register(o, "timeoutnntpread",    NUL, OPT_SINGLE,  "60",        "NNTP client read timeout",          "sec",                        &stdsyntax, "m/.*/" );
-    (void)option_register(o, "timeoutnntpwrite",   NUL, OPT_SINGLE,  "60",        "NNTP client write timeout",         "sec",                        &stdsyntax, "m/.*/" );
-    (void)option_register(o, "l2spec",             'l', OPT_SINGLE,  NULL,        "L2 channel tree specification",     "l2spec",                     &stdsyntax, "m/.*/" );
-    (void)option_register(o, "mailfrom",           'm', OPT_SINGLE,  NULL,        "mail from envelope restriction",    "regex",                      &stdsyntax, "m/.*/" );
-    (void)option_register(o, "nodename",           'n', OPT_SINGLE,  NULL,        "nodename",                          "name",                       &stdsyntax, "m/.*/" );
-    (void)option_register(o, "operationmode",      'o', OPT_SINGLE,  "553/5.7.1", "fakestatus or operationmode",       "abc/a.d.e|post|feed",        &stdsyntax, "m/.*/" ); //"m/([0-9]{3}\\/[0-9]\\.[0-9]\\.[0-9]|post|feed)/" ); /* 553 = Requested action not taken: mailbox name not allowed, 5.7.1 =  Delivery not authorized, message refused */
-    (void)option_register(o, "restrictheader",     'r', OPT_SINGLE,  NULL,        "header restriction",                "regex",                      &stdsyntax, "m/.*/" );
-    (void)option_register(o, "size",               's', OPT_SINGLE,  "8388608",   "maximum message size",              "bytes",                      &stdsyntax, "m/.*/" ); //"m/[0-9]+/" );
-    (void)option_register(o, "testfile",           't', OPT_MULTI,   NULL,        "testfile for headerrule",           "testfile",                   &stdsyntax, "m/.*/" );
-    (void)option_register(o, "user",               'u', OPT_SINGLE,  NULL,        "user",                              "uid|name",                   &stdsyntax, "m/.*/" );
-    (void)option_register(o, "version",            'v', OPT_FLAG,    NULL,        "print version",                     NULL,                         &stdsyntax, NULL );
-    (void)option_register(o, "newsgroup",          NUL, OPT_MULTI,   NULL,        "article destination",               "newsgroup",                  &stdsyntax, "m/.*/" );
+    if (o == NULL || argc < 0 || argv == NULL)
+        return OPTION_ERR_ARG;
 
+    try {
+        option_register(o, "childsmax",          'C', OPT_SINGLE,  "10",        "childs to spawn at max",            "childsmax",                  &stdsyntax, "m/\\d+/" ); //"m/[0-9]+/" );
+        option_register(o, "daemonize",          'D', OPT_FLAG,    NULL,        "detach from terminal",              NULL,                         &stdsyntax, NULL );
+        option_register(o, "kill",               'K', OPT_FLAG,    NULL,        "kill a previously run daemon",      NULL,                         &stdsyntax, NULL );
+        option_register(o, "pidfile",            'P', OPT_SINGLE,  NULL,        "file containing pid",               "pidfile",                    &stdsyntax, "m/.*/" );
+        option_register(o, "acl",                'a', OPT_MULTI,   NULL,        "LMTP server access control list",   "addr[/mask]",                &stdsyntax, "m/.*/" );
+        option_register(o, "bind",               'b', OPT_SINGLE,  NULL,        "LMTP server bind",                  "addr[:port]|-|path[:perms]", &stdsyntax, "m/.*/" );
+        option_register(o, "client",             'c', OPT_SINGLE,  NULL,        "NNTP client bind",                  "addr[:port]",                &stdsyntax, "m/.*/" );
+        option_register(o, "destination",        'd', OPT_MULTI,   NULL,        "NNTP client destination",           "addr[:port]",                &stdsyntax, "m/.*/" );
+        option_register(o, "groupmode",          'g', OPT_SINGLE,  "arg",       "arg|envelope|header",               "groupmode",                  &stdsyntax, "m/.*/" ); //"m/(arg|envelope|header)/" );
+        option_register(o, "headerrule",         'h', OPT_MULTI,   NULL,        "header rewriting rule",             "[pri]:[regex]:header:[val]", &stdsyntax, "m/^[0-9]*:.*:.+:.*$/" );
+        option_register(o, "include",            'i', OPT_MULTI,   NULL,        "configfile to include",             "configfile",                 &includeit, "m/.*/" );
+        option_register(o, "timeoutlmtp",        NUL, OPT_SINGLE,  NULL,        "LMTP server default timeout",       "sec",                        &stdsyntax, "m/.*/" );
+        option_register(o, "timeoutlmtpaccept",  NUL, OPT_SINGLE,  "0",         "LMTP server accept timeout",        "sec",                        &stdsyntax, "m/.*/" );
+        option_register(o, "timeoutlmtpread",    NUL, OPT_SINGLE,  "10",        "LMTP server read timeout",          "sec",                        &stdsyntax, "m/.*/" );
+        option_register(o, "timeoutlmtpwrite",   NUL, OPT_SINGLE,  "10",        "LMTP server write timeout",         "sec",                        &stdsyntax, "m/.*/" );
+        option_register(o, "timeoutnntp",        NUL, OPT_SINGLE,  NULL,        "NNTP client default timeout",       "sec",                        &stdsyntax, "m/.*/" );
+        option_register(o, "timeoutnntpconnect", NUL, OPT_SINGLE,  "360",       "NNTP client connect timeout",       "sec",                        &stdsyntax, "m/.*/" );
+        option_register(o, "timeoutnntpread",    NUL, OPT_SINGLE,  "60",        "NNTP client read timeout",          "sec",                        &stdsyntax, "m/.*/" );
+        option_register(o, "timeoutnntpwrite",   NUL, OPT_SINGLE,  "60",        "NNTP client write timeout",         "sec",                        &stdsyntax, "m/.*/" );
+        option_register(o, "l2spec",             'l', OPT_SINGLE,  NULL,        "L2 channel tree specification",     "l2spec",                     &stdsyntax, "m/.*/" );
+        option_register(o, "mailfrom",           'm', OPT_SINGLE,  NULL,        "mail from envelope restriction",    "regex",                      &stdsyntax, "m/.*/" );
+        option_register(o, "nodename",           'n', OPT_SINGLE,  NULL,        "nodename",                          "name",                       &stdsyntax, "m/.*/" );
+        option_register(o, "operationmode",      'o', OPT_SINGLE,  "553/5.7.1", "fakestatus or operationmode",       "abc/a.d.e|post|feed",        &stdsyntax, "m/.*/" ); //"m/([0-9]{3}\\/[0-9]\\.[0-9]\\.[0-9]|post|feed)/" ); /* 553 = Requested action not taken: mailbox name not allowed, 5.7.1 =  Delivery not authorized, message refused */
+        option_register(o, "restrictheader",     'r', OPT_SINGLE,  NULL,        "header restriction",                "regex",                      &stdsyntax, "m/.*/" );
+        option_register(o, "size",               's', OPT_SINGLE,  "8388608",   "maximum message size",              "bytes",                      &stdsyntax, "m/.*/" ); //"m/[0-9]+/" );
+        option_register(o, "testfile",           't', OPT_MULTI,   NULL,        "testfile for headerrule",           "testfile",                   &stdsyntax, "m/.*/" );
+        option_register(o, "user",               'u', OPT_SINGLE,  NULL,        "user",                              "uid|name",                   &stdsyntax, "m/.*/" );
+        option_register(o, "version",            'v', OPT_FLAG,    NULL,        "print version",                     NULL,                         &stdsyntax, NULL );
+        option_register(o, "newsgroup",          NUL, OPT_MULTI,   NULL,        "article destination",               "newsgroup",                  &stdsyntax, "m/.*/" );
+    }
+    catch(ex) {
+        if (ex.ex_class == option_create)
+            return (lmtp2nntp_option_rc_t)ex.ex_value;
+        return OPTION_ERR_TRY;
+    }
     return option_parse_internal(o, argc, argv);
 }
 
+/* this public function catches all underlying exceptions and properly returns a code */
 lmtp2nntp_option_rc_t option_destroy(lmtp2nntp_option_t *o)
 {
     optionval_t *oc;
     int i;
 
-    //printf("DEBUG: option_destroy %.8lx\n", (long)o);
-
     if (o == NULL)
         return OPTION_ERR_ARG;
 

CVSTrac 2.0.1