source: trunk/libtransmission/tr-getopt.c @ 6306

Last change on this file since 6306 was 6306, checked in by charles, 14 years ago

code cleanup

File size: 5.9 KB
Line 
1/*
2 * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *
22 * $Id:$
23 */
24
25#include <stdio.h>
26#include <stdlib.h> /* exit() */
27#include <string.h>
28
29#include "tr-getopt.h"
30
31#ifndef MAX
32#define MAX(a,b) (((a) > (b)) ? (a) : (b))
33#endif
34
35int tr_optind = 1;
36
37static const char*
38getArgName( const tr_option * opt )
39{
40    char * arg;
41
42    if( !opt->has_arg )
43        arg = "";
44    else if( opt->argName )
45        arg = opt->argName;
46    else
47        arg = "<args>";
48
49    return arg;
50}
51
52static void
53getopts_usage_line( const tr_option * opt,
54                    int longWidth, int shortWidth, int argWidth )
55{
56    const char * longName   = opt->longName ? opt->longName : "";
57    const char * shortName  = opt->shortName ? opt->shortName : "";
58    const char * arg        = getArgName( opt );
59    printf( "  -%*s, --%-*s %-*s  %s\n", shortWidth, shortName,
60                                         longWidth, longName,
61                                         argWidth, arg,
62                                         opt->description );
63}
64
65static void
66maxWidth( const struct tr_option * o,
67          int * longWidth, int * shortWidth, int * argWidth )
68{
69    const char * arg;
70
71    if( o->longName ) 
72        *longWidth = MAX( *longWidth, (int)strlen( o->longName ) );
73
74    if( o->shortName )
75        *shortWidth = MAX( *shortWidth, (int)strlen( o->shortName ) );
76
77    if(( arg = getArgName( o )))
78        *argWidth = MAX( *argWidth, (int)strlen( arg ) );
79}
80
81void
82tr_getopt_usage( const char              * progName,
83                 const char              * description,
84                 const struct tr_option    opts[] )
85{
86    int longWidth = 0;
87    int shortWidth = 0;
88    int argWidth = 0;
89    struct tr_option help;
90    const struct tr_option * o;
91
92    for( o=opts; o->val; ++o )
93        maxWidth( o, &longWidth, &shortWidth, &argWidth );
94
95    help.val = -1;
96    help.longName = "help";
97    help.description = "Display this help page and exit";
98    help.shortName = "h";
99    help.has_arg = 0;
100    maxWidth( &help, &longWidth, &shortWidth, &argWidth );
101
102    if( description == NULL )
103        description = "Usage: %s [options]";
104    printf( description, progName );
105    printf( "\n\nOptions:\n" );
106    getopts_usage_line( &help, longWidth, shortWidth, argWidth );
107    for( o=opts; o->val; ++o )
108        getopts_usage_line( o, longWidth, shortWidth, argWidth );
109}
110
111static const tr_option *
112findOption( const tr_option   * opts,
113            const char        * str,
114            const char       ** nested )
115{
116    size_t len;
117    const tr_option * o;
118
119    for( o=opts; o->val; ++o )
120    {
121        if( o->longName && (str[0]=='-') && (str[1]=='-') ) {
122            if( !strcmp( o->longName, str+2 ) ) {
123                if( nested ) *nested = NULL;
124                return o;
125            }
126            len = strlen( o->longName );
127            if( !memcmp( o->longName, str+2, len ) && str[len+2]=='=' ) {
128                if( nested ) *nested = str+len+3;
129                return o;
130            }
131        }
132       
133        if( o->shortName && (str[0]=='-') ) {
134            if( !strcmp( o->shortName, str+1 ) ) {
135                if( nested ) *nested = NULL;
136                return o;
137            }
138            len = strlen( o->shortName );
139            if( !memcmp( o->shortName, str+1, len ) && str[len+1]=='=' ) {
140                if( nested ) *nested = str+len+2;
141                return o;
142            }
143        }
144    }
145
146    return NULL;
147}
148
149int
150tr_getopt( const char        * usage,
151           int                 argc,
152           const char       ** argv,
153           const tr_option   * opts,
154           const char       ** setme_optarg )
155{
156    int i;
157    const char * nest = NULL;
158    const tr_option * o = NULL;
159
160    *setme_optarg = NULL; 
161 
162    /* handle the builtin 'help' option */
163    for( i=1; i<argc; ++i ) {
164        if( !strcmp(argv[i], "-h") || !strcmp(argv[i], "--help" ) ) {
165            tr_getopt_usage( argv[0], usage, opts );
166            exit( 0 );
167        }
168    }
169
170    /* out of options? */
171    if( argc==1 || tr_optind>=argc )
172        return TR_OPT_DONE;
173
174    o = findOption( opts, argv[tr_optind], &nest );
175    if( !o ) {
176        /* let the user know we got an unknown option... */
177        *setme_optarg = argv[tr_optind++];
178        return TR_OPT_UNK;
179    }
180
181    if( !o->has_arg ) {
182        /* no argument needed for this option, so we're done */
183        if( nest )
184            return TR_OPT_ERR;
185        *setme_optarg = NULL;
186        tr_optind++;
187        return o->val;
188    }
189
190    /* option needed an argument, and it was nested in this string */
191    if( nest ) {
192        *setme_optarg = nest;
193        tr_optind++;
194        return o->val;
195    }
196
197    /* throw an error if the option needed an argument but didn't get one */
198    if( ++tr_optind >= argc )
199        return TR_OPT_ERR;
200    if( findOption( opts, argv[tr_optind], NULL ))
201        return TR_OPT_ERR;
202
203    *setme_optarg = argv[tr_optind++];
204    return o->val;
205}
Note: See TracBrowser for help on using the repository browser.