chiark / gitweb /
client/adh-query.c: Surprising comma rather than semicolon.
[adns.git] / client / adh-opts.c
index 7c2c42bfc2572bdf117eef03a738fcce2a7374a6..08310e089d19939c7672d6bd7156f73b57ec700e 100644 (file)
@@ -4,12 +4,11 @@
  *   option handling tables etc.
  */
 /*
- *  This file is
- *    Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
- *
- *  It is part of adns, which is
- *    Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
- *    Copyright (C) 1999 Tony Finch <dot@dotat.at>
+ *  This file is part of adns, which is
+ *    Copyright (C) 1997-2000,2003,2006  Ian Jackson
+ *    Copyright (C) 1999-2000,2003,2006  Tony Finch
+ *    Copyright (C) 1991 Massachusetts Institute of Technology
+ *  (See the file INSTALL for full details.)
  *  
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
  */
 
+#include "adnshost.h"
+
 int ov_env=1, ov_pipe=0, ov_asynch=0;
 int ov_verbose= 0;
+adns_rrtype ov_type= adns_r_none;
 int ov_search=0, ov_qc_query=0, ov_qc_anshost=0, ov_qc_cname=1;
+int ov_tcp=0, ov_cname=0, ov_format=fmt_default;
+char *ov_id= 0;
 struct perqueryflags_remember ov_pqfr = { 1,1,1, tm_none };
-int ov_tcp=0, ov_cname=0;
 
-static const struct optinfo global_options[]= {
+static const struct optioninfo global_options[]= {
   { ot_desconly, "global binary options:" },
   { ot_flag,             "Do not look at environment variables at all",
     "e", "env",            &ov_env, 0 },
@@ -40,6 +43,14 @@ static const struct optinfo global_options[]= {
     "f", "pipe",           &ov_pipe, 1 },
   { ot_flag,             "Allow answers to be reordered",
     "a", "asynch",         &ov_asynch, 1 },
+  
+  { ot_desconly, "answer/error output format and destination (see below):" },
+  { ot_value,            "Answers to stdout, errors as messages to stderr (default)",
+    "Fs", "fmt-simple",    &ov_format, fmt_simple },
+  { ot_value,            "Answers and errors both to stdout in parseable format",
+    "Fi", "fmt-inline",    &ov_format, fmt_inline },
+  { ot_value,            "Fully-parseable output format (default for --asynch)",
+    "Fa", "fmt-asynch",    &ov_format, fmt_asynch },
                         
   { ot_desconly, "global verbosity level:" },
   { ot_value,            "Do not print anything to stderr",
@@ -50,16 +61,24 @@ static const struct optinfo global_options[]= {
     "Vd", "debug",         &ov_verbose, adns_if_debug },
                         
   { ot_desconly, "other global options:" },
+  { ot_funcarg,          "Configuration to use instead of /etc/resolv.conf",
+    0, "config",           0,0, of_config, "<config-text>" },
+  { ot_func,             "Print version number",
+    0, "version",          0,0, of_version },
   { ot_func,             "Print usage information",
     0, "help",             0,0, of_help },
 
   { ot_end }
 };
 
-static const struct optinfo perquery_options[]= {
+static const struct optioninfo perquery_options[]= {
   { ot_desconly, "per-query options:" },
   { ot_funcarg,          "Query type (see below)",
     "t", "type",           0,0, &of_type, "type" },
+  { ot_funcarg,          "Do reverse query (address -> name lookup)",
+    "i", "ptr",            0,0, &of_ptr, "addr" },
+  { ot_funcarg2,         "Lookup in in-addr-like `zone' (eg MAPS RBL)",
+    0, "reverse",          0,0, &of_reverse, "addr","zone" },
 
   { ot_desconly, "per-query binary options:" },
   { ot_flag,             "Use the search list",
@@ -97,24 +116,24 @@ static const struct optinfo perquery_options[]= {
   
   { ot_desconly, "asynchronous/pipe mode options:" },
   { ot_funcarg,          "Set <id>, default is decimal sequence starting 0",
-    "i", "asynch-id",      0,0, &of_asynch_id, "id" },
-  { ot_funcarg,          "Cancel the query with id <id>",
+    0, "asynch-id",        0,0, &of_asynch_id, "id" },
+  { ot_funcarg,          "Cancel the query with id <id> (no error if not found)",
     0, "cancel-id",        0,0, &of_cancel_id, "id" },
 
   { ot_end }
 };
 
 static void printusage(void) {
-  static const struct optinfo *const all_optiontables[]= {
+  static const struct optioninfo *const all_optiontables[]= {
     global_options, perquery_options, 0
   };
 
-  const struct optinfo *const *oiap, *oip=0;
+  const struct optioninfo *const *oiap, *oip=0;
   int maxsopt, maxlopt, l;
 
   maxsopt= maxlopt= 0;
   
-  for (oiap=alloptions; *oiap; oiap++) {
+  for (oiap=all_optiontables; *oiap; oiap++) {
     for (oip=*oiap; oip->type != ot_end; oip++) {
       if (oip->type == ot_funcarg) continue;
       if (oip->sopt) { l= strlen(oip->sopt); if (l>maxsopt) maxsopt= l; }
@@ -131,7 +150,7 @@ static void printusage(void) {
        "       adnshost [global-opts] [query-opts] -f|--pipe\n",
        stdout);
 
-  for (oiap=alloptions; *oiap; oiap++) {
+  for (oiap=all_optiontables; *oiap; oiap++) {
     putchar('\n');
     for (oip=*oiap; oip->type != ot_end; oip++) {
       switch (oip->type) {
@@ -178,6 +197,15 @@ static void printusage(void) {
                 oip->desc);
        }
        break;
+      case ot_funcarg2:
+       assert(!oip->sopt);
+       l= (maxlopt + maxsopt - 2 -
+           (strlen(oip->lopt) + strlen(oip->argdesc) + strlen(oip->argdesc2)));
+         printf(" --%s <%s> <%s>%*s%s\n",
+                oip->lopt, oip->argdesc, oip->argdesc2,
+                l>2 ? l : 2, "",
+                oip->desc);
+       break;
       case ot_desconly:
        printf("%s\n", oip->desc);
        break;
@@ -210,11 +238,14 @@ static void printusage(void) {
        "or if the <owner> domain refers to a CNAME and --show-cname is on\n"
        "   [<owner>] [<ttl>] CNAME <cname>\n"
        "   [<cname>] [<ttl>] <type> <data>\n"
-       "When a query fails you get a line like:\n"
- "   ; failed <statustype> [<owner>] [<ttl>] [<type>] <status> \"<status string>\"\n"
-       "\n"
-       "If you use --asynch each answer (success or failure) is preceded by a line\n"
-       "   <id> <statustype> <status> <nrrs> [<cname>] \"<status string>\"\n"
+       "When a query fails you get an error message to stderr (with --fmt-simple).\n"
+       "Specify --fmt-inline for lines like this (broken here for readability):\n"
+       "   ; failed <statustype> <statusnum> <statusabbrev> \\\n"
+       "       [<owner>] [<ttl>] [<cname>] \"<status string>\"\n"
+       "If you use --fmt-asynch, which is the default for --asynch,\n"
+       "each answer (success or failure) is preceded by a line\n"
+       "   <id> <nrrs> <statustype> <statusnum> <statusabbrev> \\\n"
+       "       [<owner>] [<ttl>] [<cname>] \"<status string>\"\n"
        "where <nrrs> is the number of RRs that follow and <cname> will be `$' or\n"
        "the CNAME target; the CNAME indirection and error formats above are not used.\n"
        "\n"
@@ -231,16 +262,96 @@ static void printusage(void) {
        " 11   usage problems\n"
        "\n"
        "Query types (see adns.h; default is addr):\n"
-       "  ns  soa  ptr  mx  rp  addr       - enhanced versions\n"
-       "  cname  hinfo  txt                - types with only one version\n"
-       "  a  ns-  soa-  ptr-  mx-  rp-     - _raw versions\n",
+       "  ns  soa  ptr  mx  rp  srv  addr       - enhanced versions\n"
+       "  cname  hinfo  txt                     - types with only one version\n"
+       "  a  ns-  soa-  ptr-  mx-  rp-  srv-    - _raw versions\n"
+       "  type<number>                          - `unknown' type, RFC3597\n"
+       "Default is addr, or ptr for -i/--ptr queries\n",
        stdout);
   if (ferror(stdout)) sysfail("write usage message",errno);
 }
 
-static void of_help(const struct optinfo *oi, const char *arg) {
+void of_version(const struct optioninfo *oi, const char *arg, const char *arg2) {
+  VERSION_PRINT_QUIT("adnshost");
+}
+
+void of_help(const struct optioninfo *oi, const char *arg, const char *arg2) {
   printusage();
   if (fclose(stdout)) sysfail("finish writing output",errno);
-  exit(0);
+  quitnow(0);
+}
+
+typedef int comparer_type(const char **optp, const struct optioninfo *entry);
+
+static int oc_long(const char **optp, const struct optioninfo *entry) {
+  return entry->lopt && !strcmp(*optp,entry->lopt);
 }
 
+static int oc_short(const char **optp, const struct optioninfo *entry) {
+  const char *sopt;
+  int l;
+
+  sopt= entry->sopt;
+  if (!sopt) return 0;
+  l= strlen(sopt);
+  if (memcmp(*optp,sopt,l)) return 0;
+  (*optp) += l;
+  return 1;
+}
+
+static const struct optioninfo *find1(const char **optp,
+                                     const struct optioninfo *table,
+                                     comparer_type *comparer) {
+  for (;;) {
+    if (table->type == ot_end) return 0;
+    if (comparer(optp,table)) return table;
+    table++;
+  }
+}
+
+static const struct optioninfo *find(const char **optp,
+                                    const char *prefix,
+                                    comparer_type *comparer) {
+  const struct optioninfo *oip;
+  const char *opt;
+
+  opt= *optp;
+  oip= find1(optp,perquery_options,comparer);
+  if (oip) return oip;
+  oip= find1(optp,global_options,comparer);
+  if (!oip) usageerr("unknown option %s%s",prefix,opt);
+  if (ads) usageerr("global option %s%s specified after query domain(s)",prefix,opt);
+  return oip;
+}
+
+const struct optioninfo *opt_findl(const char *opt) { return find(&opt,"--",oc_long); }
+const struct optioninfo *opt_finds(const char **optp) { return find(optp,"-",oc_short); }
+
+static void noninvert(const struct optioninfo *oip) NONRETURNING;
+static void noninvert(const struct optioninfo *oip) {
+  usageerr("option %s%s%s%s%s may not be inverted",
+          oip->sopt ? "-" : "", oip->sopt ? oip->sopt : "",
+          oip->lopt && oip->sopt ? " / " : "",
+          oip->lopt ? "--" : "", oip->lopt ? oip->lopt : "");
+}
+
+void opt_do(const struct optioninfo *oip, int invert,
+           const char *arg, const char *arg2) {
+  switch (oip->type) {
+  case ot_flag:
+    assert(!arg);
+    *oip->storep= !invert;
+    return;
+  case ot_value:
+    assert(!arg);
+    if (invert) noninvert(oip);
+    *oip->storep= oip->value;
+    return;
+  case ot_func: case ot_funcarg: case ot_funcarg2:
+    if (invert) noninvert(oip);
+    oip->func(oip,arg,arg2);
+    return;
+  default:
+    abort();
+  }
+}