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

Last change on this file since 12545 was 11709, checked in by jordan, 11 years ago

Update the copyright year in the source code comments.

The Berne Convention says that the copyright year is moot, so instead of adding another year to each file as in previous years, I've removed the year altogether from the source code comments in libtransmission, gtk, qt, utils, daemon, and cli.

Juliusz's copyright notice in tr-dht and Johannes' copyright notice in tr-lpd have been left alone; it didn't seem appropriate to modify them.

  • Property svn:keywords set to Date Rev Author Id
File size: 6.5 KB
Line 
1/*
2 * This file Copyright (C) Mnemosyne LLC
3 *
4 * This file is licensed by the GPL version 2. Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: tr-getopt.c 11709 2011-01-19 13:48:47Z jordan $
11 */
12
13#include <ctype.h> /* isspace() */
14#include <stdio.h>
15#include <stdlib.h> /* exit() */
16#include <string.h>
17
18#include "tr-getopt.h"
19
20#ifndef MAX
21 #define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
22#endif
23
24int tr_optind = 1;
25
26static const char*
27getArgName( const tr_option * opt )
28{
29    const char * arg;
30
31    if( !opt->has_arg )
32        arg = "";
33    else if( opt->argName )
34        arg = opt->argName;
35    else
36        arg = "<args>";
37
38    return arg;
39}
40
41static int
42get_next_line_len( const char * description, int maxlen )
43{
44    int end;
45    int len = strlen( description );
46
47    if( len < maxlen )
48        return len;
49
50    end = maxlen < len ? maxlen : len;
51    while( ( end > 0 ) && !isspace( description[end] ) )
52        --end;
53
54    return end ? end : len;
55}
56
57static void
58getopts_usage_line( const tr_option * opt,
59                    int               longWidth,
60                    int               shortWidth,
61                    int               argWidth )
62{
63    int len;
64    const char * longName   = opt->longName ? opt->longName : "";
65    const char * shortName  = opt->shortName ? opt->shortName : "";
66    const char * arg        = getArgName( opt );
67
68    const int d_indent = shortWidth + longWidth + argWidth + 7;
69    const int d_width = 80 - d_indent;
70    const char * d = opt->description;
71
72    printf( " %s%-*s %s%-*s %-*s ",
73            (shortName && *shortName ? "-" : " "), shortWidth, shortName,
74            (longName && *longName ? "--" : "  "), longWidth, longName,
75            argWidth, arg );
76    len = get_next_line_len( d, d_width );
77    printf( "%*.*s\n", len, len, d );
78
79    d += len;
80    while( isspace( *d ) ) ++d;
81
82    while(( len = get_next_line_len( d, d_width ))) {
83        printf( "%*.*s%*.*s\n", d_indent, d_indent, "", len, len, d );
84        d += len;
85        while( isspace( *d ) ) ++d;
86    }
87}
88
89static void
90maxWidth( const struct tr_option * o,
91          int *                    longWidth,
92          int *                    shortWidth,
93          int *                    argWidth )
94{
95    const char * arg;
96
97    if( o->longName )
98        *longWidth = MAX( *longWidth, (int)strlen( o->longName ) );
99
100    if( o->shortName )
101        *shortWidth = MAX( *shortWidth, (int)strlen( o->shortName ) );
102
103    if( ( arg = getArgName( o ) ) )
104        *argWidth = MAX( *argWidth, (int)strlen( arg ) );
105}
106
107void
108tr_getopt_usage( const char *           progName,
109                 const char *           description,
110                 const struct tr_option opts[] )
111{
112    int                      longWidth = 0;
113    int                      shortWidth = 0;
114    int                      argWidth = 0;
115    struct tr_option         help;
116    const struct tr_option * o;
117
118    for( o = opts; o->val; ++o )
119        maxWidth( o, &longWidth, &shortWidth, &argWidth );
120
121    help.val = -1;
122    help.longName = "help";
123    help.description = "Display this help page and exit";
124    help.shortName = "h";
125    help.has_arg = 0;
126    maxWidth( &help, &longWidth, &shortWidth, &argWidth );
127
128    if( description == NULL )
129        description = "Usage: %s [options]";
130    printf( description, progName );
131    printf( "\n\nOptions:\n" );
132    getopts_usage_line( &help, longWidth, shortWidth, argWidth );
133    for( o = opts; o->val; ++o )
134        getopts_usage_line( o, longWidth, shortWidth, argWidth );
135}
136
137static const tr_option *
138findOption( const tr_option * opts,
139            const char *      str,
140            const char **     setme_arg )
141{
142    size_t            matchlen = 0;
143    const char *      arg = NULL;
144    const tr_option * o;
145    const tr_option * match = NULL;
146
147    /* find the longest matching option */
148    for( o = opts; o->val; ++o )
149    {
150        size_t len = o->longName ? strlen( o->longName ) : 0;
151
152        if( ( matchlen < len ) && !memcmp( str, "--", 2 )
153          && !memcmp( str + 2, o->longName, len )
154          && ( str[len + 2] == '\0' || ( o->has_arg && str[len + 2] == '=' ) ) )
155        {
156            matchlen = len;
157            match = o;
158            arg = str[len + 2] == '=' ? str + len + 3 : NULL;
159        }
160
161        len = o->shortName ? strlen( o->shortName ) : 0;
162
163        if( ( matchlen < len ) && !memcmp( str, "-", 1 )
164          && !memcmp( str + 1, o->shortName, len )
165          && ( str[len + 1] == '\0' || o->has_arg ) )
166        {
167            matchlen = len;
168            match = o;
169            switch( str[len + 1] )
170            {
171                case '\0':
172                    arg = NULL;          break;
173
174                case '=':
175                    arg = str + len + 2; break;
176
177                default:
178                    arg = str + len + 1; break;
179            }
180        }
181    }
182
183    if( setme_arg )
184        *setme_arg = arg;
185
186    return match;
187}
188
189int
190tr_getopt( const char *      usage,
191           int               argc,
192           const char **     argv,
193           const tr_option * opts,
194           const char **     setme_optarg )
195{
196    int               i;
197    const char *      arg = NULL;
198    const tr_option * o = NULL;
199
200    *setme_optarg = NULL;
201
202    /* handle the builtin 'help' option */
203    for( i = 1; i < argc; ++i )
204    {
205        if( !strcmp( argv[i], "-h" ) || !strcmp( argv[i], "--help" ) )
206        {
207            tr_getopt_usage( argv[0], usage, opts );
208            exit( 0 );
209        }
210    }
211
212    /* out of options? */
213    if( argc == 1 || tr_optind >= argc )
214        return TR_OPT_DONE;
215
216    o = findOption( opts, argv[tr_optind], &arg );
217    if( !o )
218    {
219        /* let the user know we got an unknown option... */
220        *setme_optarg = argv[tr_optind++];
221        return TR_OPT_UNK;
222    }
223
224    if( !o->has_arg )
225    {
226        /* no argument needed for this option, so we're done */
227        if( arg )
228            return TR_OPT_ERR;
229        *setme_optarg = NULL;
230        ++tr_optind;
231        return o->val;
232    }
233
234    /* option needed an argument, and it was embedded in this string */
235    if( arg )
236    {
237        *setme_optarg = arg;
238        ++tr_optind;
239        return o->val;
240    }
241
242    /* throw an error if the option needed an argument but didn't get one */
243    if( ++tr_optind >= argc )
244        return TR_OPT_ERR;
245    if( findOption( opts, argv[tr_optind], NULL ) )
246        return TR_OPT_ERR;
247
248    *setme_optarg = argv[tr_optind++];
249    return o->val;
250}
Note: See TracBrowser for help on using the repository browser.