#!/usr/bin/env /proj/axaf/bin/perl

# --8<--8<--8<--8<--
#
# Copyright (C) 2011 Smithsonian Astrophysical Observatory
#
# This file is part of text2usage
#
# text2usage is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# -->8-->8-->8-->8--

use strict;
use warnings;
use Getopt::Long;
use File::Basename;
use IO::File;

our $VERSION = '@VERSION';

our $prog = basename( $0, '.pl' );

our %param = (
    page => 1,
    f77w => 0,
    hsfx => '.h',
    csfx => '.c'
);

{
    gparam();

    mk_usage(
        IO::File->new( $param{codefile}, '>' )
          or die("unable to create $param{codefile}.\n")
    );

    mk_hdr(
        IO::File->new( $param{hdrfile}, '>' )
          or die("unable to create $param{hdrfile}\n")
    );
}

sub mk_usage {
    my ($fh) = @_;

    $fh->print(<<"END");
/* for popen on Solaris */
#ifdef SunOS
#ifndef __EXTENSIONS__
#  define __EXTENSIONS__
#endif
#else
#ifndef _POSIX_C_SOURCE
#  define _POSIX_C_SOURCE 2
#endif
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "$param{hdrfile}"

static const char $param{name}_string[] =
{
END

    my $ifh = $param{input};
    $fh->print( '  ', ( map { sprintf "%d, ", ord($_) } split(//) ), "\n" )
      while (<$ifh>);

    $fh->print(<<"END");
 0
};

END

    $param{page} ? page($fh) : nopage($fh);

    test($fh) if $param{test};

}

sub mk_hdr {
    my ($fh) = @_;

    my $uname = uc( $param{pfx} );
    $fh->print(<<"END");
#ifndef ${uname}_H
#define ${uname}_H

END

    $fh->print(<<"END") if $param{f77w};
#include "config.h"
#define USAGE_F77 F77_FUNC(usage,USAGE)

END

    $fh->print(<<"END");
int $param{name}( void );

#endif /* ! ${uname}_H */
END
}

sub gparam {
    usage(1)
      unless &GetOptions(
        \%param,
        qw{
          csfx=s
          hsfx=s
          f77w
          help
          name=s
          page!
          pfx=s
          test
          version
        }
      );
    usage(0)
      if $param{help};

    if ( $param{version} ) {
        printf("$prog $VERSION\n");
        exit 0;
    }

    $param{name} = 'usage' if !defined $param{name};

    $param{name} = uc( $param{name} ) . '_F77'
      if $param{f77w};

    if (@ARGV) {
        my $file = shift @ARGV;
        my $fh   = new IO::File $file
          or die("unable to open $file\n");
        $param{input} = $fh;
    }
    else {
        $param{input} = \*STDIN;
    }

    die("too many arguments\n")
      if @ARGV;

    die("must specify an output prefix\n")
      if !exists $param{pfx};

    $param{codefile} = "$param{pfx}$param{csfx}";

    $param{hdrfile} = "$param{pfx}$param{hsfx}";
}

sub nopage {
    my ($fh) = @_;
    $fh->print(<<"END");
int
$param{name}( void )
{
  fputs( $param{name}_string, stdout );
  return 0;
}
END
}

sub page {
    my ($fh) = @_;
    $fh->print(<<"END");

int
$param{name}( void )
{
  const char *pager;
  FILE *pipe;

  if ( ! isatty( STDOUT_FILENO ) )
    fputs( $param{name}_string, stdout );
  else
  {
    if ( NULL == ( pager = getenv( "PAGER" )) )
      pager = "more";

    if ( NULL == ( pipe = popen( pager, "w" ) ) )
      return 1;

    fputs( $param{name}_string, pipe );
    pclose( pipe );
  }
  return 0;
}
END
}

sub test {
    my ($fh) = @_;
    $fh->print(<<"END");
int main(void)
{
  usage();
}
END
}

# ANCIENT CRUFT. DON'T WRITE CODE LIKE THIS
sub usage {
    my $exit = shift;

    # turn off warnings here, so don't get Format redefined
    local $^W = 0;
    local *INPUT;
    local *OUTPUT;

    require Pod::Text;
    if ( -t STDOUT ) {

        $ENV{PAGER} ||= 'more';
        open( INPUT,  $0 )             or die("unable to open $0\n");
        open( OUTPUT, "|$ENV{PAGER}" ) or die("unable to open pager\n");

        my $parser = Pod::Text->new( width => 75 );
        $parser->parse_from_filehandle( \*INPUT, \*OUTPUT );
        close(OUTPUT);
    }
    else {
        open( INPUT, $0 ) or die("unable to open $0\n");
        my $parser = Pod::Text->new( width => 75 );
        $parser->parse_from_filehandle( \*INPUT );
    }
    exit $exit if $exit >= 0;
}

__END__

=head1 NAME

text2usage - create a usage function from text documentation

=head1 SYNOPSIS

text2usage [options] [input file]

=head1 OPTIONS

=over 8

=item --name <function_name>

By default text2usage creates a function with the name C<usage>. This'll
change that.

=item --nopage

By default the usage routine will send the documentation to a pager.
This turns that off (why?).

=item --test

If present, generates a C<main()> function so the mess can be compiled
and you can see what the output will look like.

=item --pfx

The prefix to be used when creating the output files.  Required.

=item --csfx <suffix>

The suffix (period included) to be used when creating the output file
containing the code.  This defaults to C<.c>.

=item --f77w

Create a function callable from F77.  This interfaces with the GNU
B<autoconf> F77 wrappers, and requires there be a F<config.h> include
file which defines the C<F77_FUNC> macro.

=item --hsfx <suffix>

The suffix (period included) to be used for the output file containing
the header.  This defaults to C<.h>

=item --help

What you see here.

=item --version

Print the version and terminate.

=back

=head1 DESCRIPTION

B<text2usage> takes an input text file and creates code which will
spit it back out.  The characters are turned into their ASCII integer
representation to avoid funkiness with the compiler.  The code
will by default send the text to a pager (paying attention to the
environtmental variable C<PAGER>).  The C<--nopage> option changes this.

B<text2usage> will read the text on its standard input stream by
default if the filename is not given on the command line.

The code is written to C<${pfx}${csfx}>, the header file is
written to C<${pfx}{$hsfx}>.

The routine will have the name C<usage>; this may be changes with
the C<--name> option.

=head1 EXAMPLES

  text2usage --pfx=snack docs.txt

produces the files C<snack.c> and C<snack.h>

  text2usage --pfx=snack --csfx=.cc docs.txt

produces the files C<snack.cc> and C<snack.h>

=head1 VERSION

This documents version 1.1.2 of B<text2usage>.

=head1 COPYRIGHT AND LICENSE

This software is copyright the Smithsonian Astrophysical Observatory
and is released under the GNU General Public License.  You may find a
copy at L<http://www.fsf.org/copyleft/gpl.html>.


=head1 AUTHOR

Diab Jerius (djerius@cfa.harvard.edu)
