1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2024-12-26 01:27:28 +00:00
transmission/libtransmission/tr-getopt.c
Jordan Lee 879a2afcbd 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.
2011-01-19 13:48:47 +00:00

250 lines
6.5 KiB
C

/*
* This file Copyright (C) Mnemosyne LLC
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2(b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*
* $Id$
*/
#include <ctype.h> /* isspace() */
#include <stdio.h>
#include <stdlib.h> /* exit() */
#include <string.h>
#include "tr-getopt.h"
#ifndef MAX
#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
#endif
int tr_optind = 1;
static const char*
getArgName( const tr_option * opt )
{
const char * arg;
if( !opt->has_arg )
arg = "";
else if( opt->argName )
arg = opt->argName;
else
arg = "<args>";
return arg;
}
static int
get_next_line_len( const char * description, int maxlen )
{
int end;
int len = strlen( description );
if( len < maxlen )
return len;
end = maxlen < len ? maxlen : len;
while( ( end > 0 ) && !isspace( description[end] ) )
--end;
return end ? end : len;
}
static void
getopts_usage_line( const tr_option * opt,
int longWidth,
int shortWidth,
int argWidth )
{
int len;
const char * longName = opt->longName ? opt->longName : "";
const char * shortName = opt->shortName ? opt->shortName : "";
const char * arg = getArgName( opt );
const int d_indent = shortWidth + longWidth + argWidth + 7;
const int d_width = 80 - d_indent;
const char * d = opt->description;
printf( " %s%-*s %s%-*s %-*s ",
(shortName && *shortName ? "-" : " "), shortWidth, shortName,
(longName && *longName ? "--" : " "), longWidth, longName,
argWidth, arg );
len = get_next_line_len( d, d_width );
printf( "%*.*s\n", len, len, d );
d += len;
while( isspace( *d ) ) ++d;
while(( len = get_next_line_len( d, d_width ))) {
printf( "%*.*s%*.*s\n", d_indent, d_indent, "", len, len, d );
d += len;
while( isspace( *d ) ) ++d;
}
}
static void
maxWidth( const struct tr_option * o,
int * longWidth,
int * shortWidth,
int * argWidth )
{
const char * arg;
if( o->longName )
*longWidth = MAX( *longWidth, (int)strlen( o->longName ) );
if( o->shortName )
*shortWidth = MAX( *shortWidth, (int)strlen( o->shortName ) );
if( ( arg = getArgName( o ) ) )
*argWidth = MAX( *argWidth, (int)strlen( arg ) );
}
void
tr_getopt_usage( const char * progName,
const char * description,
const struct tr_option opts[] )
{
int longWidth = 0;
int shortWidth = 0;
int argWidth = 0;
struct tr_option help;
const struct tr_option * o;
for( o = opts; o->val; ++o )
maxWidth( o, &longWidth, &shortWidth, &argWidth );
help.val = -1;
help.longName = "help";
help.description = "Display this help page and exit";
help.shortName = "h";
help.has_arg = 0;
maxWidth( &help, &longWidth, &shortWidth, &argWidth );
if( description == NULL )
description = "Usage: %s [options]";
printf( description, progName );
printf( "\n\nOptions:\n" );
getopts_usage_line( &help, longWidth, shortWidth, argWidth );
for( o = opts; o->val; ++o )
getopts_usage_line( o, longWidth, shortWidth, argWidth );
}
static const tr_option *
findOption( const tr_option * opts,
const char * str,
const char ** setme_arg )
{
size_t matchlen = 0;
const char * arg = NULL;
const tr_option * o;
const tr_option * match = NULL;
/* find the longest matching option */
for( o = opts; o->val; ++o )
{
size_t len = o->longName ? strlen( o->longName ) : 0;
if( ( matchlen < len ) && !memcmp( str, "--", 2 )
&& !memcmp( str + 2, o->longName, len )
&& ( str[len + 2] == '\0' || ( o->has_arg && str[len + 2] == '=' ) ) )
{
matchlen = len;
match = o;
arg = str[len + 2] == '=' ? str + len + 3 : NULL;
}
len = o->shortName ? strlen( o->shortName ) : 0;
if( ( matchlen < len ) && !memcmp( str, "-", 1 )
&& !memcmp( str + 1, o->shortName, len )
&& ( str[len + 1] == '\0' || o->has_arg ) )
{
matchlen = len;
match = o;
switch( str[len + 1] )
{
case '\0':
arg = NULL; break;
case '=':
arg = str + len + 2; break;
default:
arg = str + len + 1; break;
}
}
}
if( setme_arg )
*setme_arg = arg;
return match;
}
int
tr_getopt( const char * usage,
int argc,
const char ** argv,
const tr_option * opts,
const char ** setme_optarg )
{
int i;
const char * arg = NULL;
const tr_option * o = NULL;
*setme_optarg = NULL;
/* handle the builtin 'help' option */
for( i = 1; i < argc; ++i )
{
if( !strcmp( argv[i], "-h" ) || !strcmp( argv[i], "--help" ) )
{
tr_getopt_usage( argv[0], usage, opts );
exit( 0 );
}
}
/* out of options? */
if( argc == 1 || tr_optind >= argc )
return TR_OPT_DONE;
o = findOption( opts, argv[tr_optind], &arg );
if( !o )
{
/* let the user know we got an unknown option... */
*setme_optarg = argv[tr_optind++];
return TR_OPT_UNK;
}
if( !o->has_arg )
{
/* no argument needed for this option, so we're done */
if( arg )
return TR_OPT_ERR;
*setme_optarg = NULL;
++tr_optind;
return o->val;
}
/* option needed an argument, and it was embedded in this string */
if( arg )
{
*setme_optarg = arg;
++tr_optind;
return o->val;
}
/* throw an error if the option needed an argument but didn't get one */
if( ++tr_optind >= argc )
return TR_OPT_ERR;
if( findOption( opts, argv[tr_optind], NULL ) )
return TR_OPT_ERR;
*setme_optarg = argv[tr_optind++];
return o->val;
}