Added silc_getopt.
authorPekka Riikonen <priikone@silcnet.org>
Tue, 25 Dec 2007 11:56:14 +0000 (11:56 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 25 Dec 2007 11:56:14 +0000 (11:56 +0000)
CHANGES.RUNTIME
TODO
includes/silc.h.in
lib/silcutil/Makefile.ad
lib/silcutil/silcgetopt.c [new file with mode: 0644]
lib/silcutil/silcgetopt.h [new file with mode: 0644]
lib/silcutil/tests/test_silchashtable.c

index f0995733a291817c93f8038e36d84154944434e6..4c2cef6413d20edbb7915359dd9f75e21d2216fd 100644 (file)
@@ -1,3 +1,7 @@
+Tue Dec 25 13:53:07 EET 2007  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added silc_getopt to lib/silcutil/silcgetopt.[ch].
+
 Sat Dec 22 19:55:28 EET 2007  Pekka Riikonen <priikone@silcnet.org>
 
        * Added SILC errno API to lib/silcutil/silcerrno.[ch].  Added
diff --git a/TODO b/TODO
index 3dccfb86103c677db86737ba366b273745a7c29e..8fbf2c34e1f9e2788f83ba68f05f78cd31002b87 100644 (file)
--- a/TODO
+++ b/TODO
@@ -103,15 +103,7 @@ Runtime library, lib/silcutil/
 
  o Add directory opening/traversing functions
 
- o silc_getopt routines
-
- o Add silc_stream_get_root and add get_root stream operation.  It
-   returns the root of the stream or NULL if stream doesn't have root.
-
- o Change some stream routines (like socket stream API) to accept ANY
-   stream and use silc_stream_get_root to get the socket stream from the
-   given stream.  This will make various stream APIs more easier to use
-   when user doesn't have to dig up the correct stream.
+ o silc_getopt routines (***DONE)
 
  o The SILC Event signals.  Asynchronous events that can be created,
    connected to and signalled.  Either own event routines or glued into
@@ -201,13 +193,6 @@ Runtime library, lib/silcutil/
 
  o Thread pool API.  Add this to lib/silcutil/silcthread.[ch].         (***DONE)
 
- o Fast mutex implementation.  Fast rwlock implementation.  Mutex and
-   rwlock implementation using atomic operations.
-
- o Compression routines are missing.  The protocol supports packet
-   compression thus it must be implemented.  SILC Zip API must be
-   defined.
-
  o Add new functions to SilcStack API in lib/silcutil/silcstack.[ch].  Add
    silc_stack_[set|get]_alignment.  It defines the default alignment used
    when allocating memory from stack.  It can be used to specify special
@@ -252,6 +237,18 @@ Runtime library, lib/silcutil/
  o Generic SilcResult that includes all possible status and
    error conditions and generic errno API. (***DONE)
 
+ (o Change some stream routines (like socket stream API) to accept ANY
+   stream and use silc_stream_get_root to get the socket stream from the
+   given stream.  This will make various stream APIs more easier to use
+   when user doesn't have to dig up the correct stream.
+
+   Add silc_stream_get_root and add get_root stream operation.  It
+   returns the root of the stream or NULL if stream doesn't have root.) maybe
+
+ (o Compression routines are missing.  The protocol supports packet
+   compression thus it must be implemented.  SILC Zip API must be
+   defined.) maybe
+
  (o SilcIpAddr abstraction.  Ipv4 and Ipv6 support to the abstaction.)
   maybe
 
@@ -259,6 +256,9 @@ Runtime library, lib/silcutil/
   to all send(), recv(), sendto() etc.  Bad thing is that we'd have to
   define all socket options, sockaddrs, etc.) maybe
 
+ (o Fast mutex implementation.  Fast rwlock implementation.  Mutex and
+   rwlock implementation using atomic operations.) not for now.
+
  (o mmap) maybe
 
 
index 4a20535e7e381ea1a96a9a6aad736fc052febbb4..8ef23141d5824e57248c277da9e9b868e0621abb 100644 (file)
@@ -254,6 +254,7 @@ extern "C" {
 #include "silcversion.h"
 
 /* SILC util library includes */
+#include "silcgetopt.h"
 #include "silclist.h"
 #include "silcstack.h"
 #include "silcmemory.h"
index 3999d3b754952bb3feba75f1691f1cfe22e8b367..b841e4421f024b60c750dbd616915a24604c8ca1 100644 (file)
@@ -75,7 +75,8 @@ libsilcutil_la_SOURCES = \
        silcenv.c       \
        silcbase64.c    \
        silcbitops.c    \
-       silcerrno.c
+       silcerrno.c     \
+       silcgetopt.c
 
 #ifdef SILC_DIST_TOOLKIT
 include_HEADERS =      \
@@ -124,7 +125,8 @@ include_HEADERS =   \
        silcenv.h       \
        silcbase64.h    \
        silcbitops.h    \
-       silcerrno.h
+       silcerrno.h     \
+       silcgetopt.h
 
 SILC_EXTRA_DIST = tests
 #endif SILC_DIST_TOOLKIT
diff --git a/lib/silcutil/silcgetopt.c b/lib/silcutil/silcgetopt.c
new file mode 100644 (file)
index 0000000..5697617
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+
+  silcgetopt.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2007 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#include "silc.h"
+
+/* Getopt, like getopt(3). */
+
+int silc_getopt(int argc, char **argv, const char *optstring, SilcGetOpt op)
+{
+  register int c;
+  register char *cp;
+  SilcBool optional = FALSE, optional_found = FALSE;
+
+  SILC_VERIFY(op);
+
+  op->opt_arg = NULL;
+
+  if (op->opt_sp == 1) {
+    if (op->opt_index >= argc ||
+       argv[op->opt_index][0] != '-' || argv[op->opt_index][1] == '\0') {
+      return -1;
+    } else if (strcmp(argv[op->opt_index], "--") == 0) {
+      op->opt_index++;
+      return -1;
+    }
+  }
+  op->opt_option = c = argv[op->opt_index][op->opt_sp];
+
+  if (c == ':' || (cp = strchr(optstring, c)) == NULL) {
+    if (op->opt_error)
+      fprintf(stderr, "%s: illegal option -- %c\n", argv[0], c);
+    if (argv[op->opt_index][++op->opt_sp] == '\0') {
+      op->opt_index++;
+      op->opt_sp = 1;
+    }
+    return '?';
+  }
+
+  if (*++cp == ':') {
+    /* Check for optional argument (::), must be written -oarg, not -o arg. */
+    if (strlen(cp) && *(cp + 1) == ':') {
+      optional = TRUE;
+      if (argv[op->opt_index][op->opt_sp + 1] != '\0')
+       optional_found = TRUE;
+    }
+
+    if (argv[op->opt_index][op->opt_sp + 1] != '\0')
+      op->opt_arg = &argv[op->opt_index++][op->opt_sp + 1];
+    else if (++op->opt_index >= argc) {
+      if (!optional && !optional_found) {
+       if (op->opt_error)
+         fprintf(stderr, "%s: option requires an argument -- %c\n",
+                 argv[0], c);
+       op->opt_sp = 1;
+       return ':';
+      }
+    } else if (!optional || optional_found)
+      op->opt_arg = argv[op->opt_index++];
+    op->opt_sp = 1;
+  } else {
+    if (argv[op->opt_index][++op->opt_sp] == '\0') {
+      op->opt_sp = 1;
+      op->opt_index++;
+    }
+    op->opt_arg = NULL;
+  }
+
+  return c;
+}
diff --git a/lib/silcutil/silcgetopt.h b/lib/silcutil/silcgetopt.h
new file mode 100644 (file)
index 0000000..ac6b216
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+
+  silcgetopt.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2007 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCGETOPT_H
+#define SILCGETOPT_H
+
+/****s* silcutil/SilcGetOptAPI/SilcGetOpt
+ *
+ * NAME
+ *
+ *    typedef struct SilcGetOptObject { ... } *SilcGetOpt, SilcGetOptStruct;
+ *
+ * DESCRIPTION
+ *
+ *    Command line option parsers structure given to silc_getopt as argument.
+ *    It contains the current parsed command line option data.
+ *
+ * SOURCE
+ */
+typedef struct SilcGetOptObject {
+  int opt_index;               /* Current option index in argv[] array */
+  int opt_option;              /* Current option character */
+  char *opt_arg;               /* Current parsed option argument */
+  SilcBool opt_error;          /* Set this to TRUE to make silc_getopt print
+                                  errors or FALSE to suppress them. */
+
+  SilcUInt16 opt_sp;           /* Internal parser index */
+} *SilcGetOpt, SilcGetOptStruct;
+/***/
+
+/****d* silcutil/SilcGetOptAPI/SILC_GETOPT_INIT
+ *
+ * NAME
+ *
+ *    #define SILC_GETOPT_INIT ...
+ *
+ * DESCRIPTION
+ *
+ *    Macro used to initialize SilcGetOptStruct before calling silc_getopt.
+ *
+ * EXAMPLE
+ *
+ *    SilcGetOptStruct op = SILC_GETOPT_INIT;
+ *
+ ***/
+#define SILC_GETOPT_INIT { 1, 0, NULL, TRUE, 1 }
+
+/****f* silcutil/SilcGetOptAPI/silc_getopt
+ *
+ * SYNOPSIS
+ *
+ *    int silc_getopt(int argc, char **argv, const char *optstring,
+ *                    SilcGetOpt op)
+ *
+ * DESCRIPTION
+ *
+ *    Parses comand line options.  This function is equivalent to getopt(3).
+ *    Returns the current parsed option, '?' if option was unknown, ':' if
+ *    required argument was missing or -1 after all options have been parsed.
+ *    If options require arguments they are available from the `op' structure,
+ *    to where the options are parsed.  The parsing is stopped immediately
+ *    when first non-option character, which is not an argument for an option,
+ *    is encountered.
+ *
+ *    The `optstring' contains the supported option characters.  One character
+ *    per option is required.  If colon (':') follows option character the
+ *    option requires an argument.  If two colons ('::') follows option
+ *    character the argument is optional.  In that case the argument must
+ *    follow the option in command line, for example -oarg, instead of -o arg.
+ *
+ * EXAMPLE
+ *
+ *    int main(int argc, char **argv)
+ *    {
+ *      SilcGetOptStruct op = SILC_GETOPT_INIT;
+ *
+ *      while ((option = silc_getopt(argc, argv, "ab:t::", &op)) != -1) {
+ *        switch (option) {
+ *          case 'a':
+ *            ...
+ *            break;
+ *          case 'b':
+ *            argument = silc_strdup(op.opt_arg);
+ *            break;
+ *          case 't':
+ *            if (op.opt_arg)
+ *              optional_argument = silc_strdup(op.opt_arg);
+ *            break;
+ *          default:
+ *            exit(1);
+ *            break;
+ *        }
+ *      }
+ *    }
+ *
+ ***/
+int silc_getopt(int argc, char **argv, const char *optstring, SilcGetOpt op);
+
+#endif /* SILCGETOPT_H */
index 30e370d55b18360dac0b5b50eddc23ab7d8b9b88..742b372872c9e7172f21b9e8c26d450110946390 100644 (file)
@@ -208,19 +208,38 @@ SilcBool dump_table()
 int main(int argc, char **argv)
 {
   SilcBool success = FALSE;
+  SilcGetOptStruct op = SILC_GETOPT_INIT;
+  int opt;
   int i;
 
-  if (argc > 1 && !strcmp(argv[1], "-d")) {
-    silc_log_debug(TRUE);
-    silc_log_debug_hexdump(TRUE);
-    silc_log_quick(TRUE);
-    silc_log_set_debug_string("*table*,*errno*");
-  }
-
-  if (argc > 1 && !strcmp(argv[1], "-D")) {
-    silc_log_debug(TRUE);
-    dump = TRUE;
-    silc_log_set_debug_string("*table*,*errno*");
+  while ((opt = silc_getopt(argc, argv, "de::D", &op)) != -1) {
+    switch (opt) {
+      case 'd':
+       silc_log_debug(TRUE);
+       silc_log_debug_hexdump(TRUE);
+       silc_log_quick(TRUE);
+       silc_log_set_debug_string("*table*,*errno*");
+       break;
+
+      case 'D':
+       silc_log_debug(TRUE);
+       dump = TRUE;
+       silc_log_set_debug_string("*table*,*errno*");
+       break;
+
+      case 'e':
+       silc_log_debug(TRUE);
+       fprintf(stderr, "%s\n", op.opt_arg);
+       if (op.opt_arg) {
+         dump = TRUE;
+         silc_log_set_debug_string(op.opt_arg);
+       }
+       break;
+
+      default:
+       exit(1);
+       break;
+    }
   }
 
   if (!alloc_table())