static char rcs[]="@(#)$Id: emacs_std_outline.c,v 1.7 2007/08/20 00:25:14 leavens Exp $";
/*
 * emacs_std_outline -- translate emacs outline to standard outline format
 *
 * SYNOPSIS: copy the files (default stdin) to standard output,
 * replacing lines such as
 *	* basics of the Bourne shell
 *      ** Shell scripts
 *      *** executing shell scripts
 *      *** shell variables
 *      **** shell environment
 *      ***** exported vs. non-exported variables
 *      ***** PATH
 *      **** arguments
 *      ** substitutions
 *      *** conditional substitutions
 * with the following
 *	I. basics of the Bourne shell
 *       A. Shell scripts
 *        1. executing shell scripts
 *        2. shell variables
 *         a. shell environment
 *          i. exported vs. non-exported variables
 *          ii. PATH
 *         b. arguments
 *       B. substitutions
 *        1. conditional substitutions
 * If several files are named, they are considered to be from one outline,
 * so that the numbering keeps going from one file to the next.
 * Lines not starting with a * in column 1 are copied to stdout without change.
 *
 * The argument to the -n option specifies value (in arabic numerals!)
 * of the top-level outline counter.
 *
 * Returns 0 if no problems, otherwise nonzero.
 * Error messages go to standard error.
 *
 * AUTHOR: Gary T. Leavens
 */

#include "stdio.h"
#include <string.h>
#include "print_errors.h"
#include "outline.h"

int main(int argc, char *argv[])
{
  FILE *fp;
  extern void outline(FILE *fp);
  extern void outline_set_top(int);
  extern int getopt(int argc, char *const *argv, const char *optstring);
  extern int optind;
  extern char * optarg;
  int c;

  program_usage_init(argv[0], "[-n num] [file ...]");

  while ((c = getopt(argc, argv, "n:")) != -1) {
    switch (c) {
    case 'n':
      {	int topn;
	if (sscanf(optarg, "%d", &topn) != 1) {
	  error("-n option needs a number");
	}
	if (topn < 1 || topn > 99) {
	  error("-n argument %s out of range", optarg);
	}
	outline_set_top(topn-1);
      }
      break;
    default:
      usage();
      break;
    }
  }

  if (argc == optind) {
    outline(stdin);
  } else {

    for (; optind < argc; optind++) {
      /* allow single - to stand for standard input */
      if (strcmp(argv[optind], "-") == 0) {
	outline(stdin);
	continue;
      } 
      if ((fp = fopen(argv[optind], "r")) == NULL) {
	sys_err("cannot read %s", argv[optind]);
      }
      outline(fp);
      fclose(fp);
    }
  }
  return(0);
}

extern void print_outline_translation(char *, int);

void outline(FILE *fp)
     /* modifies: stdout, fp */
     /* effect: translate lines read from fp
	from emacs outline style to standard style outline */
{
  char buf[BUFSIZ];		/* lines read in from input */
  int ns;			/* number of stars in the line */
  
  while (fgets(buf, sizeof(buf), fp) != NULL) {
    if ((ns = strspn(buf, "*")) == 0) {
      fputs(buf, stdout);
    } else {
      /* process an outline line */
      print_outline_translation(buf, ns);
    }
  } /* while */
}


void print_outline_translation(char * s, int level)
     /* requires: level > 0, s has at least level stars in s[0],...,s[level] */
     /* modifies: stdout, stderr */
     /* effect: print, on stdout, level-1 spaces, an outline number for level,
	a dot (.), and the rest of the s, following the first level chars.
	(i.e., s+level).  However, if level > OUTLINE_MAX_LEVEL, print an error
	message to stderr and exit(1). */
{
  if (level > OUTLINE_MAX_LEVEL) {
    error("too deep nesting of outlines (level %d)", level);
  }

  printf("%*s%s.%s", level-1, "", outline_format_heading(level), s+level);
}
