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

Last change on this file since 7331 was 7331, checked in by charles, 12 years ago

(daemon) #1510: kysucix's patch to give an option to delete local data via RPC when removing a torrent.

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