--- /dev/null
+/* getopts.c - Command line argument parser
+ *
+ * Whom: Steve Mertz <steve@dragon-ware.com>
+ * Date: 20010111
+ * Why: Because I couldn't find one that I liked. So I wrote this one.
+ *
+*/
+/*
+ * Copyright (c) 2001-2004 Steve Mertz <steve@dragon-ware.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Dragon Ware nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "getopts.h"
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+int option_index = 1;
+
+static const char*
+getArgName( const struct options * opt )
+{
+ if( !opt->args ) return "";
+ if( opt->argName ) return opt->argName;
+ return "<args>";
+}
+
+static void
+getopts_usage_line( const struct options * opt, int nameWidth, int shortWidth, int argWidth )
+{
+ const char * name = opt->name ? opt->name : "";
+ const char * shortName = opt->shortName ? opt->shortName : "";
+ const char * arg = getArgName( opt );
+ printf( " -%*s, --%-*s %-*s %s\n", shortWidth, shortName, nameWidth, name, argWidth, arg, opt->description );
+}
+
+/* int getopts_usage()
+ *
+ * Returns: 1 - Successful
+ */
+int getopts_usage(const char *progName, const char *usage, struct options opts[])
+{
+ int count;
+ int nameWidth = 0;
+ int shortWidth = 0;
+ int argWidth = 0;
+ struct options help;
+
+ for( count=0; opts[count].description; ++count )
+ {
+ const char * arg;
+
+ if( opts[count].name )
+ nameWidth = MAX( nameWidth, (int)strlen( opts[count].name ) );
+
+ if( opts[count].shortName )
+ shortWidth = MAX( shortWidth, (int)strlen( opts[count].shortName ) );
+
+ if(( arg = getArgName( &opts[count] )))
+ argWidth = MAX( argWidth, (int)strlen( arg ) );
+ }
+
+ if( !usage )
+ usage = "Usage: %s [options]";
+ printf( usage, progName );
+ printf( "\n\n" );
+ printf( "Usage:\n" );
+
+ help.number = -1;
+ help.name = "help";
+ help.description = "Display this help page and exit";
+ help.shortName = "h";
+ help.args = 0;
+ getopts_usage_line( &help, nameWidth, shortWidth, argWidth );
+
+ for( count=0; opts[count].description; ++count )
+ getopts_usage_line( &opts[count], nameWidth, shortWidth, argWidth );
+
+ return 1;
+}
+
+/* int getopts()
+ *
+ * Returns: -1 - Couldn't allocate memory. Please handle me.
+ * 0 - No arguements to parse
+ * # - The number in the struct for the matched arg.
+ *
+*/
+int
+getopts( const char * usage,
+ int argc,
+ char ** argv,
+ struct options * opts,
+ char ** args )
+{
+ int argCounter, sizeOfArgs;
+ if (argc == 1 || option_index == argc)
+ return 0;
+
+/* Search for '-h' or '--help' first. Then we can just exit */
+ for (argCounter = 1; argCounter < argc; argCounter++)
+ {
+ if (!strcmp(argv[argCounter], "-h") || !strcmp(argv[argCounter], "--help"))
+ {
+useage:
+fprintf( stderr, "dkdkdkdkdkd\n" );
+ getopts_usage(argv[0], usage, opts);
+ exit(0);
+ }
+ }
+/* End of -h --help section */
+
+ *args = NULL;
+ if (option_index <= argc)
+ {
+ for (argCounter = 0; opts[argCounter].number!=0; argCounter++)
+ {
+ if ((opts[argCounter].name && !strcmp(opts[argCounter].name, (argv[option_index]+2))) ||
+ (opts[argCounter].shortName && !strcmp(opts[argCounter].shortName, (argv[option_index]+1))))
+ {
+ if (opts[argCounter].args)
+ {
+ option_index++;
+ if (option_index >= argc)
+ goto useage;
+/* This grossness that follows is to support having a '-' in the argument. */
+ if (*argv[option_index] == '-')
+ {
+ int optionSeeker;
+ for (optionSeeker = 0; opts[optionSeeker].description; optionSeeker++)
+ {
+ if ((opts[optionSeeker].name &&
+ !strcmp(opts[optionSeeker].name, (argv[option_index]+2))) ||
+ (opts[optionSeeker].shortName &&
+ !strcmp(opts[optionSeeker].shortName, (argv[option_index]+1))))
+ {
+ goto useage;
+ }
+ }
+/* End of gross hack for supporting '-' in arguments. */
+ }
+ sizeOfArgs = strlen(argv[option_index]);
+#ifdef __cplusplus
+ if ((*args = (char *)calloc(1, sizeOfArgs+1)) == NULL)
+#else
+ if ((*args = calloc(1, sizeOfArgs+1)) == NULL)
+#endif
+ return -1;
+ strncpy(*args, argv[option_index], sizeOfArgs);
+ }
+ option_index++;
+ return opts[argCounter].number;
+ }
+ }
+/** The Option doesn't exist. We should warn them. */
+ //if (*argv[option_index] == '-')
+ {
+ sizeOfArgs = strlen(argv[option_index]);
+#ifdef __cplusplus
+ if ((*args = (char *)calloc(1, sizeOfArgs+1)) == NULL)
+#else
+ if ((*args = calloc(1, sizeOfArgs+1)) == NULL)
+#endif
+ return -1;
+ strncpy(*args, argv[option_index], sizeOfArgs);
+ option_index++;
+ return -2;
+ }
+ }
+ return 0;
+}
+
+
+
+
+
+
#include <stdlib.h>
#include <string.h> /* strcmp */
-#include <getopt.h>
#include <unistd.h> /* getcwd */
#include <libevent/event.h>
#include <libtransmission/utils.h>
#include <libtransmission/version.h>
+#include "getopts.h"
+
#define MY_NAME "transmission-remote"
#define DEFAULT_HOST "localhost"
#define DEFAULT_PORT TR_DEFAULT_RPC_PORT
enum { TAG_LIST, TAG_DETAILS, TAG_FILES, TAG_PEERS };
+static const char*
+getUsage( void )
+{
+ return "Transmission "LONG_VERSION_STRING" http://www.transmissionbt.com/\n"
+ "A fast and easy BitTorrent client\n"
+ "\n"
+ "Usage: "MY_NAME" [host] [options]\n"
+ " "MY_NAME" [port] [options]\n"
+ " "MY_NAME" [host:port] [options]";
+}
+
+static struct options opts[] =
+{
+ { 'a', "add", "Add torrent files", "a", 0, NULL },
+ { 'd', "downlimit", "Set the maximum download speed in KB/s", "d", 1, "<number>" },
+ { 'D', "no-downlimit", "Don't limit the download speed", "D", 0, NULL },
+ { 'e', "encryption", "Set encryption mode [required, preferred, tolerated]", "e", 1, "<mode>" },
+ { 'f', "files", "Get a file list for the current torrent(s)", "f", 0, NULL },
+ { 'g', "debug", "Print debugging information", "g", 0, NULL },
+ { 'h', "help", "Show this help page and exit", "h", 0, NULL },
+ { 'i', "info", "Show details of the current torrent(s)", "i", 0, NULL },
+ { 'l', "list", "List all torrents", "l", 0, NULL },
+ { 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", 0, NULL },
+ { 'M', "no-portmap", "Disable portmapping", "M", 0, NULL },
+ { 'n', "auth", "Set username for authentication", "n", 1, "<user>:<pass>" },
+ { 'p', "port", "Port to listen for incoming peers", "p", 1, "<port>" },
+ { 'r', "remove", "Remove the current torrent(s)", "r", 0, NULL },
+ { 's', "start", "Start the current torrent(s)", "s", 0, NULL },
+ { 'S', "stop", "Stop the current torrent(s)", "S", 0, NULL },
+ { 't', "torrent", "Set the current torrent(s)", "t", 1, "<id|hash|all>" },
+ { 'u', "uplimit", "Set the maximum upload speed in KB/s", "u", 1, "<number>" },
+ { 'U', "no-uplimit", "Don't limit the upload speed", "U", 0, NULL },
+ { 'v', "verify", "Verify the current torrent(s)", "v", 0, NULL },
+ { 'w', "download-dir", "Set the download folder for new torrents", "w", 1, "<path>" },
+ { 'x', "pex", "Enable peer exchange (PEX)", "x", 0, NULL },
+ { 'X', "no-pex", "Disable peer exchange (PEX)", "X", 0, NULL },
+ { 0, NULL, NULL, NULL, 0, NULL }
+};
+
static void
showUsage( void )
{
- puts( "Transmission "LONG_VERSION_STRING" http://www.transmissionbt.com/\n"
- "A fast and easy BitTorrent client\n"
- "\n"
- "Usage: "MY_NAME" [host] [options]\n"
- " "MY_NAME" [port] [options]\n"
- " "MY_NAME" [host:port] [options]\n"
- "\n"
- "Options:\n"
- " -a --add <torrent> Add a torrent\n"
- " -d --download-limit <int> Max download rate in KiB/s\n"
- " -D --download-unlimited No download rate limit\n"
- " -e --encryption required Require encryption for all peers\n"
- " -e --encryption preferred Prefer peers to use encryption\n"
- " -e --encryption tolerated Prefer peers to use plaintext\n"
- " -f --files <id> Get a file list for the specified torrent\n"
- " -g --debug Print debugging information\n"
- " -h --help Display this message and exit\n"
- " -i --info Detailed information for the specified torrent\n"
- " -l --list List all torrents\n"
- " -m --port-mapping Automatic port mapping via NAT-PMP or UPnP\n"
- " -M --no-port-mapping Disable automatic port mapping\n"
- " -p --port <id> Port to listen for incoming peers\n"
- " -r --remove <id> Remove the torrent with the given ID\n"
- " -r --remove all Remove all torrents\n"
- " -s --start <id> Start the torrent with the given ID\n"
- " -s --start all Start all stopped torrents\n"
- " -S --stop <id> Stop the torrent with the given ID\n"
- " -S --stop all Stop all running torrents\n"
- " -t --auth <user>:<pass> Username and password for authentication\n"
- " -u --upload-limit <int> Max upload rate in KiB/s\n"
- " -U --upload-unlimited No upload rate limit\n"
- " -v --verify <id> Verify the torrent's local data\n"
- " -w --download-dir <path> Folder to set for new torrents\n"
- " -x --enable-pex Enable peer exchange\n"
- " -X --disable-pex Disable peer exchange\n" );
+fprintf( stderr, "asdfasdfasdfasdfasdfasdf\n");
+ getopts_usage( MY_NAME, getUsage(), opts );
exit( 0 );
}
return b64;
}
+static void
+addIdArg( tr_benc * args, const char * id )
+{
+ if( !*id ) {
+ fprintf( stderr, "No torrent specified! Please use the -t option first.\n" );
+ id = "-1"; /* no torrent will have this ID, so should be a no-op */
+ } else if( strcmp( id, "all" ) ) {
+ tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), id, strlen(id) );
+ }
+}
+
static void
readargs( int argc, char ** argv )
{
- int opt;
- char optstr[] = "a:d:De:f:ghi:lmMp:r:s:S:t:u:Uv:w:xX";
-
- const struct option longopts[] =
- {
- { "add", required_argument, NULL, 'a' },
- { "download-limit", required_argument, NULL, 'd' },
- { "download-unlimited", no_argument, NULL, 'D' },
- { "encryption", required_argument, NULL, 'e' },
- { "files", required_argument, NULL, 'f' },
- { "debug", no_argument, NULL, 'g' },
- { "help", no_argument, NULL, 'h' },
- { "info", required_argument, NULL, 'i' },
- { "list", no_argument, NULL, 'l' },
- { "port-mapping", no_argument, NULL, 'm' },
- { "no-port-mapping", no_argument, NULL, 'M' },
- { "port", required_argument, NULL, 'p' },
- { "remove", required_argument, NULL, 'r' },
- { "start", required_argument, NULL, 's' },
- { "stop", required_argument, NULL, 'S' },
- { "auth", required_argument, NULL, 't' },
- { "upload-limit", required_argument, NULL, 'u' },
- { "upload-unlimited", no_argument, NULL, 'U' },
- { "verify", required_argument, NULL, 'v' },
- { "download-dir", required_argument, NULL, 'w' },
- { "enable-pex", no_argument, NULL, 'x' },
- { "disable-pex", no_argument, NULL, 'X' },
- { NULL, 0, NULL, 0 }
- };
-
- while((( opt = getopt_long( argc, argv, optstr, longopts, NULL ))) != -1 )
+ int c;
+ int addingTorrents = 0;
+ char * optarg;
+ char id[4096];
+
+ *id = '\0';
+
+ while(( c = getopts( getUsage(), argc, argv, opts, &optarg )))
{
- char * tmp;
char buf[MAX_PATH_LENGTH];
int addArg = TRUE;
- int64_t fields = 0;
tr_benc top, *args;
tr_bencInitDict( &top, 3 );
+ int64_t fields = 0;
args = tr_bencDictAddDict( &top, "arguments", 0 );
- switch( opt )
+fprintf( stderr, "got opt [%c][%s]\n", (char)c, (optarg?optarg:"(null)") );
+ switch( c )
{
- case 'g': debug = 1;
- addArg = FALSE;
+ case -2: /* special case: recognize options we didn't set above */
+fprintf( stderr, "hello world\n" );
+ if( addingTorrents ) {
+ char * tmp;
+fprintf( stderr, "adding filename [%s]\n", optarg );
+ tr_bencDictAddStr( &top, "method", "torrent-add" );
+ tr_bencDictAddStr( args, "metainfo", ((tmp=getEncodedMetainfo(optarg))) );
+ tr_free( tmp );
+ } else {
+ fprintf( stderr, "Unknown option: %s\n", optarg );
+ addArg = FALSE;
+ }
break;
- case 't': auth = tr_strdup( optarg );
+ case 'a': addingTorrents = 1;
addArg = FALSE;
break;
- case 'h': showUsage( );
- addArg = FALSE;
+ case 'd': tr_bencDictAddStr( &top, "method", "session-set" );
+ tr_bencDictAddInt( args, "speed-limit-down", numarg( optarg ) );
+ tr_bencDictAddInt( args, "speed-limit-down-enabled", 1 );
break;
- case 'a': tr_bencDictAddStr( &top, "method", "torrent-add" );
- tr_bencDictAddStr( args, "metainfo", ((tmp=getEncodedMetainfo(optarg))) );
- tr_free( tmp );
+ case 'D': tr_bencDictAddStr( &top, "method", "session-set" );
+ tr_bencDictAddInt( args, "speed-limit-down-enabled", 0 );
break;
case 'e': tr_bencDictAddStr( &top, "method", "session-set" );
tr_bencDictAddStr( args, "encryption", optarg );
| TR_RPC_TORRENT_FIELD_PRIORITIES;
tr_bencDictAddInt( args, "fields", fields );
break;
+ case 'g': debug = 1;
+ addArg = FALSE;
+ break;
case 'i': tr_bencDictAddStr( &top, "method", "torrent-get" );
tr_bencDictAddInt( &top, "tag", TAG_DETAILS );
- tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), optarg, strlen(optarg) );
+ addIdArg( args, id );
fields = TR_RPC_TORRENT_FIELD_ACTIVITY
- | TR_RPC_TORRENT_FIELD_ANNOUNCE
- | TR_RPC_TORRENT_FIELD_ERROR
- | TR_RPC_TORRENT_FIELD_HISTORY
- | TR_RPC_TORRENT_FIELD_ID
- | TR_RPC_TORRENT_FIELD_INFO
- | TR_RPC_TORRENT_FIELD_SCRAPE
- | TR_RPC_TORRENT_FIELD_SIZE
- | TR_RPC_TORRENT_FIELD_TRACKER_STATS;
+ | TR_RPC_TORRENT_FIELD_ANNOUNCE
+ | TR_RPC_TORRENT_FIELD_ERROR
+ | TR_RPC_TORRENT_FIELD_HISTORY
+ | TR_RPC_TORRENT_FIELD_ID
+ | TR_RPC_TORRENT_FIELD_INFO
+ | TR_RPC_TORRENT_FIELD_SCRAPE
+ | TR_RPC_TORRENT_FIELD_SIZE
+ | TR_RPC_TORRENT_FIELD_TRACKER_STATS;
tr_bencDictAddInt( args, "fields", fields );
break;
- case 'd': tr_bencDictAddStr( &top, "method", "session-set" );
- tr_bencDictAddInt( args, "speed-limit-down", numarg( optarg ) );
- tr_bencDictAddInt( args, "speed-limit-down-enabled", 1 );
- break;
- case 'D': tr_bencDictAddStr( &top, "method", "session-set" );
- tr_bencDictAddInt( args, "speed-limit-down-enabled", 0 );
- break;
- case 'u': tr_bencDictAddStr( &top, "method", "session-set" );
- tr_bencDictAddInt( args, "speed-limit-up", numarg( optarg ) );
- tr_bencDictAddInt( args, "speed-limit-up-enabled", 1 );
- break;
- case 'U': tr_bencDictAddStr( &top, "method", "session-set" );
- tr_bencDictAddInt( args, "speed-limit-up-enabled", 0 );
- break;
case 'l': tr_bencDictAddStr( &top, "method", "torrent-get" );
tr_bencDictAddInt( &top, "tag", TAG_LIST );
fields = TR_RPC_TORRENT_FIELD_ID
case 'M': tr_bencDictAddStr( &top, "method", "session-set" );
tr_bencDictAddInt( args, "port-forwarding-enabled", 0 );
break;
+ case 'n': auth = tr_strdup( optarg );
+ addArg = FALSE;
+ break;
case 'p': tr_bencDictAddStr( &top, "method", "session-set" );
tr_bencDictAddInt( args, "port", numarg( optarg ) );
break;
case 'r': tr_bencDictAddStr( &top, "method", "torrent-remove" );
- if( strcmp( optarg, "all" ) )
- tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), optarg, strlen(optarg) );
+ addIdArg( args, id );
break;
case 's': tr_bencDictAddStr( &top, "method", "torrent-start" );
- if( strcmp( optarg, "all" ) )
- tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), optarg, strlen(optarg) );
+ addIdArg( args, id );
break;
case 'S': tr_bencDictAddStr( &top, "method", "torrent-stop" );
- if( strcmp( optarg, "all" ) )
- tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), optarg, strlen(optarg) );
+ addIdArg( args, id );
+ break;
+ case 't': tr_strlcpy( id, optarg, sizeof( id ) );
+ addArg = FALSE;
+ break;
+ case 'u': tr_bencDictAddStr( &top, "method", "session-set" );
+ tr_bencDictAddInt( args, "speed-limit-up", numarg( optarg ) );
+ tr_bencDictAddInt( args, "speed-limit-up-enabled", 1 );
+ break;
+ case 'U': tr_bencDictAddStr( &top, "method", "session-set" );
+ tr_bencDictAddInt( args, "speed-limit-up-enabled", 0 );
break;
case 'v': tr_bencDictAddStr( &top, "method", "torrent-verify" );
- if( strcmp( optarg, "all" ) )
- tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), optarg, strlen(optarg) );
+ addIdArg( args, id );
break;
case 'w': tr_bencDictAddStr( &top, "method", "session-set" );
tr_bencDictAddStr( args, "download-dir", absolutify(buf,sizeof(buf),optarg) );
case 'X': tr_bencDictAddStr( &top, "method", "session-set" );
tr_bencDictAddInt( args, "pex-allowed", 0 );
break;
- default:
+ default: fprintf( stderr, "got opt [%d]\n", (int)c );
showUsage( );
- addArg = FALSE;
break;
}