/* tag: Tom Lord Tue Dec  4 14:41:52 2001 (piw-glob.c)
 */
/* piw-glob.c -
 *
 ****************************************************************
 * Copyright (C) 1999 Tom Lord
 * 
 * See the file "COPYING.PIW" for further information about
 * the copyright and warranty status of this work.
 */


#include "hackerlab/os/errno-to-string.h"
#include "hackerlab/os/sys/socket.h"
#include "hackerlab/os/netinet/in.h"
#include "hackerlab/os/arpa/inet.h"
#include "hackerlab/os/netdb.h"
#include "hackerlab/char/char-class.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/vu/url-fd.h"
#include "hackerlab/cmd/main.h"



static t_uchar * program_name = "piw-glob";
static t_uchar * usage = "[options]";
static t_uchar * version_string = "1.0";


#define OPTS(OP, OP2) \
  OP (opt_help_msg, "h", "help", 0, "Display a help message and exit.") \
  OP (opt_version, "V", "version", 0, "Display a release identifier and exit.") \
  OP (opt_output, "o url", "output=url", 1, "Write output on URL.") \
  OP (opt_exand, "x path", "expand path", 1, "Print the expansion of path.") \
  OP (opt_gethost, "g host", "gethost host", 1, "Print the address of an internet HOST.")
  
enum options
{
  OPTS (OPT_ENUM, OPT_IGN)  
};

struct opt_desc opts[] = 
{
  OPTS (OPT_DESC, OPT_DESC)
    {-1, 0, 0, 0, 0}
};



int
main (int argc, char * argv[])
{
  int errn;
  int o;
  struct opt_parsed * option;
  int output_fd_specified;
  int output_fd;

  url_fd_push_handler (0);

  option = 0;
  output_fd_specified = 0;
  output_fd = 1;

  while (1)
    {
      o = opt_standard (lim_use_must_malloc, &option, opts, &argc, argv, program_name, usage, version_string, 0, opt_help_msg, -1, opt_version);
      if (o == opt_none)
	break;
      switch (o)
	{
	default:
	  safe_printfmt (2, "unhandled option `%s'\n", option->opt_string);
	  panic ("internal error parsing arguments");

	usage_error:
	  opt_usage (2, argv[0], program_name, usage, 1);
	  panic_exit ();

#if 0
	bogus_arg:
	  safe_printfmt (2, "ill-formed argument for `%s' (`%s')\n", option->opt_string, option->arg_string);
	  goto usage_error;
#endif

	case opt_output:
	  {
	   if (output_fd_specified)
	     {
	       printfmt (&errn, 2, "`%s' may only be specified once.\n", option->arg_string);
	       goto usage_error;
	     }

	   output_fd_specified = 1;
	   output_fd = vu_open (&errn, option->arg_string, O_WRONLY | O_CREAT, 0666);
	   if (output_fd < 0)
	     {
	       printfmt (&errn, 2, "unable to open \"%s\" (%s)\n", option->arg_string, errno_to_string (errn));
	       exit (1);
	     }
	   break;
	  }

	case opt_exand:
	  {
	    char * expansion;

	    expansion = file_name_tilde_expand (lim_use_must_malloc, option->arg_string);
	    if (0 > printfmt (&errn, output_fd, "%s\n", expansion))
	      panic ("unable to write expanded file name");
	    break;
	  }

	case opt_gethost:
	  {
	    if (char_is_digit (*option->arg_string))
	      {
		int x;
		struct in_addr addr;

		x = inet_aton (option->arg_string, &addr);
		if (!x)
		  {
		    printfmt (&errn, 2, "`%s' is not an internet address\n", option->arg_string);
		    exit (1);
		  }
		if (0 > printfmt (&errn, output_fd, "%s\n", option->arg_string))
		  panic ("unable to write host address");
	      }
	    else
	      {
		struct hostent * hostentp;
		struct in_addr * addrp;
		char * answer;
		hostentp = gethostbyname (option->arg_string);
		if (!hostentp)
		  {
		    printfmt (&errn, 2, "unable to locate host entry for `%s'\n", option->arg_string);
		    exit (1);
		  }
		if (hostentp->h_addrtype != AF_INET)
		  {
		    printfmt (&errn, 2, "`%s' is not an internet address\n", option->arg_string);
		    exit (1);
		  }
		addrp = (struct in_addr *)hostentp->h_addr;
		answer = inet_ntoa (*addrp);
		if (0 > printfmt (&errn, output_fd, "%s\n", answer))
		  panic ("unable to write host address");
	      }
	    break;
	  }
	}
    }
  return 0;
}
