Index: utils/ofarc/OFArc.m ================================================================== --- utils/ofarc/OFArc.m +++ utils/ofarc/OFArc.m @@ -149,11 +149,11 @@ } @implementation OFArc - (void)applicationDidFinishLaunching { - OFString *outputDir = nil, *encodingString = nil, *type = nil; + OFString *outputDir, *encodingString, *type; const of_options_parser_option_t options[] = { { 'a', @"append", 0, NULL, NULL }, { 'c', @"create", 0, NULL, NULL }, { 'C', @"directory", 1, NULL, &outputDir }, { 'E', @"encoding", 1, NULL, &encodingString }, @@ -166,13 +166,13 @@ { 't', @"type", 1, NULL, &type }, { 'v', @"verbose", 0, NULL, NULL }, { 'x', @"extract", 0, NULL, NULL }, { '\0', nil, 0, NULL, NULL } }; - OFOptionsParser *optionsParser; of_unichar_t option, mode = '\0'; of_string_encoding_t encoding = OF_STRING_ENCODING_AUTODETECT; + OFOptionsParser *optionsParser; OFArray OF_GENERIC(OFString *) *remainingArguments, *files; id archive; #ifdef OF_HAVE_SANDBOX OFSandbox *sandbox = [OFSandbox sandbox]; @@ -291,10 +291,11 @@ @"prog", [OFApplication programName], @"opt", optStr)]; } [OFApplication terminateWithStatus: 1]; + break; } } @try { if (encodingString != nil) Index: utils/ofdns/Makefile ================================================================== --- utils/ofdns/Makefile +++ utils/ofdns/Makefile @@ -10,11 +10,12 @@ ${PROG}: ${LIBOBJFW_DEP_LVL2} ${LIBOBJFWRT_DEP_LVL2} CPPFLAGS += -I../../src \ -I../../src/runtime \ -I../../src/exceptions \ - -I../.. + -I../.. \ + -DLANGUAGE_DIR=\"${datadir}/ofdns/lang\" LIBS := -L../../src -lobjfw \ -L../../src/runtime -L../../src/runtime/linklib ${RUNTIME_LIBS} \ ${LIBS} LD = ${OBJC} LDFLAGS += ${LDFLAGS_RPATH} Index: utils/ofdns/OFDNS.m ================================================================== --- utils/ofdns/OFDNS.m +++ utils/ofdns/OFDNS.m @@ -18,41 +18,95 @@ #include "config.h" #import "OFApplication.h" #import "OFArray.h" #import "OFDNSResolver.h" +#import "OFLocale.h" +#import "OFOptionsParser.h" #import "OFSandbox.h" #import "OFStdIOStream.h" @interface OFDNS: OFObject +{ + size_t _inFlight; + int _errors; +} @end OF_APPLICATION_DELEGATE(OFDNS) + +static void +help(OFStream *stream, bool full, int status) +{ + [of_stderr writeLine: + OF_LOCALIZED(@"usage", + @"Usage: %[prog] -[chst] domain1 [domain2 ...]", + @"prog", [OFApplication programName])]; + + if (full) { + [stream writeString: @"\n"]; + [stream writeLine: OF_LOCALIZED(@"full_usage", + @"Options:\n " + @"-c --class " + @" The DNS class to query (defaults to IN)\n " + @"-h --help " + @" Show this help\n " + @"-s --server" + @" The server to query\n " + @"-t --type " + @" The record type to query (defaults to ALL)")]; + } + + [OFApplication terminateWithStatus: status]; +} @implementation OFDNS - (void)resolver: (OFDNSResolver *)resolver didPerformQuery: (OFDNSQuery *)query response: (OFDNSResponse *)response exception: (id)exception { - if (exception != nil) { - [of_stderr writeFormat: @"Failed to resolve: %@\n", exception]; - [OFApplication terminateWithStatus: 1]; + _inFlight--; + + if (exception == nil) + [of_stdout writeFormat: @"%@\n", response]; + else { + [of_stderr writeLine: OF_LOCALIZED( + @"failed_to_resolve", + @"Failed to resolve: %[exception]", + @"exception", exception)]; + _errors++; } - [of_stdout writeFormat: @"%@\n", response]; - - [OFApplication terminate]; + if (_inFlight == 0) + [OFApplication terminateWithStatus: _errors]; } - (void)applicationDidFinishLaunching { - OFArray OF_GENERIC(OFString *) *arguments = [OFApplication arguments]; - of_dns_class_t DNSClass = OF_DNS_CLASS_ANY; - of_dns_record_type_t recordType = OF_DNS_RECORD_TYPE_ALL; - OFDNSQuery *query; + OFString *DNSClassString, *server, *recordTypeString; + const of_options_parser_option_t options[] = { + { 'c', @"class", 1, NULL, &DNSClassString }, + { 'h', @"help", 0, NULL, NULL }, + { 's', @"server", 1, NULL, &server }, + { 't', @"type", 1, NULL, &recordTypeString }, + { '\0', nil, 0, NULL, NULL } + }; + OFOptionsParser *optionsParser; + of_unichar_t option; + OFArray OF_GENERIC(OFString *) *remainingArguments; OFDNSResolver *resolver; + of_dns_class_t DNSClass; + of_dns_record_type_t recordType; + +#ifdef OF_HAVE_FILES +# ifndef OF_AMIGAOS + [OFLocale addLanguageDirectory: @LANGUAGE_DIR]; +# else + [OFLocale addLanguageDirectory: @"PROGDIR:/share/ofdns/lang"]; +# endif +#endif #ifdef OF_HAVE_SANDBOX OFSandbox *sandbox = [[OFSandbox alloc] init]; @try { sandbox.allowsStdIO = true; @@ -62,34 +116,86 @@ } @finally { [sandbox release]; } #endif - if (arguments.count < 1 || arguments.count > 4) { - [of_stderr writeFormat: - @"Usage: %@ host [type [class [server]]]\n", - [OFApplication programName]]; - [OFApplication terminateWithStatus: 1]; + optionsParser = [OFOptionsParser parserWithOptions: options]; + while ((option = [optionsParser nextOption]) != '\0') { + switch (option) { + case 'h': + help(of_stdout, true, 0); + break; + case ':': + if (optionsParser.lastLongOption != nil) + [of_stderr writeLine: OF_LOCALIZED( + @"long_option_required_argument", + @"%[prog]: Option --%[opt] requires an " + @"argument", + @"prog", [OFApplication programName], + @"opt", optionsParser.lastLongOption)]; + else { + OFString *optStr = [OFString + stringWithFormat: @"%C", + optionsParser.lastOption]; + [of_stderr writeLine: OF_LOCALIZED( + @"option_requires_argument", + @"%[prog]: Option -%[opt] requires an " + @"argument", + @"prog", [OFApplication programName], + @"opt", optStr)]; + } + + [OFApplication terminateWithStatus: 1]; + break; + case '?': + if (optionsParser.lastLongOption != nil) + [of_stderr writeLine: OF_LOCALIZED( + @"unknown_long_option", + @"%[prog]: Unknown option: --%[opt]", + @"prog", [OFApplication programName], + @"opt", optionsParser.lastLongOption)]; + else { + OFString *optStr = [OFString + stringWithFormat: @"%C", + optionsParser.lastOption]; + [of_stderr writeLine: OF_LOCALIZED( + @"Unknown_option", + @"%[prog]: Unknown option: -%[opt]", + @"prog", [OFApplication programName], + @"opt", optStr)]; + } + + [OFApplication terminateWithStatus: 1]; + break; + } } + + remainingArguments = optionsParser.remainingArguments; + + if (remainingArguments.count < 1) + help(of_stderr, false, 1); resolver = [OFDNSResolver resolver]; - - if (arguments.count >= 2) - recordType = of_dns_record_type_parse( - [arguments objectAtIndex: 1]); - - if (arguments.count >= 3) - DNSClass = of_dns_class_parse([arguments objectAtIndex: 2]); - - if (arguments.count >= 4) { - resolver.configReloadInterval = 0; - resolver.nameServers = - [arguments objectsInRange: of_range(3, 1)]; - } - - query = [OFDNSQuery queryWithDomainName: [arguments objectAtIndex: 0] - DNSClass: DNSClass - recordType: recordType]; - [resolver asyncPerformQuery: query - delegate: self]; + recordType = (recordTypeString != nil + ? of_dns_record_type_parse(recordTypeString) + : OF_DNS_RECORD_TYPE_ALL); + DNSClass = (DNSClassString != nil + ? of_dns_class_parse(DNSClassString) + : OF_DNS_CLASS_IN); + + if (server != nil) { + resolver.configReloadInterval = 0; + resolver.nameServers = [OFArray arrayWithObject: server]; + } + + _inFlight = remainingArguments.count; + for (OFString *domainName in remainingArguments) { + OFDNSQuery *query = + [OFDNSQuery queryWithDomainName: domainName + DNSClass: DNSClass + recordType: recordType]; + + [resolver asyncPerformQuery: query + delegate: self]; + } } @end