From 562927f2871fedc49ec9e3e7e74bf93cbcafb71e Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Tue, 25 Dec 2007 11:56:14 +0000 Subject: [PATCH] Added silc_getopt. --- CHANGES.RUNTIME | 4 + TODO | 32 +++---- includes/silc.h.in | 1 + lib/silcutil/Makefile.ad | 6 +- lib/silcutil/silcgetopt.c | 85 ++++++++++++++++++ lib/silcutil/silcgetopt.h | 115 ++++++++++++++++++++++++ lib/silcutil/tests/test_silchashtable.c | 41 ++++++--- 7 files changed, 255 insertions(+), 29 deletions(-) create mode 100644 lib/silcutil/silcgetopt.c create mode 100644 lib/silcutil/silcgetopt.h diff --git a/CHANGES.RUNTIME b/CHANGES.RUNTIME index f0995733..4c2cef64 100644 --- a/CHANGES.RUNTIME +++ b/CHANGES.RUNTIME @@ -1,3 +1,7 @@ +Tue Dec 25 13:53:07 EET 2007 Pekka Riikonen + + * Added silc_getopt to lib/silcutil/silcgetopt.[ch]. + Sat Dec 22 19:55:28 EET 2007 Pekka Riikonen * Added SILC errno API to lib/silcutil/silcerrno.[ch]. Added diff --git a/TODO b/TODO index 3dccfb86..8fbf2c34 100644 --- 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 diff --git a/includes/silc.h.in b/includes/silc.h.in index 4a20535e..8ef23141 100644 --- a/includes/silc.h.in +++ b/includes/silc.h.in @@ -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" diff --git a/lib/silcutil/Makefile.ad b/lib/silcutil/Makefile.ad index 3999d3b7..b841e442 100644 --- a/lib/silcutil/Makefile.ad +++ b/lib/silcutil/Makefile.ad @@ -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 index 00000000..56976176 --- /dev/null +++ b/lib/silcutil/silcgetopt.c @@ -0,0 +1,85 @@ +/* + + silcgetopt.c + + Author: Pekka Riikonen + + 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 index 00000000..ac6b2168 --- /dev/null +++ b/lib/silcutil/silcgetopt.h @@ -0,0 +1,115 @@ +/* + + silcgetopt.h + + Author: Pekka Riikonen + + 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 */ diff --git a/lib/silcutil/tests/test_silchashtable.c b/lib/silcutil/tests/test_silchashtable.c index 30e370d5..742b3728 100644 --- a/lib/silcutil/tests/test_silchashtable.c +++ b/lib/silcutil/tests/test_silchashtable.c @@ -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()) -- 2.24.0