BIG, POSTSCRIPT, OVERSTRIKE, GIF: BINARY - ascii2ps
From Ric Hotchkiss <geh...@sdrc.com>
· alt.ascii-art
· 13 Jun 1994 16:33 · View full thread
· report
I started to post my PostScript collection of overstrike images a week or so
ago. I have received some mail indicating that this may not be a such good idea
(thay are quite large and all). So, I decided that maybe I should post the code
I wrote that converts the overstrike images into PostScript and a pointer to
the ftp site that I found the overstrike images at in the fist place.
I found the images at:
ftp.funet.fi:/pub/pics/lpr_art
the files are named p???.dat (some of which are not overstrike images).
If you want to print these images, you can do the following:
1. Ftp them from the above site.
2. To get some idea of what the image will look like, you can use the follwing
command on UNIX:
grep -v '^+' filename
This will display the file without the overstrike lines. Note that most of
these are 132 columns.
3. Compile the code after my .sig using the follwing command:
cc -o asc2ps asc2ps.c
(Let me know if this doesn't work). Put the resulting executable asc2ps in a
directory in your PATH (If you are not on UNIX, I'm not sure what to do
here).
4. Print the files to a PostScript printer by using the following:
asc2ps filename | lpr
OR
asc2ps filename > filename.ps
then print filename.ps
Remember, if your default printer is not a PostScript printer you will need
to use the -Pprinter flag of lpr.
At the top of the code is a man page.
P.S. If anyone wants to archive this at an ftp site, feel free, but please let
me know so that if I make upgrades/bug fixes, I can send you a new version.
--
|\ ___ _ _ _ _ _ _ _
(|_|_\________________ | _ (_)__| |_| |___| |_ __| |_ | |_(_)______
)|____________________| | / / _| _ / _ \ _/ _| ' \| ' / (_-<_-<
(| |___\ The Draftsman |_|_\_\__|_| |_\___/\__\__|_||_|_`_\_/__/__/
Of Course, my opinions do not reflect those of my employer, that's not my job!
-------8<-------8<-------8<-------8<-------8<-------8<-------8<-------8<-------
/*-----------------------------------------------------------------------------
asc2ps User Commands asc2ps
NAME
asc2ps - convert ascii art files to PostScript for printing
SYNOPSIS
asc2ps [-opt] [files]
ARGUMENTS
files - ascii art files to convert to PostScript
OPTIONS
-d|--down r Overstrike down shift in points (default: 0.2).
-f|--font s PostScript font name (default: Courier).
-g|--gap r Interline gap in points (default: 1).
-l|--length r Page length in inches (default: 11.
-m|--margin r Left margin width in points (default: 15).
-n|--nlines i Number of lines per page (default: 112).
-o|--ovchar c Character indicating an overstrike line (default: +).
-r|--right r Overstrike right shift in points (default: 0.2).
-s|--size r Size of font in points (default: 6.8).
-t|--top r Top margin width in points (default: 15).
-?|--help Print usage message.
DESCRIPTION
This command converts ascii art files into PostScript for printing. The
various options allow you to specify margins and fonts, etc.
There is a class of ascii art which is to be viewed only on a printer
because some characters are supposed be printed over others
(overstrike). This type of ascii art is handled specially. The down and
right options control how much the overstrike lines are offset from the
previous line (smearing) The format of these (at least the ones I've
seen) is such that any line beginning with a + character is supposed to
be printed on the same line as the previous line.
Note: defaults are set assuming the ascii art is wider than 80
characters (otherwise why not print the art directly). 132 column art
should print at about the width of the page using the defaults.
EXAMPLES
SEE ALSO
gifscii, ascgif, asc
BUGS
You tell me.
AUTHOR
Ric...@sdrc.com
history
written: 06/09/94
last revised: 06/12/94
_man_
-----------------------------------------------------------------------------*/
/* these are currently in /u/gehotch/src, should be in tools somewhere */
#include <stdarg.h>
/* Here I just insert my special local include files so compiling is easier
* (don't have to have any local .h files to complile) just type:
* cc -o asc2ps asc2ps.c
*/
/*-----------------------------------------------------------------------------
* #includes, #defines and function prototypes for general use
*/
#ifndef __STD_UTL_H
/*-----------------------------------------------------------------------------
* include files
*/
#ifndef __CTYPE_H__
#include <ctype.h>
#endif
#ifndef __STDIO_H__
#include <stdio.h>
#endif
#ifndef __STRING_H__
#include <string.h>
#endif
#ifndef __STDLIB_H__
#include <stdlib.h>
#endif
#ifndef __MATH_H__
#include <math.h>
#endif
/*-----------------------------------------------------------------------------
* simple #defines
*/
#define NULL 0
#define TRUE 1
#define FALSE 0
#define YES 1
#define NO 0
#define FILLEN 40 /* max characters in a file name */
#define MAXLEN 255 /* max characters in a string */
/*-----------------------------------------------------------------------------
* string functions
* UPCASE(s) - convert ea char of s to upper case
* LOCASE(s) - convert ea char of s to lower case
* CMDNAME(s) - set string s to command name stripped of path
*/
#define UPCASE(s) {int z; for(z=0;s[z]!='\0';toupper(s[n++]));}
#define LOCASE(s) {int z; for(z=0;s[z]!='\0';tolower(s[n++]));}
#define CMDNAME(s) strext(s, strrlo(argv[0], "/")+1, strlen(argv[0]), argv[0]);
/*-----------------------------------------------------------------------------
* bit functions
* SET_BITS - Sets bits in mask "a" specified by mask "b"
* CLR_BITS - Clears bits in mask "a" specified by mask "b"
* BITS_SET - "true" if ANY set bit in mask "b" is set in mask "a"
* BITS_CLR - "true" if ALL set bits in mask "b" are clear in mask "a"
*/
#define SET_BITS(a,b) ( (a) |= (b) )
#define CLR_BITS(a,b) ( (a) &= (~ (b)) )
#define BITS_SET(a,b) ( ( (a) & (b) ) != 0 )
#define BITS_CLR(a,b) ( ( (a) & (b) ) == 0 )
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* bit symbols
*/
#define BIT1 (1) /* 2**0 */
#define BIT2 (1<<1) /* 2**1 */
#define BIT3 (1<<2) /* 2**2 */
#define BIT4 (1<<3) /* 2**3 */
#define BIT5 (1<<4) /* 2**4 */
#define BIT6 (1<<5) /* 2**5 */
#define BIT7 (1<<6) /* 2**6 */
#define BIT8 (1<<7) /* 2**7 */
#define BIT9 (1<<8) /* 2**8 */
#define BIT10 (1<<9) /* 2**9 */
#define BIT11 (1<<10) /* 2**10 */
#define BIT12 (1<<11) /* 2**11 */
#define BIT13 (1<<12) /* 2**12 */
#define BIT14 (1<<13) /* 2**13 */
#define BIT15 (1<<14) /* 2**14 */
#define BIT16 (1<<15) /* 2**15 */
#define BIT17 (1<<16) /* 2**16 */
#define BIT18 (1<<17) /* 2**17 */
#define BIT19 (1<<18) /* 2**18 */
#define BIT20 (1<<19) /* 2**19 */
#define BIT21 (1<<20) /* 2**20 */
#define BIT22 (1<<21) /* 2**21 */
#define BIT23 (1<<22) /* 2**22 */
#define BIT24 (1<<23) /* 2**23 */
#define BIT25 (1<<24) /* 2**24 */
#define BIT26 (1<<25) /* 2**25 */
#define BIT27 (1<<26) /* 2**26 */
#define BIT28 (1<<27) /* 2**27 */
#define BIT29 (1<<28) /* 2**28 */
#define BIT30 (1<<29) /* 2**29 */
#define BIT31 (1<<30) /* 2**30 */
#define BIT32 (1<<31) /* 2**31 */
/*-----------------------------------------------------------------------------
* define this header
*/
#define __STD_UTL_H
#endif
#ifndef _GETOPTS_H
#define _GETOPTS_H
#include <stdio.h>
/*-----------------------------------------------------------------------------
* typedefs
*/
typedef enum /* bitmasks to determine if argument is reqd */
{
opt_NONE = 0, /* option takes no argument */
opt_OPT = 1, /* option takes an OPTIONAL argument */
opt_REQD = 2, /* option takes one REQUIRED argument */
opt_0MORE = 3, /* option takes 0 or more arguments */
opt_1MORE = 4 /* option takes 1 or more arguments */
} teOptArg;
typedef struct /* structure to define valid options */
{
const char cPrefix; /* the option prefix (must be + or -) */
const char cShort; /* short option character (e.g. c for -c) */
const char *pcLong; /* pointer to long option name string */
const teOptArg eArgReq; /* enum defining if argument follows option */
const char *pcOptArg; /* text of opt argument to appear in Usage */
const char *pcDescr; /* description of option to appear in Usage */
} tzOptDef;
typedef enum /* bitmasks used to control parsing behavior */
{
opt_DEFAULT = 0x00, /* Default setting */
opt_QUIET = 0x01, /* Dont print error messages */
opt_NUMERIC = 0x02, /* treat numeric options as integers */
opt_SHORT_ONLY = 0x04, /* Dont accept long-options */
opt_LONG_ONLY = 0x08, /* Dont accept short-options (also let "-" work
* as a long-option prefix).
*/
opt_NOGUESSING = 0x10, /* Normally, when we see a short (long) option
* on the command line that doesnt match any
* known short (long) options, then we try to
* "guess" by seeing if it will match any known
* long (short) option. Setting this mask
* prevents this "guessing" from occurring.
*/
opt_QUERY = 0x20 /* Dont set flags, just find what they are */
} teOptCtrl;
typedef struct /* structure to manage options definition */
{
unsigned uOptMsk : 8; /* control settings (set of teOptCtrl masks) */
int iOptNdx; /* current index in argv */
const tzOptDef *pzOptDef; /* structure of option-sepcifications */
const char *pcNxtChr; /* next option-character to process */
const tzOptDef *pzLstOpt; /* last list-option we matched */
const char *pcCmd; /* name of the command */
char cPrefix; /* option prefix + or - used for this option */
} tzOptStr;
#ifdef __cplusplus
extern "C" {
#endif
typedef enum /* error return values for getopts(3C) */
{
opt_ENDOPTS = 10000, /* end of options reached */
opt_BADCHAR = 10001, /* unknown short option found */
opt_BADKWD = 10002, /* unknow long option found */
opt_AMBIGUOUS = 10003, /* ambiguous long option found */
opt_NUMRET = 10004 /* a numeric option is returned in pcOptArg */
} teOptRet;
/*-----------------------------------------------------------------------------
* function prototypes
*/
extern tzOptStr *
optinit (const char *pcCmd,
const tzOptDef *pzOptDef);
extern int
getopts (tzOptStr *zOptStr,
int argc,
const char *argv[],
const char **ppcOptarg);
extern int
getoptndx(const tzOptStr *zOptStr);
extern void
optfree(tzOptStr *zOptStr);
/*
* Reset optind for another pass.
*/
extern void
optreset(tzOptStr *zOptStr);
/*
* Print "usage: progname" + "[-options]" on fp (dont print trailing newline)
*/
extern void
optusage(const tzOptStr *zOptStr,
const char *pcPositnls,
FILE *fpOut);
/*
* Return what the controls were, then set them to the given flags. See the
* definition of teOptCtrl for a list of the control masks and what they do.
*/
extern unsigned
optctrl(tzOptStr *zOpt,
unsigned uNewFlgs);
#ifdef __cplusplus
}
#endif
#endif /* _GETOPTS_H */
char *pcCmd; /* program name */
float rDown = 0.3; /* Overstrike down shift */
char *pcFontDef = {"Courier"}; /* default font */
char *pcFont; /* PostScript font name */
float rGap = 0.0; /* Interline gap in points */
float rLength = 11.0; /* Page length in inches */
float rMargin = 1; /* Left margin width in points */
int iNlines = 112; /* Number of lines per page */
char cOvchar = '+'; /* Character indicating overstrike */
float rRight = 0.3; /* Overstrike right shift in points */
float rSize = 6.8; /* Size of font in points */
float rTop = 1; /* top margin default */
static const tzOptDef azOptDef[] = /* options definition */
{
{ '-', 'd', "down", opt_REQD, "r",
"Overstrike down shift in points (default: 0.3)." },
{ '-', 'f', "font", opt_REQD, "s",
"PostScript font name (default: Courier)." },
{ '-', 'g', "gap", opt_REQD, "r",
"Interline gap in points (default: 0)." },
{ '-', 'l', "length", opt_REQD, "r",
"Page length in inches (default: 11." },
{ '-', 'm', "margin", opt_REQD, "r",
"Left margin width in points (default: 1)." },
{ '-', 'n', "nlines", opt_REQD, "i",
"Number of lines per page (default: 112)." },
{ '-', 'o', "ovchar", opt_REQD, "c",
"Character indicating an overstrike line (default: +)." },
{ '-', 'r', "right", opt_REQD, "r",
"Overstrike right shift in points (default: 0.3)." },
{ '-', 's', "size", opt_REQD, "r",
"Size of font in points (default: 6.8)." },
{ '-', 't', "top", opt_REQD, "r",
"Top margin width in points (default: 1)." },
{ '-', '?', "help", opt_NONE, "",
"Print usage message." },
{ NULL }
};
main(int argc, char *argv[])
{
char *pcOptArg; /* option argument pointer */
FILE *fpIn; /* input file pointer */
int i, c; /* counter */
tzOptStr *pzOpts = optinit(*argv, azOptDef); /* intialize the options */
pcCmd = strrchr(argv[0], '/'); /* generate command name */
pcCmd = (pcCmd == NULL) ? argv[0] : (pcCmd + 1); /* w/o pathname */
pcFont = pcFontDef;
--argc; ++argv;
while ((c = getopts(pzOpts, argc, argv, &pcOptArg)) != opt_ENDOPTS)
{
switch (c)
{
case 'd': rDown = atof (pcOptArg); break;
case 'f': pcFont = pcOptArg; break;
case 'g': rGap = atof (pcOptArg); break;
case 'l': rLength = atof (pcOptArg); break;
case 'm': rMargin = atof (pcOptArg); break;
case 'n': iNlines = atoi (pcOptArg); break;
case 'o': cOvchar= pcOptArg[0]; break;
case 'r': rRight = atof (pcOptArg); break;
case 's': rSize = atof (pcOptArg); break;
case 't': rTop = atof (pcOptArg); break;
default: /* print usage message, exit */
optusage(pzOpts, "", stdout);
exit (1);
break;
}
}
if (argc == getoptndx(pzOpts))
{
printAA (stdin);
}
else
{
for (i = getoptndx(pzOpts); i < argc; i++ )
{
/* open the input file to read */
if ((fpIn = fopen(argv[i], "r")) == NULL)
{
error ("cannot open image file: %s\n", argv[i]);
continue;
}
printAA (fpIn);
fclose (fpIn); /* close the tmp file */
}
}
optfree(pzOpts);
}
/*
*-----------------------------------------------------------------------------
* function error
* print error message
*-----------------------------------------------------------------------------
*/
void error (char *fmt, ...)
{
va_list args;
va_start (args, fmt);
fprintf (stderr, "%s ERROR: ", pcCmd);
vfprintf (stderr, fmt, args);
va_end (args);
}
/*-----------------------------------------------------------------------------
* print the ascii image into postcript code
*/
printAA (FILE *fpIn)
{
char c;
printPs (); /* print PostScript code */
putc ('(', stdout); /* print first open paren */
while ((c = getc (fpIn)) != EOF && (c < 177)) /* read file */
{
switch (c) /* special process some char */
{
case '(': /* parens must be quoted */
case ')': printf ("\\%c", c); break;
case '\n': printf (" )\n("); break; /* newline needs parens */
default: putc (c, stdout); /* just print char */
}
}
printf (" )\n] OverPrint\n%%%%end\n"); /* closing PostScript lines */
}
/*-----------------------------------------------------------------------------
* print postscript code
*/
printPs ()
{
printf ("%%!\n");
printf ("%%%% a postscript file crudely created by a script\n");
printf ("%%%% %s (9th June 1994, )\n", pcCmd);
printf ("%%%% `date`\n"); /*??? need to fix date*/
printf ("/LeftMargin %f def\n", rMargin);
printf ("/TopMargin %f def\n", rTop);
printf ("/PageHeight %f def\n", rLength);
printf ("/FontSize %f def\n", rSize);
printf ("/LineSpacing %f def\n", rGap);
printf ("/LinesPerPage %d def\n", iNlines);
printf ("/Font /%s def\n", pcFont);
printf ("/SmearRight %f def\n", rRight);
printf ("/SmearDown %f def\n", rDown);
printf ("Font findfont\n");
printf ("FontSize scalefont\n");
printf ("setfont\n");
printf ("/TopOfPage PageHeight 72 mul TopMargin sub def\n");
printf ("/LineHeight LineSpacing FontSize add def\n");
printf ("/Smear {\n");
printf (" exch\n");
printf (" 1 add\n");
printf (" exch\n");
printf ("} def\n");
printf ("/Fresh {\n");
printf (" exch pop\n");
printf (" exch dup LinesPerPage gt { showpage pop 0 } if\n");
printf (" 1 add exch 0 exch\n");
printf ("} def\n");
printf ("/Position {\n");
printf (" 3 -1 roll\n");
printf (" dup LeftMargin exch\n");
printf (" LineHeight mul TopOfPage sub neg moveto\n");
printf (" 3 -1 roll\n");
printf (" dup dup SmearRight mul exch\n");
printf (" SmearDown mul rmoveto\n");
printf (" 3 -1 roll\n");
printf ("} def\n");
printf ("%%%% strip the leading character from a string before printing it\n");
printf ("%%%% syntax : string stripshow\n");
printf ("/StripShow {\n");
printf (" dup 1 exch\n");
printf ("%% =>string 1 string\n");
printf (" length 1 sub\n");
printf ("%% =>string 1 strlen\n");
printf (" getinterval show\n");
printf ("} def\n");
printf ("%%%%takes an array of string and prints them\n");
printf ("%%%% syntax: array OverPrint\n");
printf ("/OverPrint {\n");
printf (" 0 0 3 -1 roll\n");
printf (" {\n");
printf ("%%get the first character\n");
printf (" dup 0 get\n");
printf (" %d eq { Smear } { Fresh } ifelse\n", cOvchar);
printf (" Position StripShow\n");
printf (" } forall\n");
printf (" showpage\n");
printf ("} def\n");
printf ("[\n");
}
/******************************************************************************
include this here to simplify compiling for non-technical types. All you need
to do is:
cc -o asc2ps asc2ps.c
assuming you have the .local .h files in the proper directory
*/
/*-----------------------------------------------------------------------------
getopt(3C) User Commands getopt(3C)
NAME
A suit of tools to parse/manage command-line options
optinit - initialize the options structure
optctrl - get/set the option parsing controls
getopts - parse the commandline options, returning them one by one
optusage - print usage message based on options definition
getoptndx - returns index of the first non-option in argv
optfree - free memory associated with the options structure
optreset - reset the options structure (to parse new argv)
SYNOPSIS
#include <getopts.h>
tzOptStr optinit(*argv, azOptDef);
void optfree(pzOpt)
int getopts(pzOpt, argc, argv, &pcOptarg);
int getoptndx(pzOpts);
void optusage(pzOpt, pcPositnls, fpOut)
unsigned optctrl(pzOpt, uNewFgs)
void optreset(pzOpt)
int argc;
tzOptDef azOptDef[]
char *argv[];
char *pcOptarg;
tzOptStr pzOpt;
FILE *fpOut;
unsigned uNewFlgs;
char *pcPositnls[] = { "non option arguments" };
DESCRIPTION
Get program options and present them to the calling function one at a
time. Supports + and - options as distinct (e.g. set -x and set +x in
ksh). Supports ++ and -- long options (e.g. --file ++count). Provides
an option to treat numeric options as integers or single character
options (e.g. pg +234 means start at line 234, comm -23 means supress
printing of column 2 and 3).
ARGUMENTS
"azOptDef[]" is an array of structures. of the following format:
azOptDef.cPrefix - The option prefix (must be '+' or '-') This
determines whether the option is to be preceded
by a '+' or '-' character (e.g. -c or +c).
azOptDef.cShort - The short option character. This is the option
- letter that the user will type in (e.g. 'c')
azOptDef.pcLong - Pointer to long option name string. This is the
long option name that is equivalent (e.g. --center
might be the long equivalent to -c).
azOptDef.eArgReq - define whether an argument follows the option
must be one of the enums teOptArg defined in
getopts.h. (see getopts.h)
opt_NONE - option takes no argument
opt_OPT - option takes an OPTIONAL argument
opt_REQD - option takes one REQUIRED argument
opt_0MORE - option takes 0 or more arguments
opt_1MORE - option takes 1 or more arguments
azOptDef.pzOptArg - word to appear as the option argument in the Usage
message. To make a hidden option (one that does not
get printed in the usage message) put the string:
"HIDDEN_OPTION" in this field, then optusage will
not print this option in the Usage message.
azOptDef.pcDescr - Description of option to appear in Usage message.
This is a string that will be printed after the
short and long option names that describes what
the option does. See example below
Exmaple:
static const tzOptDef azOptDef[] =
{
{ '-', '?', "help", opt_NONE, "", "print help message" },
{ '-', 'f', "flags", opt_OPT, "flgs", "modify option flags" },
{ '-', 'g', "group", opt_1MORE, "grps". "groups to include" },
{ '-', 'c', "count", opt_REQD, "#", "subtract \'#\' thingys" },
{ '+', 'c', "count", opt_REQD, "#", "add \'#\' of thingys" },
{ '-', 's', "string", opt_OPT, "strn", "use string \'strn\'" },
{ '-', 'x', "", opt_NONE, "", "\textract values" },
{ '-', '', "hello", opt_NONE, "", "\tprint hello message" },
{ NULL }
};
azOptDef now corresponds to the following usage message:
(See optusage function for positionals)
Usage: progname [-opt[arg]] [--] "positionals"
-?|--help print help message
-f|--flags [flgs] modify option flags
-g|--groups grps[...] groups to include
-c|--count # subract '#' of thingys
+c|++count # add '#' of thingys
-s|--string strn use string 'strn'
-x extract values
--hello print hello message
Long-option names are matched case-insensitive and only a unique prefix
of the name needs to be specified.
Single character option-name characters are case-sensitive!
CAVEAT
Because of the way in which multi-valued options and options with
optional values are handled, it is NOT possible to supply a value to an
option in a separate argument (different argv[] element) if the value
begins with a '-'. What this means is that if an option "-s" requires a
value and you wish to supply a value of "-foo" then you must specify
this on the command-line as "-s-foo" instead of "-s -foo" because
"-s -foo" will be considered to be two separate sets of options.
A multi-valued option is terminated by another option or by the end-of
options. The following are all equivalent (if "-l" is a multi-valued
option and "-x" is an option that takes no value):
progname -x -l item1 item2 item3 -- arg1 arg2 arg3
progname -x -litem1 -litem2 -litem3 -- arg1 arg2 arg3
progname -l item1 item2 item3 -x arg1 arg2 arg3
RETURNS
opt_ENDOPTS :
When all options have been parsed.
'c' :
If "-c" (or it's corresponding --long_option) was found.
-OR-
-(int) 'c' :
If "+c" (or it's corresponding ++long_option) was found.
Any argument for the option is in pcOptarg. If an argument is not
required or was not given, then pcOptarg will be NULL. If an argument
was required but not given, then an error message has been printed on
stderr (unless opt_QUIET is set).
opt_BADCHAR :
If an unknown option was found. An error message has been printed on
stderr (unless opt_QUIET is set). The offending option character is
denoted by *pcOptarg.
opt_BADKWD :
If an unknown long option was found. An error message has been printed
on stderr (unless opt_QUIET is set). The offending long-option name is
pointed to by pcOptarg.
opt_AMBIGUOUS :
If an ambiguous long option was found. An error message has been
printed on stderr (unless opt_QUIET is set). The ambiguous long-option
name is pointed to by pcOptarg.
opt_NUMERIC :
If opt_NUMERIC is set in the uOptMsk field of the tzOptStr and the
option found was numeric (e.g. -123). The actual numeric value of the
option is returned in pcOptarg, since you cannot supply an argument to
a numeric option.
EXAMPLE
#include <stdio.h>
#include <getopts.h>
static const tzOptDef azOptDef[] =
{
{ '-', '?', "help", opt_NONE, "\tprint help message" },
{ '-', 'f', "flags", opt_OPT, "flgs\tmodify option flags" },
{ '-', 'g', "group", opt_1MORE, "grps\tgroups to include" },
{ '-', 'c', "count", opt_REQD, "#\tsubtract \'#\' of thingys" },
{ '+', 'c', "count", opt_REQD, "#\tadd \'#\' of thingys" },
{ '-', 's', "string", opt_OPT, "strn\tuse string \'strn\'" },
{ '-', 'x', "", opt_NONE, "\textract values" },
{ '-', '', "hello", opt_NONE, "\tprint hello message" },
{ NULL }
};
main (int argc, char *argv[])
{
tzOptStr *zOpts = optinit(*argv, );
char *pcOptarg;
int i, c, iErr = 0;
int iCflg = 1, iXflg = 0, iHello = 0, iGroups = 0;
char *pcSflg = "default";
--argc, ++argv;
while ((c = getopts(zOpts, argc, argv, &pcOptarg)) != opt_ENDOPTS)
{
switch (c)
{
case 'c':
if (pcOptarg == NULL) ++iErr;
else iCflg = (int) atol (pcOptarg);
break;
case 's': pcSflg = pcOptarg; break;
case 'x': ++iXflg; break;
case ' ': ++iHello; break;
case 'g': ++iGroups; break; <---- group-name is in "pcOptarg"
default: ++iErr; break;
}
}
if (iErr)
{
optusage(zOptStr, "any positional arguments", stderr);
exit(1);
}
for (i = getoptndx(zOptStr); i < argc; i++ )
{
... do whatever with argv[i] ...
}
optfree(zOptStr);
}
AUTHOR
Brad Appleton <bra...@ssd.csd.harris.com>
history
written: 01/16/92
last revised: 08/12/93 Ric Hotchkiss <Ric...@sdrc.com>
_man_
-----------------------------------------------------------------------------*/
/*
* ^FILE: getopts.c - implement the functions defined in <getopts.h>
*
* ^HISTORY:
* 01/16/92 Brad Appleton <bra...@ssd.csd.harris.com>
* Created
*
* 08/10/93 Ric Hotchkiss <Ric...@sdrc.com>
* modified code so + is distinguished from - as option prefix (use +/-
* for short options ++/-- for long options. This prefix is stored in
* the options structure (zOptStr->cPrefix).
*
* expanded usage message printing to print more information.
*
* changed options specifier from array of pointers to strings to an array
* of structures, to simplify parsing and definition.
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#define TRUE 1
#define FALSE 0
/* return values for a keyword matching function */
typedef enum { NO_MATCH, PARTIAL_MATCH, EXACT_MATCH } teKwdMtch;
/* Get the option-char of an option-spec. */
#define OPTCHAR(op) (op->cShort)
/* Get the long-option of an option-spec. */
#define LONGOPT(op) (op->pcLong)
/* Is the option-char null? */
#define isNULLOPT(oc) ((! oc) || isspace(oc) || (! isprint(oc)))
/* Does this option require an argument? */
#define isREQUIRED(op) ((op->eArgReq == opt_REQD)||(op->eArgReq == opt_1MORE))
/* Does this option take an optional argument? */
#define isOPTIONAL(op) ((op->eArgReq == opt_OPT) || (op->eArgReq == opt_0MORE))
/* Does this option take no arguments? */
#define isNOARG(op) (op->eArgReq == opt_NONE)
/* Can this option take more than one argument? */
#define isLIST(op) ((op->eArgReq == opt_0MORE) || (op->eArgReq == opt_1MORE))
/* Does this option take any arguments? */
#define isVALTAKEN(op) (isREQUIRED(op) || isOPTIONAL(op))
/* Check for explicit "end-of-options" */
#define isENDOPTS(t) ((! t) || (! strcmp(t, "--")))
/* See if an argument is an option */
#define isOPTION(a) ((a[1] != '\0') && ((*a == '-') || (*a == '+')))
/* These next three macros help manage the `iOptNdx' field of an tzOptStr
* structure as the current element of an iterator for an argc/argv pair.
*
* isENDARGS() determines if we are at the end-of-arguments
* CURR() returns the current item (without advancing the iterator)
* NEXT() advances to the next item in the iterator.
*/
#define isENDARGS(op,ac,av) ((op->iOptNdx == ac) || (! av[op->iOptNdx]))
#define CURR(op,ac,av) isENDARGS(op,ac,av) ? NULL : av[op->iOptNdx]
#define NEXT(op,ac,av) if (! isENDARGS(op,ac,av)) ++(op->iOptNdx)
/*
* ^FUNCTION: optdef_ver - verify syntax of each element of the option vector
*
* ^SYNOPSIS:
* static void optdef_ver(const tzOptDef *pzOptDef)
*
* ^PARAMETERS:
* const tzOptDef *pzOptDef - the vector of option-specs to inspect.
*
* ^DESCRIPTION:
* All we have to do is iterate through the option structure and make sure
* That each option-spec is of the proper format.
*
* ^REQUIREMENTS:
* const tzOptDef *pzOptDef should be non-NULL and terminated by a NULL
* pointer.
*
* ^SIDE-EFFECTS:
* If an invalid option-spec is found, prints a message on stderr and
* exits with a status of 127.
*
* ^RETURN-VALUE:
* None.
*
* ^ALGORITHM:
* For each option-spec
* - verify that the prifix is one of '+' or '-'
* - verify that the eArgReq field is in the range of the enum
* end-for
*/
static void
optdef_ver (const tzOptDef *pzOptDef)
{
int iErrs = 0;
if ((pzOptDef == NULL) || (pzOptDef->cShort == NULL)) return;
for (; pzOptDef->cShort != NULL; pzOptDef++)
{
if (pzOptDef->cPrefix != '-' && pzOptDef->cPrefix != '+')
{
fprintf(stderr, "getopts(3):\tinvalid prefix spec \"%c\".\n",
pzOptDef->cPrefix);
fprintf(stderr, "\t\tPrefix must be \'+\' or \'-\'\n");
++iErrs;
}
if ((pzOptDef->eArgReq < opt_NONE) &&
(pzOptDef->eArgReq > opt_1MORE))
{
fprintf(stderr, "getopts(3):\tinvalid option argument spec \"%d\".\n",
pzOptDef->eArgReq);
fprintf(stderr,
"\t\teArgReq must be between %d and %d (see getopts.h)\n",
opt_NONE, opt_1MORE);
++iErrs;
}
} /*for*/
if (iErrs) exit(127);
}
/*
* ^FUNCTION: kwd_match - match a keyword
*
* ^SYNOPSIS:
* static teKwdMtch kwd_match(pcKeyWd, pcMatch, iLen)
*
* ^PARAMETERS:
* char *pcKeyWd -- the actual keyword to match
* char *pcMatch -- the possible keyword to compare against "pcKeyWd"
* int iLen -- number of character of "pcMatch" to consider
* (if negative then we should use all of "pcMatch")
*
* ^DESCRIPTION:
* See if "pcMatch" matches some prefix of "pcKeyWd" (case insensitive).
*
* ^REQUIREMENTS:
* - tolower() should NOT modify a non-uppercase character.
*
* ^SIDE-EFFECTS:
* None.
*
* ^RETURN-VALUE:
* An enumeration value of type teKwdMtch corresponding to whether
* We had an exact match, a partial match, or no match.
*
* ^ALGORITHM:
* Trivial
*/
static teKwdMtch
kwd_match(const char *pcKeyWd,
const char *pcMatch,
int iLen)
{
unsigned i;
if (pcKeyWd == pcMatch) return (EXACT_MATCH);
if ((! pcKeyWd) || (! pcMatch)) return (NO_MATCH);
if ((! *pcKeyWd) && (! *pcMatch)) return (EXACT_MATCH);
if ((! *pcKeyWd) || (! *pcMatch)) return (NO_MATCH);
for (i = 0; ((i < iLen) || (iLen < 0)) && (pcMatch[i]); i++)
{
if (tolower(pcKeyWd[i]) != tolower(pcMatch[i])) return (NO_MATCH);
}
return ((pcKeyWd[i]) ? PARTIAL_MATCH : EXACT_MATCH);
}
/*
* ^FUNCTION: match_opt - match an option
*
* ^SYNOPSIS:
* static const tzOptDef *match_opt(pzOptDef, cOptChr)
*
* ^PARAMETERS:
* const tzOptDef *pzOptDef -- structure of option-specifications
* char cOptChr -- the option-character to match
*
* ^DESCRIPTION:
* See if "cOptChr" is found in "azOptDef"
*
* ^REQUIREMENTS:
* - azOptDef should be non-NULL and terminated by a NULL pointer.
* - tolower() should NOT modify a non-uppercase character.
*
* ^SIDE-EFFECTS:
* None.
*
* ^RETURN-VALUE:
* NULL if no match is found,
* otherwise a pointer to the matching option-spec.
*
* ^ALGORITHM:
* foreach option-spec
* - see if "cOptChr" is a match, if so return option-spec
* end-for
*/
static const tzOptDef *
match_opt(const tzOptDef *pzOptDef,
char cOptChr)
{
char cOpc;
if ((! pzOptDef) || (! pzOptDef->cShort)) return (NULL);
for (; pzOptDef->cShort; ++pzOptDef)
{
cOpc = OPTCHAR(pzOptDef);
if (isNULLOPT(cOpc)) continue;
if (cOptChr == cOpc)
{
return (pzOptDef);
}
}
return (NULL); /* not found */
}
/*
* ^FUNCTION: match_longopt - match a long-option
*
* ^SYNOPSIS:
* static const tzOptDef *match_longopt(pzOptDef, pcOptStr, iLen, piAmbig)
*
* ^PARAMETERS:
* char *pzOptDef[] -- the vector of option-specs
* char *pcLongOp -- the long-option to match
* int iLen -- the number of character of "pcLongOp" to match
* int *piAmbig -- set by this routine before returning.
*
* ^DESCRIPTION:
* Try to match "pcLongOp" against some unique prefix of a long-option
* (case insensitive).
*
* ^REQUIREMENTS:
* - opts->pzOptDef should be non-NULL and terminated by a NULL pointer.
*
* ^SIDE-EFFECTS:
* - *piAmbig is set to '1' if "pcLongOp" matches >1 long-option
* (otherwise it is set to 0).
*
* ^RETURN-VALUE:
* NULL if no match is found,
* otherwise a pointer to the matching option-spec.
*
* ^ALGORITHM:
* piAmbig is FALSE
* foreach option-spec
* if we have an EXACT-MATCH, return the option-spec
* if we have a partial-match then
* if we already had a previous partial match then
* set piAmbig = TRUE and retrun NULL
* else
* remember this options spec and continue matching
* end-if
* end-if
* end-for
* if we had exactly 1 partial match return it, else return NULL
*/
static const tzOptDef *
match_longopt(const tzOptDef *pzOptDef,
const char *pcOpt,
int iLen,
int *piAmbig)
{
teKwdMtch eReslt;
const tzOptDef *pzMatch = NULL;
*piAmbig = 0;
if ((! pzOptDef) || (! pzOptDef->cShort)) return (NULL);
for (; pzOptDef->cShort; ++pzOptDef)
{
const char *pcLongOp = LONGOPT(pzOptDef);
if (! pcLongOp) continue;
eReslt = kwd_match(pcLongOp, pcOpt, iLen);
if (eReslt == EXACT_MATCH)
{
return (pzOptDef);
}
else if (eReslt == PARTIAL_MATCH)
{
if (pzMatch)
{
++(*piAmbig);
return (NULL);
}
else
{
pzMatch = pzOptDef;
}
}
}/*for*/
return (pzMatch);
}
/*
* ^FUNCTION: parse_opt - parse an option
*
* ^SYNOPSIS:
* int parse_opt(pzOpt, iArgc, apcArgv, ppcOptArg)
*
* ^PARAMETERS:
* tzOptStr *pzOpt -- the options structure
* int iArgc -- argc from main
* const char *apcArgv[] -- argv[] from main
* const char **ppcOptArg -- where to store any option-argument
*
* ^DESCRIPTION:
* Parse the next option in apcArgv (advancing iOptNdx as necessary).
* Make sure we update the pzOpt->pcNxtChr pointer along the way. Any option
* we find should be returned and ppcOptArg should point to its argument.
*
* ^REQUIREMENTS:
* - pzOpt->pcNxtChr must point to the prospective option character
*
* ^SIDE-EFFECTS:
* - pzOpt->iOptNdx is advanced when an argument completely parsed
* - ppcOptArg is modified to point to any option argument
* - if opt_QUIET is not set, error messages are printed on stderr
*
* ^RETURN-VALUE:
* 'c' if the -c option was matched (ppcOptArg points to its argument)
* -1 if the option is invalid (ppcOptArg points to the bad option-char).
*
* ^ALGORITHM:
* It gets complicated -- follow the comments in the source.
*/
int
parse_opt(tzOptStr *pzOpt,
int iArgc,
const char *apcArgv[],
const char **ppcOptArg)
{
const char *pcNxtArg = NULL;
const tzOptDef *pzOptSpc = NULL;
pzOpt->pzLstOpt = NULL; /* reset the list pointer */
if ((! pzOpt->pzOptDef) || (! pzOpt->pzOptDef->cShort)) return (opt_ENDOPTS);
/* Try to match a known option */
pzOptSpc = match_opt(pzOpt->pzOptDef, *(pzOpt->pcNxtChr++));
/* Check for an unknown option */
if (! pzOptSpc)
{
/* See if this was a long-option in disguise */
if (! (pzOpt->uOptMsk & opt_NOGUESSING))
{
int cOpc;
unsigned uSavCtrl = pzOpt->uOptMsk;
const char *pcSavNxt = pzOpt->pcNxtChr;
pzOpt->pcNxtChr -= 1;
pzOpt->uOptMsk |= (opt_QUIET | opt_NOGUESSING);
cOpc = parse_longopt(pzOpt, iArgc, apcArgv, ppcOptArg);
pzOpt->uOptMsk = uSavCtrl;
if (cOpc > 0)
{
return (cOpc);
}
else
{
pzOpt->pcNxtChr = pcSavNxt;
}
}
if (! (pzOpt->uOptMsk & opt_QUIET))
{
fprintf(stderr, "%s: unknown option %c%c.\n",
pzOpt->pcCmd, pzOpt->cPrefix, *(pzOpt->pcNxtChr - 1));
}
*ppcOptArg = (pzOpt->pcNxtChr - 1); /* record bad option in ppcOptArg */
return (opt_BADCHAR);
}
/* If no argument is taken, then leave now */
if (isNOARG(pzOptSpc))
{
ppcOptArg = NULL;
return (pzOptSpc->cShort);
}
/* Check for argument in this arg */
if (*(pzOpt->pcNxtChr))
{
*ppcOptArg = pzOpt->pcNxtChr; /* the argument is right here */
pzOpt->pcNxtChr = NULL; /* we've exhausted this argument */
if (isLIST(pzOptSpc)) pzOpt->pzLstOpt = pzOptSpc; /* save list-spec */
return (pzOptSpc->cShort);
}
/* Check for argument in next arg */
pcNxtArg = CURR(pzOpt, iArgc, apcArgv);
if ((pcNxtArg != NULL) && (! isOPTION(pcNxtArg)))
{
*ppcOptArg = pcNxtArg; /* the argument is here */
NEXT(pzOpt, iArgc, apcArgv); /* end of arg - advance */
if (isLIST(pzOptSpc)) pzOpt->pzLstOpt = pzOptSpc; /* save list-spec */
return (pzOptSpc->cShort);
}
/* No argument given - if its required, thats an error */
*ppcOptArg = NULL;
if (isREQUIRED(pzOptSpc) && !(pzOpt->uOptMsk & opt_QUIET))
{
fprintf(stderr, "%s: argument required for %c%c option.\n",
pzOpt->pcCmd, pzOpt->cPrefix, pzOptSpc->cShort);
}
return (pzOptSpc->cShort);
}
/*
* ^FUNCTION: parse_longopt - parse a long-option
*
* ^SYNOPSIS:
* int parse_longopt(pzOpt, iArgc, apcArgv, ppcOptArg)
*
* ^PARAMETERS:
* tzOptStr *pzOpt -- the options structure
* int iArgc -- argc from main
* const char *apcArgv[] -- argv[] from main
* const char **ppcOptArg -- where to store any option-argument
*
* ^DESCRIPTION:
* Parse the next long-option in apcArgv (advancing iOptNdx as necessary).
* Make sure we update the pzOpt->pcNxtChr pointer along the way. Any option
* we find should be returned and ppcOptArg should point to its argument.
*
* ^REQUIREMENTS:
* - pzOpt->pcNxtChr must point to the prospective option character
*
* ^SIDE-EFFECTS:
* - iOptNdx is advanced when an argument completely parsed
* - ppcOptArg is modified to point to any option argument
* - if opt_QUIET is not set, error messages are printed on stderr
*
* ^RETURN-VALUE:
* 'c' if the the long-option corresponding to the -c option was matched
* (ppcOptArg points to its argument)
* -2 if the option is invalid (ppcOptArg points to bad long-option name).
*
* ^ALGORITHM:
* It gets complicated -- follow the comments in the source.
*/
int
parse_longopt(tzOptStr *pzOpt,
int iArgc,
const char *apcArgv[],
const char **ppcOptArg)
{
int iLen = -1;
int iAmbig = 0;
const tzOptDef *pzOptSpc = NULL;
const char *pcVal = NULL;
const char *pcNxtArg = NULL;
char acPrefix[3];
pzOpt->pzLstOpt = NULL; /* reset the list-spec */
if ((! pzOpt->pzOptDef) || (! pzOpt->pzOptDef->cShort)) return (opt_ENDOPTS);
/* if a value is supplied in this apcArgv element, get it now */
pcVal = strpbrk(pzOpt->pcNxtChr, ":=");
if (pcVal)
{
iLen = pcVal - pzOpt->pcNxtChr;
++pcVal;
}
/* Try to match a known long-option */
pzOptSpc = match_longopt(pzOpt->pzOptDef, pzOpt->pcNxtChr, iLen, &iAmbig);
/* Check for an unknown long-option */
if (! pzOptSpc)
{
/* See if this was a short-option in disguise */
if ((! iAmbig) && (! (pzOpt->uOptMsk & opt_NOGUESSING)))
{
int cOpc;
unsigned uSavCtrl = pzOpt->uOptMsk;
const char *pcSavNxt = pzOpt->pcNxtChr;
pzOpt->uOptMsk |= (opt_QUIET | opt_NOGUESSING);
cOpc = parse_opt(pzOpt, iArgc, apcArgv, ppcOptArg);
pzOpt->uOptMsk = uSavCtrl;
if (cOpc > 0)
{
return (cOpc);
}
else
{
pzOpt->pcNxtChr = pcSavNxt;
}
}
if (! (pzOpt->uOptMsk & opt_QUIET))
{
acPrefix[0] = pzOpt->cPrefix;
acPrefix[1] = (pzOpt->uOptMsk & opt_LONG_ONLY) ? '\0' : pzOpt->cPrefix;
acPrefix[2] = '\0';
fprintf(stderr, "%s: %s option %s%s.\n", pzOpt->pcCmd,
((iAmbig) ? "ambiguous" : "unknown"), acPrefix, pzOpt->pcNxtChr);
}
*ppcOptArg = pzOpt->pcNxtChr; /* record bad option in ppcOptArg */
pzOpt->pcNxtChr = NULL; /* we've exhausted this argument */
return ((iAmbig) ? opt_AMBIGUOUS : opt_BADKWD);
}
/* If no argument is taken, then leave now */
if (isNOARG(pzOptSpc))
{
if ((pcVal) && ! (pzOpt->uOptMsk & opt_QUIET))
{
acPrefix[0] = pzOpt->cPrefix;
acPrefix[1] = (pzOpt->uOptMsk & opt_LONG_ONLY) ? '\0' : pzOpt->cPrefix;
acPrefix[2] = '\0';
fprintf(stderr, "%s: option %s%s does NOT take an argument.\n",
pzOpt->pcCmd, acPrefix, pzOptSpc->cShort);
}
*ppcOptArg = pcVal; /* record the unexpected argument */
pzOpt->pcNxtChr = NULL; /* we've exhausted this argument */
return (pzOptSpc->cShort);
}
/* Check for argument in this arg */
if (pcVal)
{
*ppcOptArg = pcVal; /* the argument is right here */
pzOpt->pcNxtChr = NULL; /* we exhausted the rest of this arg */
if (isLIST(pzOptSpc)) pzOpt->pzLstOpt = pzOptSpc; /* save list-spec */
return (pzOptSpc->cShort);
}
/* Check for argument in next arg */
pcNxtArg = CURR(pzOpt, iArgc, apcArgv); /* find next argument to parse */
if ((pcNxtArg != NULL) && (! isOPTION(pcNxtArg)))
{
*ppcOptArg = pcNxtArg; /* the argument is right here */
NEXT(pzOpt, iArgc, apcArgv); /* end of arg advance iOptNdx */
pzOpt->pcNxtChr = NULL; /* we exhausted the rest of this arg */
if (isLIST(pzOptSpc)) pzOpt->pzLstOpt = pzOptSpc; /* save list-spec */
return (pzOptSpc->cShort);
}
/* No argument given - if its required, thats an error */
ppcOptArg = NULL;
if (isREQUIRED(pzOptSpc) && !(pzOpt->uOptMsk & opt_QUIET))
{
acPrefix[0] = pzOpt->cPrefix;
acPrefix[1] = (pzOpt->uOptMsk & opt_LONG_ONLY) ? '\0' : pzOpt->cPrefix;
acPrefix[2] = '\0';
fprintf(stderr, "%s: argument required for %s%s option.\n",
pzOpt->pcCmd, acPrefix, pzOptSpc->pcLong);
}
pzOpt->pcNxtChr = NULL; /* we exhausted the rest of this arg */
return (pzOptSpc->cShort);
}
/*
* ^FUNCTION: optusage - print usage
*
* ^SYNOPSIS:
* void optusage(pzOpt, pcPositnls, fpOut)
*
* ^PARAMETERS:
* const tzOptStr *pzOpt -- the options structure
* char *pcPositnls -- command-line syntax for any positional args
* FILE *fpOut -- where to print the usage
*
* ^DESCRIPTION:
* Print command-usage (using either option or long-option syntax) on fpOut.
*
* ^REQUIREMENTS:
* fpOut should correspond to an open output file.
*
* ^SIDE-EFFECTS:
* Prints on fpOut
*
* ^RETURN-VALUE:
* None.
*
* ^ALGORITHM:
* Print usage on fpOut, wrapping long lines where necessary.
*/
void
optusage(const tzOptStr *pzOpt,
const char *pcPositnls,
FILE *fpOut)
{
tzOptDef *p = pzOpt->pzOptDef;
tzOptDef *pzSave = pzOpt->pzOptDef;
int i, j;
unsigned uTmp, uCols = 78, uPrtArg = FALSE;
unsigned uMarg1, uMarg2, uLong = 0, uOptArg = 0, uAdd = 0;
char acBuf[256], acWord[80];
/* if there are no options
* just print: "usage: progname positionals"
* then return
*/
if ((! p) || (! p->cShort))
{
fprintf(fpOut, "usage: %s %s", pzOpt->pcCmd, pcPositnls);
return;
}
/* set initial margin setting based on teOptCtrl flags
* step through p (pzOptDef structure) to determine margin settings of output
*/
if ((pzOpt->uOptMsk & opt_SHORT_ONLY)) uMarg1 = 11;
else if ((pzOpt->uOptMsk & opt_LONG_ONLY)) uMarg1 = 12;
else uMarg1 = 14;
for (; p->cShort != NULL; p++)
{
if (strcmp ("HIDDED_OPTION", p->pcOptArg) == 0) continue;
uTmp = strlen (p->pcLong);
uLong = (uLong < uTmp) ? uTmp : uLong;
uTmp = strlen (p->pcOptArg);
uOptArg = (uOptArg < uTmp) ? uTmp : uOptArg;
switch (p->eArgReq)
{
case opt_NONE: break;
case opt_OPT: uAdd = (uAdd < 2) ? 2: uAdd; break;
case opt_REQD: uPrtArg = TRUE; break;
case opt_0MORE: uAdd = (uAdd < 6) ? 6: uAdd; uPrtArg = TRUE; break;
case opt_1MORE: uAdd = (uAdd < 6) ? 6: uAdd; uPrtArg = TRUE; break;
}
}
uMarg1 += uLong + 1;
uMarg2 = uMarg1 + uOptArg + uAdd;
/* now print start of the message: "Usage: prognam [-opt[arg]] positionals"
*/
fprintf(fpOut, "usage: %s [-opt", pzOpt->pcCmd);
if (uPrtArg) fprintf(fpOut, "[arg]");
fprintf(fpOut, "] %s\n", pcPositnls);
/* step through p (pzOptDef structure), build and print line for each option
* - add 8 spaces for tab @ beginning of line
* - if short opt allowed: add prefix & short opt or spaces if non-printing
* - if short and long opt allowed: add '|' char to separate short|long
* - if long options are allowed: add prefix twice and long option
* - while line shorter than uMarg1 (margin up to opt arguments) add spaces
* - add argument and possible brackets (e.g. [...]) or spaces if no argument
* - while line shorter than uMarg2 (margin up to description) add spaces
* - add the description (spliting into lines and adding margin etc).
* - finally print the line
*/
p = pzSave;
for (; p->cShort != NULL; p++)
{
if (strcmp ("HIDDED_OPTION", p->pcOptArg) == 0) continue;
sprintf(acBuf, " ");
if (! (pzOpt->uOptMsk & opt_LONG_ONLY)) /* short option */
{
if (isgraph (p->cShort)) /* prefix & option */
sprintf(acBuf, "%s%c%c", acBuf, p->cPrefix, p->cShort);
else /* just spaces */
sprintf(acBuf, "%s ", acBuf, p->cPrefix, p->cShort);
}
if (! (pzOpt->uOptMsk & (opt_LONG_ONLY | opt_SHORT_ONLY)))
{ /* option separator "|" */
if (isgraph (p->cShort)) /* separator "|" */
sprintf(acBuf, "%s|", acBuf);
else /* just space */
sprintf(acBuf, "%s ", acBuf);
}
if (! (pzOpt->uOptMsk & opt_SHORT_ONLY)) /* long option */
sprintf(acBuf, "%s%c%c%s", acBuf, p->cPrefix, p->cPrefix,
p->pcLong);
while (strlen (acBuf) < uMarg1) /* spaces up to 1st margin */
sprintf(acBuf, "%s ", acBuf);
switch (p->eArgReq) /* option arguments */
{
case opt_NONE: break;
case opt_OPT:
sprintf(acBuf, "%s[%s]", acBuf, p->pcOptArg);
break;
case opt_REQD:
sprintf(acBuf, "%s%s", acBuf, p->pcOptArg);
break;
case opt_0MORE:
if (strchr (p->pcOptArg, ' '))
sprintf(acBuf, "%s[%s]", acBuf, p->pcOptArg);
else
sprintf(acBuf, "%s[%s ...]", acBuf, p->pcOptArg);
break;
case opt_1MORE:
if (strchr (p->pcOptArg, ' '))
sprintf(acBuf, "%s%s", acBuf, p->pcOptArg);
else
sprintf(acBuf, "%s%s [...]", acBuf, p->pcOptArg);
break;
}
while (strlen (acBuf) < uMarg2) /* spaces up to 2nd margin */
sprintf(acBuf, "%s ", acBuf);
for (j = 0; j < strlen(p->pcDescr); j++) /* description */
{
for (; (! isspace(p->pcDescr[j])) && /* while in a word */
j < strlen(p->pcDescr); j++)
{ /* add to pcWord buffer */
sprintf(acWord, "%s%c", acWord, p->pcDescr[j]);
if ((strlen(acBuf) + strlen(acWord)) > uCols)
{ /* if description too long */
sprintf(acBuf, "%s\n\0", acBuf); /* add newline */
fputs (acBuf, fpOut); /* print the buffer */
acBuf[0] = '\0'; /* reset buffer */
while (strlen(acBuf) < uMarg2) /* add spaces to 2nd margin */
sprintf(acBuf, "%s ", acBuf);
}
}
sprintf(acBuf, "%s %s", acBuf, acWord); /* add pcWord to acBuf */
acWord[0] = '\0'; /* reset word */
}
fputs (acBuf, fpOut);
fputc('\n', fpOut);
}
fflush(fpOut);
}
/*
* ^FUNCTION: getopts - get options from the command-line
*
* ^SYNOPSIS:
* int getopts(pzOpt, iArgc, apcArgv, ppcOptArg)
*
* ^PARAMETERS:
* tzOptStr *pzOpt -- the options structure
* int iArgc -- argc from main
* const char *apcArgv[] -- argv[] from main
* const char **ppcOptArg -- where to store any option-argument
*
* ^DESCRIPTION:
* Parse the next option in apcArgv (advancing iOptNdx as necessary).
* Make sure we update the pzOpt->pcNxtChr pointer along the way. Any option
* we find should be returned and ppcOptArg should point to its argument.
*
* ^REQUIREMENTS:
* pzOpt should have been created by optinit().
*
* ^SIDE-EFFECTS:
* - iOptNdx is advanced when an argument is completely parsed
* - ppcOptArg is modified to point to any option argument
* - if opt_QUIET is not set, error messages are printed on stderr
*
* ^RETURN-VALUE:
* 0 if all options have been parsed.
* 'c' if the the option or long-option corresponding to the -c option was
* matched (ppcOptArg points to its argument).
* -1 if the option is invalid (ppcOptArg points to bad option character).
* -2 if the option is invalid (ppcOptArg points to bad long-option name).
*
* ^ALGORITHM:
* It gets complicated -- follow the comments in the source.
*/
int
getopts(tzOptStr *pzOpt,
int iArgc,
const char *apcArgv[],
const char **ppcOptArg)
{
const char *pcArg;
int c;
/* See if we have an option left over from before ... */
if ((pzOpt->pcNxtChr) && *(pzOpt->pcNxtChr))
{
c = parse_opt(pzOpt, iArgc, apcArgv, ppcOptArg);
return ((pzOpt->cPrefix == '-') ? c : -c);
}
/* Check for end-of-options ... */
pcArg = CURR(pzOpt, iArgc, apcArgv);
if (! pcArg)
{
pzOpt->pzLstOpt = NULL;
return (opt_ENDOPTS);
}
else if (isENDOPTS(pcArg))
{
NEXT(pzOpt, iArgc, apcArgv); /* advance past end-of-options arg */
pzOpt->pzLstOpt = NULL;
return (opt_ENDOPTS);
}
/* Do we have a positional arg? */
if (! pzOpt->pzLstOpt)
{
if ((! *pcArg) || (! pcArg[1]))
{
return (opt_ENDOPTS);
}
else if ((*pcArg != '-') && (*pcArg != '+'))
{
return (opt_ENDOPTS);
}
}
/* pass the argument that pzOpt->pcNxtArg already points to */
NEXT(pzOpt, iArgc, apcArgv);
pzOpt->cPrefix = *pcArg; /* store the prifix char */
if (! (pzOpt->uOptMsk & opt_SHORT_ONLY)) /* check for long option */
{
if (((*pcArg == '-') && (pcArg[1] == '-')) ||
((*pcArg == '+') && (pcArg[1] == '+')))
{
pzOpt->pcNxtChr = pcArg + 2;
c = parse_longopt(pzOpt, iArgc, apcArgv, ppcOptArg);
return ((pzOpt->cPrefix == '-') ? c : -c);
}
}
if ((*pcArg == '-') || (*pcArg == '+')) /* check for short option */
{
pzOpt->pcNxtChr = pcArg + 1;
if (pzOpt->uOptMsk & opt_LONG_ONLY)
{
c = parse_longopt(pzOpt, iArgc, apcArgv, ppcOptArg);
return ((pzOpt->cPrefix == '-') ? c : -c);
}
else
{
c = parse_opt(pzOpt, iArgc, apcArgv, ppcOptArg);
return ((pzOpt->cPrefix == '-') ? c : -c);
}
}
/* If we get here - it is because we have a list value */
*ppcOptArg = pcArg; /* record the list value */
c = pzOpt->pzLstOpt->cShort;
return ((pzOpt->cPrefix == '-') ? c : -c);
}
/*
* ^FUNCTION: optctrl - get/set parse-controls
*
* ^SYNOPSIS:
* extern unsigned optctrl(pzOpt, uNewFlgs)
*
* ^PARAMETERS:
* tzOptStr *pzOpt -- the options structure
* unsigned uNewFlgs -- combination of bitmasks defined by teOptCtrl
*
* ^DESCRIPTION:
* If uNewFlgs contains opt_QUERY, then just get the current flags.
* Otherwise, set "opt_ctrls" to the given flags and retrun what they were.
*
* ^REQUIREMENTS:
* None.
*
* ^SIDE-EFFECTS:
* Modifies pzOpt->uOptMsk
*
* ^RETURN-VALUE:
* The current opt-ctrls for "pzOpt" at the time of the call.
*
* ^ALGORITHM:
* set the new-flags (if !opt_QUERY), return the old-ones.
*/
extern unsigned
optctrl(tzOptStr *pzOpt,
unsigned uNewFlgs)
{
unsigned uOldCtrl = pzOpt->uOptMsk; /* save old flags */
/* Set new flags if not a QUERY ... */
if (! (uNewFlgs & opt_QUERY))
{
pzOpt->uOptMsk = uNewFlgs;
}
return (uOldCtrl); /* return old flags */
}
/*
* ^FUNCTION: getoptndx - get option index.
*
* ^SYNOPSIS:
* int getoptndx(pzOpt);
*
* ^PARAMETERS:
* const tzOptStr *pzOpt; -- options structure
*
* ^DESCRIPTION:
* After getopts() has indicated that the end-of-options has been
* encountered, the programmer may wish to know the index (in argv)
* of the first no-option element in the array. This function provides
* precisely this service.
*
* ^REQUIREMENTS:
* Getopts() should already have returne '0' (meaning end-of-options)
* for the corresponing argc/argv pair.
*
* ^SIDE-EFFECTS:
* None.
*
* ^RETURN-VALUE:
* Index of the first non-option element in the argv vector that was
* repeatedly passed to getopts.
*
* ^ALGORITHM:
* Trivial.
*/
int
getoptndx(const tzOptStr *pzOpt)
{ return (pzOpt->iOptNdx); }
/*
* ^FUNCTION: optreset - reset for parsing more options.
*
* ^SYNOPSIS:
* optreset(pzOpt);
*
* ^PARAMETERS:
* tzOptStr *pzOpt; -- the options structure
*
* ^DESCRIPTION:
* After having parsed all the options in an argv[] array, the programmer
* may wish to make a second pass over argv to reparse the options (or
* perhaps the programmer wasnt to prse yet-another argv vector).
* This function performs the necessary re-initialization for such
* "re-parsing" of program options.
*
* ^REQUIREMENTS:
* pzOpt should have been created using optinit!
*
* ^SIDE-EFFECTS:
* pzOpt is modified.
*
* ^RETURN-VALUE:
* None.
*
* ^ALGORITHM:
* Trivial.
*/
void
optreset(tzOptStr *pzOpt)
{
pzOpt->iOptNdx = 0;
pzOpt->pcNxtChr = NULL;
pzOpt->pzLstOpt = NULL;
}
/*
* ^FUNCTION: optinit, optfree - create and destroy an options structure
*
* ^SYNOPSIS:
* pzOpt = optinit(pcCmd, azOptDef);
* optfree(pzOpt);
*
* ^PARAMETERS:
* const char *pcCmd -- the command (program) name
* const tzOptDef *pzOptDef -- the valid options structure
*
* ^DESCRIPTION:
* Optinit allocates space for an tzOptStr structure and initializes it.
* It returns a pointer to the newly created options structure. If space
* cannot be allocated of if one of the option-specifications is invalid
* then a message is printed on stderr and exit(127) is called.
*
* Optfree deallocates the storage associated with an options structure.
*
* Optinit and optfree manage a very small buffer of statically allocated
* tzOptStr structures. If less than two tzOptStr structures are in use
* at any given time than the normal overhead associated with malloc and
* is avoided.
*
* ^REQUIREMENTS:
* The options structure passed to optfree MUST have been created with
* optinit.
*
* ^SIDE-EFFECTS:
* for optinit() - space is allocated and initialized. Any error messages
* are printed on stderr.
*
* for optfree() - space is deallocated (and the caller should probably
* set the corresponding tzOptStr pointer to NULL upon return).
*
* ^RETURN-VALUE:
* Optinit returns a pointer to the newly allocated options structure.
*
* ^ALGORITHM:
* Fairly trivial.
*/
/*
* We keep a small pool of options-structures here for "allocation" via
* optinit(). We assume that the user usually wont need more than two
* option-structures at a time. In such cases we try to avoid the overhead
* of malloc and free (and the need for error-checking).
*/
#define POOL_SIZE 2
static tzOptStr zOptPool[POOL_SIZE];
/* Our local pool of readily available option-structures.
*/
static char opt_used[POOL_SIZE] =
{ '\0', '\0' };
/* Indicates which "members" of our local pool are currently in use.
* opts_used[i] == 0 implies that zOptPool[i] is available for use.
*/
tzOptStr *
optinit (const char *pcCmd,
const tzOptDef *pzOptDef)
{
tzOptStr *pzOpt;
optdef_ver (pzOptDef); /* make sure all the option-specs are valid */
/* get space */
if (! *opt_used)
{
pzOpt = zOptPool;
++(*opt_used);
}
else if (! opt_used[1])
{
pzOpt = &(zOptPool[1]);
++(opt_used[1]);
}
else
{
pzOpt = (tzOptStr *) malloc(sizeof(tzOptStr));
if (! pzOpt)
{
perror("Unable to allocate space for options-structure.");
exit(127);
}
}
/* initialize */
pzOpt->uOptMsk = opt_DEFAULT;
pzOpt->iOptNdx = 0;
pzOpt->pcNxtChr = NULL;
pzOpt->pzLstOpt = NULL;
pzOpt->pzOptDef = pzOptDef;
pzOpt->pcCmd = strrchr(pcCmd, '/');
pzOpt->pcCmd = (pzOpt->pcCmd == NULL) ? pcCmd : (pzOpt->pcCmd + 1);
return (pzOpt);
}
void
optfree(tzOptStr *pzOpt)
{
if (pzOpt == NULL) return;
if (pzOpt == zOptPool)
{
*opt_used = '\0';
}
else if (pzOpt == &(zOptPool[1]))
{
opt_used[1] = '\0';
}
else
{
free(pzOpt);
}
}
Original message headers
X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: f996b,1847fbfe9dabdb02,start X-Google-Attributes: gidf996b,public X-Google-ArrivalTime: 1994-06-13 23:56:08 PST Path: nntp.gmd.de!Germany.EU.net!EU.net!uunet!psinntp!heimdall!sgige1!gehotch From: geh...@sdrc.com (Ric Hotchkiss) Newsgroups: alt.ascii-art Subject: BIG, POSTSCRIPT, OVERSTRIKE, GIF: BINARY - ascii2ps Message-ID: <868...@heimdall.sdrc.com> Date: 13 Jun 94 16:33:48 GMT Sender: new...@heimdall.sdrc.com Reply-To: Ric...@sdrc.com Followup-To: alt.ascii-art Organization: Me Lines: 1862
Related ASCII art in the Gallery
Explore these categories from our collection of 11,000+ artworks:
\\__ o
|\/ o\ o
> < o
|/\ __/
// |\__/,| (`\ |_ _ |.--.) ) ( T ) / (((^_(((/(((_/
, _ , ( o o ) /'` ' `'\ |'''''''| |\\'''//| """
,~~--~~-. + | |\ || |~ |`,/-\ *\_) \_) `-'
__
\ \ _ _
\**\ ___\/ \
X*#####*+^^\_\
o/\ \
\__\ .------------. |\\//\\//\\//| |//\\//\\//\\| |\\//\\//\\//| |//\\//\\//\\| '------------'
Make your own ASCII art
Turn images, text or 3D into ASCII, or draw your own – right in your browser.
About this message.
This message was posted publicly to the newsgroup
alt.ascii-art
in 1994 and is mirrored here unchanged as part of the Historic Archives – only email addresses are masked.
The artwork and text belong to their original authors: if you copy a piece, keep the artist's initials or signature intact and credit them where you can.
Are you the author? Contact us to get your posts attributed, connected to your artist profile, or removed.
Report this message
Help us keep the archive clean and accurate. Reports are reviewed by a person – nothing is changed automatically.