/* unfold.c: the (near) opposite of standard `fold'
 *
 ****************************************************************
 * Copyright (C) 2001, 2002, 2003  TOM LORD
 * 
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "config-options.h"
#include "hackerlab/cmd/main.h"


/* __stdc__ prototypes for static functions */
static long trim_nl (t_uchar * str, long len);



static t_uchar * program_name = "unfold";
static t_uchar * usage = "unfold [options]";
static t_uchar * version_string = (cfg__std__package " from regexps.com\n"
				   "\n"
				   "Copyright 2001, 2002, 2003 Tom Lord\n"
				   "\n"
				   "This is free software; see the source for copying conditions.\n"
				   "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
				   "PARTICULAR PURPOSE.\n"
				   "\n"
				   "Report bugs to " cfg__text_utils_bug_mail ".\n"
				   "\n");


#define OPTS(OP, OP2) \
  OP (opt_help_msg, "h", "help", 0, \
      "Display a help message and exit.") \
  OP (opt_long_help, "H", 0, 0, \
      "Display a verbose help message and exit.") \
  OP (opt_version, "V", "version", 0, \
      "Display a release identifier string") \
  OP2 (opt_version, 0, 0, 0, "and exit.") \
  OP (opt_width, "w", "width WIDTH", 1, \
      "Set the output line width (default 80).")

static t_uchar long_help[] = ("combine short lines into longer lines\n"
			      "Lines from standard input are copied to standard output,\n"
			      "combining adjacent lines into single lines, separated by a\n"
			      "space.\n"
			      "\n"
			      "Each output line contains no less than one input line, and\n"
			      "subject to that constraint, no more WIDTH characters.\n"
			      "(Note that input lines longer than WIDTH characters produce\n"
			      "output lines longer than WIDTH characters.)\n");

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;
  t_uint line_width;

  option = 0;
  line_width = 80;

  safe_buffer_fd (0, 0, O_RDONLY, 0);
  safe_buffer_fd (1, 0, O_WRONLY, 0);

  while (1)
    {
      o = opt_standard (lim_use_must_malloc, &option, opts, &argc, argv, program_name, usage, version_string, long_help, opt_help_msg, opt_long_help, 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);
	  exit (1);

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

	case opt_width:
	  if (0 > cvt_decimal_to_uint (&errn, &line_width, option->arg_string, str_length (option->arg_string)))
	    goto bogus_arg;
	}
    }


  {
    t_uchar * line;
    long len;
    int this_line_width;

    this_line_width = 0;
    while (1)
      {
	safe_next_line (&line, &len, 0);
	len = trim_nl (line, len);

	if (len == 0)
	  break;

	if (line_width <= len + this_line_width)
	  {
	    if (this_line_width)
	      safe_write_retry (1, "\n", 1);
	    safe_write_retry (1, line, len);
	    this_line_width = len;
	  }
	else
	  {
	    if (this_line_width)
	      safe_write_retry (1, " ", 1);
	    safe_write_retry (1, line, len);
	    this_line_width = this_line_width + len;
	  }
      }

    if (this_line_width)
      safe_write_retry (1, "\n", 1);
  }

  
  return 0;
}




static long
trim_nl (t_uchar * str, long len)
{
  if (!len)
    return 0;

  if (str[len - 1] == '\n')
    {
      str[len - 1] = 0;
      --len;
    }

  return len;
}

/* tag: Tom Lord Tue Dec  4 14:41:26 2001 (unfold.c)
 */
