/*************************************************************************** * Copyright (C) 2003 by beltorak * * beltorak@ananzi.co.za * * * * 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; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #define _GNU_SOURCE #include #include #include #include #include "options.h" #define PERR(fmt, ...) fprintf(stderr, fmt "\n", ## __VA_ARGS__) /* Prints option help */ void cat_option_help( struct tbt_option* option_list ) { int i = 0; size_t pos; /* screen position */ int MID_SCREEN = 30; printf("Note that options that take an optional argument must not be\n"); printf("separated from eachother. For example, \"-D[val]\" == \"-Dwhatever\"\n"); printf("and \"--option[=arg]\" == \"--option=arg\"\n"); while(option_list[i].type) { pos = 0; switch (option_list[i].type) { case 't': printf("\n%s\n", option_list[i].help_str); break; case '\n': putchar('\n'); break; case 'd': while(pos++ < MID_SCREEN) putchar(' '); printf("%s\n", option_list[i].help_str); break; default: if(option_list[i].short_opt) { printf(" -%c", option_list[i].short_opt); pos += 4; if(option_list[i].long_opt) { printf(", "); pos += 2; } else { if(option_list[i].type == 'y') { printf(" %s ", option_list[i].arg_name); pos += 4 + strlen(option_list[i].arg_name); } else if(option_list[i].type == 'o') { printf("[%s] ", option_list[i].arg_name); pos += 4 + strlen(option_list[i].arg_name); } while(pos++ < MID_SCREEN) putchar(' '); } } else { pos += 6; printf(" "); } if(option_list[i].long_opt) { printf("--%s", option_list[i].long_opt); pos += 2 + strlen(option_list[i].long_opt); if(option_list[i].type == 'y') { printf("=%s", option_list[i].arg_name); pos += 1 + strlen(option_list[i].arg_name); } else if(option_list[i].type == 'o') { printf("[=%s]", option_list[i].arg_name); pos += 3 + strlen(option_list[i].arg_name); } } while(pos++ < MID_SCREEN) putchar(' '); printf("%s\n", option_list[i].help_str); } ++i; } return; } /* -- end cat_option_help() -- */ /* Creates and returns a short option string suitable for use with getopt(). */ char* get_short_optstring( struct tbt_option* option_list ) { /* get a size count of option_list */ int i = 0; while(option_list[i].type) ++i; /* Account for arg requirements (':' or '::') and trailing NIL */ i *= 3; ++i; char* short_optstring = malloc(i); if( ! short_optstring ) return NULL; int j = 0; int k = 0; while(option_list[j].type) { if(option_list[j].short_opt) { switch(option_list[j].type) { case '\n': case 't': case 'd': ++j; break; case 'y': short_optstring[k++] = option_list[j++].short_opt; short_optstring[k++] = ':'; break; case 'o': short_optstring[k++] = option_list[j++].short_opt; short_optstring[k++] = ':'; short_optstring[k++] = ':'; break; case 'n': short_optstring[k++] = option_list[j++].short_opt; break; default: /* unhandled tbt_option type */ free(short_optstring); return NULL; } /* bounds checking */ if(k >= i) { PERR("Fatal error: j @ %d >= i @ %d", j, i); exit(EXIT_FAILURE); } } else ++j; } short_optstring[k] = 0; return short_optstring; } /* -- end get_short_optstring() -- */ /* allocates (and returns ptr to) an array of 'struct option's suitable for passing to getopt_long() */ struct option* get_long_opttable(struct tbt_option* option_list ) { int i = 0; while(option_list[i].type) ++i; ++i; struct option* long_opttable = malloc(i*sizeof(struct option)); int j = 0; int k = 0; while(option_list[j].type) { int hasarg = 0; if(option_list[j].long_opt) { switch(option_list[j].type) { case '\n': case 'd': case 't': ++j; break; /* The following depend on the values specified in man getopt_long */ case 'o': ++hasarg; case 'y': ++hasarg; case 'n': long_opttable[k].name = option_list[j].long_opt; long_opttable[k].has_arg = hasarg; long_opttable[k].flag = NULL; long_opttable[k++].val = option_list[j++].short_opt; break; default: free(long_opttable); return NULL; break; } /* bounds checking */ if(k >= i) { PERR("Fatal error: j @ %d >= i @ %d", j, i); exit(EXIT_FAILURE); } } else ++j; } long_opttable[k].name = 0; long_opttable[k].has_arg = 0; long_opttable[k].flag = 0; long_opttable[k].val = 0; return long_opttable; } /* -- end get_long_opttable() */ /* This function takes the results from getopt_long() and runs the function specified in the option_list. Returns the results of the function called, or -1 if the option passed is not found. Prefers short_opt to long_opt. */ int process_option( struct tbt_option* opt_list, char short_opt, const char* long_opt ) { while(opt_list->type) { switch( opt_list->type ){ case 'y': case 'n': case 'o': if( short_opt ) { if( opt_list->short_opt == short_opt ) return (opt_list->opt_func)(optarg); } else if( opt_list->long_opt ) { if( strcmp(long_opt, opt_list->long_opt) == 0 ) return (opt_list->opt_func)(optarg); } break; default: break; } ++opt_list; } PERR("Option Passed does not exist in opt_list"); return -1; } /* -- end process_option() -- */ /* end options.c */