%{
/*	This program is converts manual pages written in TeX format to a 
	format understood by nroff and the nroff macro package -man.

	A set of TeX macros is defined in the file manualMacros.tex.
	Those macros are converted by this program:

	\manFont	-- set roman or sansserif font
	\manTitle	-- set up the title
	\manPageInfo	-- set page foot center, foot left, and head center
	\manBegin	-- begin the man page
	\manEnd		-- end the man page
	\manSection	-- start a section
	\manSubSection	-- start a subsection
	\manItemIndent	-- set the hanging indentation for items
	\manItem	-- set up itemized paragraph
	\lineBreak	-- fill and break the current line
	\manName	-- dummy macro to identify man page name keywords
	\manIfNroff	-- ignore
	\manIfTex	-- ignore everything that follows up to the next
			   \manEndIf
	\manFi		-- ignore unless we are in a \manIfTex
	\manElse	-- switches depending of whether \manIfNroff or
			   \manIfTeX was set

	Regular TeX directives which are translated include:

	\cverbatim	-- set up C literal mode
	@endcverbatim	-- end C literal mode
	<blank line>	-- start a new paragraph
	\bf		-- set bold face font
	\tt		-- set typewritter font
	\it		-- set italix font
	\centerline	-- center a line of text
	\vfil\eject	-- (ignored by texman)
	\bigskip	-- (translated to skip two lines)
	\medskip	-- (translated to skip one line)
	\smallskip	-- (translated to null)
	\item		-- set itemized paragraph with indent of 3
	\diamondsuit	-- insert a '<>'
	\le		-- (translated to <=)
	\ge		-- (translated to >=)
	``		-- translated to "
	''		-- translated to "
	\$		-- translated to $
	\{		-- translated to {
	\}		-- translated to }
	\-		-- ignored
	\/		-- ignored
	\#		-- translated to #
	\%		-- translated to %
	\times		-- translated to X
	\\		-- translated to \
	\hbox		-- ignored
	\;		-- ignored
        \noindent       -- ignored	

	@@              -- turned into @ (in literal mode)
	
*/


#include <stdio.h>
#include <ctype.h>
#include <varargs.h>

#include "../h/cdefs.h"



#define MBUFSIZE	0x10000
#define MAXMARGS	32

#define FONT		1
#define TITLE		2
#define PAGEINFO	3
#define SECTION		4
#define MANITEMINDENT	5
#define MANITEM		6
#define CENTERLINE	7
#define ITEM		8
#define MANINSET	9
#define MANNAME		10
#define SUBSECTION      11

#define NESTABLE	0x1

char macroBuf[MBUFSIZE];
char *macroBufp;
char *macroArgv[MAXMARGS];
int macroArgc;
int macroActive = 0;
int macroArgCount = 0;
int macroLevel;

#define MAXLEVEL	128
int groupLevel = 0;
char fontStack[MAXLEVEL];
char quotes[MAXLEVEL];
char currentFont = 'R';
char currentQuotes = 0;

int ttStandout = NO;

%}
ee	(\n|([ \t]+\n?)|[^a-zA-Z \t\n])
%option yylineno
%START	NORM LITERAL
%%
<NORM>\\[a-zA-Z]+{ee}	{ controlSequence();
			}
<NORM>\\tolerance[ \t]*=[ \t]*[0-9]+{ee}	{
			  controlSequence();
			}
<NORM>\\rightskip[ \t]*=[ \t]*[0-9a-zA-Z]+{ee}	{
			  controlSequence();
			}
<NORM>\\\input{ee}.*\n  { controlSequence();
			}
<LITERAL>@endcverbatim{ee} { controlSequence();
			}
<LITERAL>@@             { printo ("@");
			}
<NORM>\\\$		{ printo ("$");
			}
<NORM>\$		{ /* ignore */
			}
<NORM>\#		{ printo ("#");
			}
<NORM>\%		{ printo ("%%");
			}
<NORM>``		{ printo ("\"");
			}
<NORM>''		{ printo ("\"");
			}
<NORM>\\\{		{ printo ("{");
			}
<NORM>\\\}		{ printo ("}");
			}
<NORM>\\-		{ /* ignore */
			}
<NORM>\\\/		{ /* ignore */
			}
<NORM>\\\;		{ /* ignore */
			}
<NORM>\\#		{ printo ("#");
			}
<NORM>\\~		{ printo ("~");
			}
<NORM>\\\\		{ printo ("\\");
			}
<NORM>\{		{ fontStack[groupLevel] = currentFont;
			  quotes[groupLevel] = currentQuotes;
			  if (macroActive && groupLevel == macroLevel)
			   { macroArgv[macroArgc] = macroBufp;
			   }
			  groupLevel++;
			}
<NORM>\}		{ groupLevel--;
			  if (quotes[groupLevel] != currentQuotes)
			   { currentQuotes = quotes[groupLevel];
			     printo ("\"");
			   }
			  if (fontStack[groupLevel] != currentFont)
			   { currentFont = fontStack[groupLevel];
			     printo ("\\f%c", currentFont);
			   }
			  if (macroActive && groupLevel == macroLevel)
			   { macroArgc++;
			     *macroBufp++ = '\0';
			     if (macroArgc == macroArgCount)
			      { int macro = macroActive;
				macroActive = 0;
				invokeMacro (macro);
			      }
			   }
			}
\n[ \t\n]*\n		{ if (macroActive)
			   { fatalMsg (-1,
		"can't start paragraph inside macros, line %d\n", yylineno);
			   }
			  newline(); printo (".PP\n");
			}
\n			{ if (macroActive)
			   { if (macroLevel < groupLevel)
			      { if (!isspace (macroBufp[-1]))
				 { printo (" ");
				 }
			      }
			   }
			  else
			   { newline();
			   }
			}
[ \t]			{ if (!macroActive ||
			       macroActive && macroLevel < groupLevel)
			   { printo (yytext);
			   }
			}
.			{ if (macroActive && macroLevel == groupLevel)
			   { fatalMsg (-1,
		"malformed macro argument, line %d\n", yylineno);
			   }
			  else
			   { printo (yytext);
			   }
			}
%%

int outputSuppress = 0;
int nameMode = 0;

main(argc, argv)
int argc;
char *argv[];
{
	argc--; argv++;
	while (argc--)
	 { if (ARGUMENT ("-ttso"))
	    { ttStandout = YES;
	    }
	   else if (ARGUMENT ("-N"))
	    { outputSuppress = 1;
	      nameMode = 1;
	    }
	   else
	    { usageMsg (-1, "texman [-N] [-ttso]\n");
	    }
	 }
	BEGIN NORM;
	yylex();
	exit (0);	
}

yywrap()
{
	return(1);
}

#define SEQUENCE(x)	(strcmp(yytext, (x)) == 0)

controlSequence()
{
	int c;
	char *cp;

	c = yytext[strlen(yytext)-1];
	if (!isalpha(c) && c != ' ' && c != '\t' && c != '\n')
	 { unput (c);
	 }
	cp = &yytext[1];
	while (isalpha(*cp))
	 { cp++;
	 }
	*cp = '\0';

	if (SEQUENCE ("\\manIfNroff"))
	 { 
	   /* ignore */
	 }
	else if (SEQUENCE ("\\manIfTeX"))
	 { outputSuppress = 1;
	 }
	else if (SEQUENCE ("\\manElse"))
	 { if (!nameMode)
	    { outputSuppress = !outputSuppress;
	    }
	 }
	else if (SEQUENCE ("\\manFi"))
	 { if (outputSuppress && !nameMode)
	    { outputSuppress = 0;
	    }
	 }
	else if (SEQUENCE ("\\times"))
	 { printo ("X");
	 }
	else if (SEQUENCE ("\\smallskip"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't skip spaces inside macros, line %d\n", yylineno);
	    }
	 }
	else if (SEQUENCE ("\\medskip"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't skip spaces inside macros, line %d\n", yylineno);
	    }
	   newline(); printo (".sp 1\n");	   
	 }
	else if (SEQUENCE ("\\dots"))
	 { printo (" ... ");
	 }
	else if (SEQUENCE ("\\bigskip"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't skip spaces inside macros, line %d\n", yylineno);
	    }
	   newline(); printo (".sp 2\n");
	 }
	else if (SEQUENCE ("\\cverbatim"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't do \\cverbatim inside macros, line %d\n", yylineno);
	    }
	   newline(); printo (".nf\n");
	   BEGIN LITERAL;
	 }
	else if (SEQUENCE ("@endcverbatim"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't do @endcverbatim inside macros, line %d\n", yylineno);
	    }
	   newline(); printo (".fi\n.sp 1\n");
	   BEGIN NORM;
	 }
	else if (SEQUENCE ("\\tt"))
	 { if (macroActive && macroLevel == groupLevel)
	    { fatalMsg (-1,
	      "malformed macro arguments, line %d\n", yylineno);
	    }
	   if (ttStandout)
	    { printo ("\\fI");
	      currentFont = 'I';
	    }
	 }
	else if (SEQUENCE ("\\TT"))
	 { if (macroActive && macroLevel == groupLevel)
	    { fatalMsg (-1,
	      "malformed macro arguments, line %d\n", yylineno);
	    }
	   if (ttStandout)
	    { printo ("\\fI");
	      currentFont = 'I';
	    }
	   else if (!currentQuotes)
	    { printo ("\"");
	      currentQuotes = 1;
	    }
	 }
	else if (SEQUENCE ("\\bf"))
	 { if (macroActive && macroLevel == groupLevel)
	    { fatalMsg (-1,
	      "malformed macro arguments, line %d\n", yylineno);
	    }
	   printo ("\\fB");
	   currentFont = 'B';
	 }
	else if (SEQUENCE ("\\it"))
	 { if (macroActive && macroLevel == groupLevel)
	    { fatalMsg (-1,
	      "malformed macro arguments, line %d\n", yylineno);
	    }
	   printo ("\\fI");
	   currentFont = 'I';
	 }
	else if (SEQUENCE ("\\manBegin"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't do \\manBegin inside macros, line %d\n", yylineno);
	    }
	 }
	else if (SEQUENCE ("\\manEnd"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't do \\manEnd inside macros, line %d\n", yylineno);
	    }
	 }
	else if (SEQUENCE ("\\manName"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't do \\manName inside macros, line %d\n", yylineno);
	    }
	   if (nameMode)
	    { startMacro (MANNAME, 1);
	    }
	 }
	else if (SEQUENCE ("\\end"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't do \\end inside macros, line %d\n", yylineno);
	    }
	   printo (".ex\n");
	 }
	else if (SEQUENCE ("\\manSection"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't do \\manSection inside macros, line %d\n", yylineno);
	    }
	   startMacro (SECTION, 1);
	 }
	else if (SEQUENCE ("\\manSubSection"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't do \\manSubSection inside macros, line %d\n", yylineno);
	    }
	   startMacro (SUBSECTION, 1);
	 }
	else if (SEQUENCE ("\\manItem"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't do \\manItem inside macros, line %d\n", yylineno);
	    }
	   startMacro (MANITEM, 1);
	 }
	else if (SEQUENCE ("\\manInset"))
	 { if (macroActive)
	    { fatalMsg (-1,
	      "can't do \\manInset inside macros, line %d\n", yylineno);
	    }
	   startMacro (MANINSET, 1);
	 }
	else if (SEQUENCE ("\\item"))
	 { if (macroActive)
	    { fatalMsg (-1,
		"can't do \\item inside macros, line %d\n", yylineno);
	    }
	   startMacro (ITEM, 1);
	 }
	else if (SEQUENCE ("\\manItemIndent"))
	 { if (macroActive)
	    { fatalMsg (-1,
		"can't do \\manItemIndent inside macros, line %d\n", yylineno);
	    }
	   startMacro (MANITEMINDENT, 1);
	 }
	else if (SEQUENCE ("\\manTitle"))
	 { if (macroActive)
	    { fatalMsg (-1,
		"can't do \\manTitle inside macros, line %d\n", yylineno);
	    }
	   startMacro (TITLE, 2);
	 }
	else if (SEQUENCE ("\\manPageInfo"))
	 { if (macroActive)
	    { fatalMsg (-1,
		"can't do \\manPageInfo inside macros, line %d\n", yylineno);
	    }
	   startMacro (PAGEINFO, 3);
	 }
	else if (SEQUENCE ("\\lineBreak"))
	 { if (macroActive)
	    { fatalMsg (-1,
		"can't do \\lineBreak inside macros, line %d\n", yylineno);
	    }
	   newline ();
	   printo (".br\n");
	 }
	else if (SEQUENCE ("\\centerline"))
	 { if (macroActive)
	    { fatalMsg (-1,
		"can't do \\centerline inside macros, line %d\n", yylineno);
	    }
	   startMacro (CENTERLINE, 1);
	 }
	else if (SEQUENCE ("\\manFont"))
	 { if (macroActive)
	    { fatalMsg (-1,
		"can't do \\manFont inside macros, line %d\n", yylineno);
	    }
	   startMacro (FONT, 1);
	 }
	else if (SEQUENCE ("\\input"))
	 { if (macroActive)
	    { fatalMsg (-1,
		"can't do \\input inside macros, line %d\n", yylineno);
	    }
	 }
	else if (SEQUENCE ("\\diamondsuit"))
	 { printo ("<>");
	 }
	else if (SEQUENCE ("\\pi"))
	 { printo ("PI");
	 }
	else if (SEQUENCE ("\\tolerance"))
	 { /* ignore */
	 }
	else if (SEQUENCE ("\\rightskip"))
	 { /* ignore */
	 }
	else if (SEQUENCE ("\\hbox"))
	 { /* ignore */
	 }
	else if (SEQUENCE ("\\noindent"))
	 { /* ignore */
	 }
	else if (SEQUENCE ("\\le"))
	 { printo ("<=");
	 }
	else if (SEQUENCE ("\\ge"))
	 { printo (">=");
	 }
}

char obuf[1024];
char lastc = '\n';

printo(va_alist)
va_dcl
{
	char *s;
	register char *cp;
	va_list ap;

	va_start(ap);
	s = va_arg(ap, char*);
	vsnprintf (obuf, 1024, s, ap);
	if (macroActive)
	 { strcpy (macroBufp, obuf);
	   macroBufp += strlen (obuf);
	 }
	else if (!outputSuppress)
	 { for (cp=obuf; *cp != '\0'; cp++)
	    { putchar (lastc = *cp);
	    }
	 }
	va_end(ap);
}

newline()
{
	if (lastc != '\n')
	 { putchar (lastc = '\n');
	 }
}
/*
input() 
{
	if (yysptr > yysbuf)
	 { yytchar = *(--yysptr);
	 }
 	else
  	 { int c = getc(yyin);
	   yytchar = c;
	 }
	if (yytchar == '\n')
  	 { yylineno++;
	 }
	if (yytchar == EOF)
  	 { return (0);
	 }
	else
 	 { return (yytchar);
	 }
}

unput(c) 
{	
	yytchar = (c);
	if (yytchar == '\n')
	 { yylineno--;
	 }
	*yysptr++ = yytchar;
}
*/
startMacro (name, numArgs)
int name;
int numArgs;
{
	macroLevel = groupLevel;
	macroActive = name;
	macroArgCount = numArgs;
	macroArgc = 0;
	macroBufp = macroBuf;
}
	
invokeMacro (macro)
int macro;
{
	switch (macro)
	 { case SECTION:
	    { sectionMacro();
	      break;
	    }
	   case SUBSECTION:
	    { subsectionMacro();
	      break;
	    }
	   case MANITEM:
	    { manitemMacro();
	      break;
	    }
	   case MANITEMINDENT:
	    { manitemIndentMacro();
	      break;
	    }
	   case ITEM:
	    { itemMacro();
	      break;
	    }
	   case TITLE:
	    { titleMacro();
	      break;
	    }
	   case PAGEINFO:
	    { pageInfoMacro();
	      break;
	    }
	   case CENTERLINE:
	    { centerlineMacro();
	      break;
	    }
	   case FONT:
	    { break;
	    }
	   case MANINSET:
	    { manInsetMacro();
	      break;
	    }
	   case MANNAME:
	    { manNameMacro();
	      break;
	    }
	 }
}

sectionMacro()
{
	newline();
	printo (".SH %s\n", macroArgv[0]);
}

subsectionMacro()
{
	newline();
#ifdef sun
	printo (".SS %s\n", macroArgv[0]);
#else
	printo (".SH %s\n", macroArgv[0]);
#endif
}

itemMacro()
{
	newline();
	if (strcmp (macroArgv[0], "") == 0)
	 { printo (".IP \"\" %d\n", 3);
	 }
	else
	 { printo (".TP %d\n", 3);
	   printo ("%s\n", macroArgv[0]);
	 }
}

int manitemIndent = 8;

manitemMacro()
{
	newline();
	if (strcmp (macroArgv[0], "") == 0)
	 { printo (".IP \"\" %d\n", manitemIndent);
	 }
	else
	 { printo (".TP %d\n", manitemIndent);
	   printo ("%s\n", macroArgv[0]);
	 }
}

manitemIndentMacro()
{
	int i;
	if (sscanf (macroArgv[0], "%d", &i) != 1)
	 { fatalMsg (-1, 
	"error reading integer value for \\manItemIndent, line %d\n", yylineno);
	 }
	manitemIndent = i;
}

char pageHeadCenter[256] = "UNIX Programmer's Manual";
char pageFootCenter[256] = "";
char pageFootLeft[256] = "4.3 BSD";

titleMacro()
{
	newline();
	printo (".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
		macroArgv[0],
		macroArgv[1],
		pageFootCenter,
		pageFootLeft,
		pageHeadCenter);
	printo (".na\n");    	
}

pageInfoMacro()
{
	strcpy (pageHeadCenter, macroArgv[0]);
	strcpy (pageFootLeft, macroArgv[1]);
	strcpy (pageFootCenter, macroArgv[2]);
}

centerlineMacro()
{
	newline();
	printo (".ce 1\n");
	printo ("%s\n", macroArgv[0]);
}

manInsetMacro()
{
	newline();
	printo (".in +0.5i\n");
	printo (".ll -0.5i\n");
	printo ("%s", macroArgv[0]);
	newline();
	printo (".ll +0.5i\n");
	printo (".in -0.5i\n");
}

manNameMacro()
{
	printf ("%s\n", macroArgv[0]);
}
