/*
 * An output filter to produce LaTeX using Paul DuBois' RTF reader
 * WECHTL Erwin
 * Woerthg. 2/18
 * A-2500 Baden
 * AUSTRIA
 *
 * a student of the University in vienna
 * Technische Universitaet Wien
 * Institut fuer Technische Informatik
 * Treitlstr. 3
 * A-1040 WIEN
 * AUSTRIA
 *
 * Changed code from:
 *
 * Written and copyright (c) 1991 by Robert Lupton (rhl@astro.princeton.edu)
 * Permission is granted to freely distribute and modify this code, providing:
 *	1/ This copyright notice is preserved
 *	2/ You send me a copy of any changes for inclusion in a future release
 */
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#ifdef __STDC__
#   include <stdlib.h>
#   ifndef THINK_C
#      include <unistd.h>
#   endif
#else /* !__STDC__ */
#   ifdef NO_MALLOC_H
        extern char     *malloc ();
#   else /* NO_MALLOC_H */
#       include    <malloc.h>
#   endif /* NO_MALLOC_H */
#endif /* !__STDC__ */
#ifndef SEEK_SET
#   define SEEK_SET 0
#endif
#include "fonts.h"
#include "r2L_version.h"
#include "rtf2LaTeX.h"
#include "rtf.h"

#ifdef THINK_C
#include <console.h>
#include "macintosh.h"
static char * RTFDIR;
#endif


char *progname;	/* Used in Error messages */
RTFFuncPtr default_read_font = NULL;	/* default func to read style table */
RTFFuncPtr default_read_style = NULL;	/* default func to read style table */

/* This forward declaration isn't possible in the header file because
 * RTFStyle isn't defined there yet.
 */
static int is_specialWORDstyle A((RTFStyle*,LATEXStyle*));
/*****************************************************************************/
int
main(ac,av)
int ac;
char *av[];
{
   RTF_STACK rtf_initial;		/* initial values of things that
					   on rtf stack */

   static char *header_erwinbet[] = {
      "% Converted from RTF format using rtf2LaTeX",
      "% Comments and bugs to Erwin Wechtl",
      "%                      Woertg. 2/18",
      "%                      A-2500 Baden",
      "%",
      NULL,
   };


FILE *fil = NULL;
extern int optind;
extern char *optarg;
int c;
char *codefile = "mac", *landfile = "english";
char *str = "12345.67";
char *rtf_filename = NULL;

#ifdef THINK_C
   RTFDIR = get_home_dir();
   ac = ccommand(&av);
#endif /* THINK_C */

   progname = av[0];
   while((c = getopt(ac,av,"cC:dhgGHL:npqrstT:uv:V")) != EOF)
      {
      switch (c)
       {
       case 'g':
	 german_squotes = 1;
	 break;
       case 'G':
	 german_dquotes = 1;
	 break;
       case 'q':
	 translate_quotes = 1;
	 break;
       case 'C':
	 codefile = optarg;
	 break;
       case 'c':			/* don't do character formating */
	 formatting_char= 0;
	 break;
       case 'd':			/* formate also in specila WORD styles like heading, footer, footnote text, .. (default 0) */
	 formatting_sWORD = 1;
	 break;
       case 'h':
	 usage();
	 exit(0);
       case 'H':			/* use LaTeX default header and footer */
	 header_on = 0;
	 break;
       case 'L':
	 landfile = optarg;
	 break;
       case 'n':
	 other_linebreak = 1;           /* use \hfil\break instead of \\ */
	 break;                         /* for making a new line         */
       case 'p':			/* don't do paragraph formating */
	 formatting_para =  0;
	 break;
       case 'r':			/* ignore left and right skip */
	 rl_skip_on = 0;
	 break;
       case 's':			/* ignore tab stops */
	 tabstops_on = 0;
	 break;
       case 't':			/* don't do any formating in tables */
	 formatting_table =  0;
	 break;
       case 'T':			/* decrease cell-width (default 0.7)*/
	 smaller_cell_factor=atof(optarg);
	 if (!(smaller_cell_factor > 0))
		{
		fprintf(stderr,"\n%s: Argument of the -T flag must be greater than 0,\n but it is %g\n", progname, smaller_cell_factor);
		fprintf(stderr,"use -h for help\n");
		exit(2);
		}
	 break;
       case 'u':			/* change underline to italic */
	 noUnderline = 1;
	 break;
       case 'v':
	 verbose = atoi(optarg);
	 if (verbose!=1 && verbose!=2)
		{
		fprintf(stderr,"\n%s: The level of verbose can only be 1 or 2\n", progname);
		fprintf(stderr,"use -h for help\n");
		exit(2);
		}
	 break;
       case 'V':
	 fprintf(stderr,"%s: %s\n",progname,version);
	 exit(0);
	 break;
       case '?':
	 fprintf(stderr,"%s: ", progname);
	 usage();
	 exit(2);
      }
    }
  if (optind<ac)
  {
      if ((strchr(av[optind],'.')) != NULL)
	rtf_filename = av[optind];
      else
      {
	if((rtf_filename = malloc(strlen(av[optind]) + 5)) == NULL)
	{
	    fprintf(stderr,"%s: Error in malloc\n", progname);
	    exit(3);
	}
	strcpy(rtf_filename, av[optind]);
      	strcat(rtf_filename,".rtf");
      }
  }
#ifdef THINK_C
  else rtf_filename = get_file_from_dialog();
  if (!rtf_filename) exit(0);
#endif
  if(rtf_filename != NULL)
  {
      if((fil = fopen(rtf_filename,"r")) == NULL)
      {
	 fprintf(stderr,"%s: Can't open %s\n",progname,rtf_filename);
	 exit(1);
      }
      RTFSetStream(fil);
  }
  if (optind+1<ac)
	{
	fprintf(stderr,"%s: After the filename (%s) there are no more arguments or flags allowed!\n", progname, av[optind]);
	fprintf(stderr,"use -h for help\n");
	exit(2);
	}

   rtf_default.LaTeX_stack = NULL;	/* the rtf stack */
   rtf_default.char_attr = char_attr;
   rtf_default.par_attr = par_attr;
   rtf_default.style = -1;
   rtf_default.prev = NULL;
   rtf_current = rtf_initial = rtf_default;
   rtf_ptr=&rtf_default;
   tabinitold[0]=tabinitnew[0]='\0';
   Cformatting_char=formatting_char;
   Cformatting_para=formatting_para;
   tabstopsInit();
   RTFInit();
   read_code_file(codefile);		/* the file with the characters above 126
					   files have the extension .code
					   default file mac.code 
					   use flag -C for other files
						e.g ansi.code*/
   open_land_file(landfile);		/* the file with the special WORD styles 
					   footer, footnote text, heading, ...
					   files have the extension .land
					   default file english.land
					   use flag -L for other files
						e.g german.land    */
   print_text(header_erwinbet,stdout);
   output_str("\\documentstyle",'\0');
   if(german_squotes || german_dquotes)
       output_str("[german]",'\0');
   output_str("{article}\n",'\0');
   if(header_on)
	{
	output_str("\\pagestyle",'\0');
	output_str("{myheadings}\n",'\0');
	}
   output_str("\\newlength{\\defaultparindent}\n",'\0');
   output_str("\\setlength{\\defaultparindent}{\\parindent}\n",'\0');
   default_read_font = RTFGetDestinationCallback(rtfFontTbl);

   (void)RTFSetClassCallback(rtfUnknown, UnknownClass);
   (void)RTFSetClassCallback(rtfGroup, GroupClass);
   (void)RTFSetClassCallback(rtfText, start_para);
   (void)RTFSetClassCallback(rtfControl, ControlClass);
   (void)RTFSetDestinationCallback(rtfPict, read_pict);

   RTFRead();
   
   if(rtf_group != 0) {
      fprintf(stderr,"%s: End of file is in an unclosed RTF group (level %d)\n",
	      progname,rtf_group);
   }
   if(LaTeX_group != 0) {
      fprintf(stderr,"%s: End of file is in an unclosed LaTeX group (level %d)\n",
	      progname,LaTeX_group);
   }
   if(quotecount % 2)
   {
      fprintf(stderr,"%s: Uneven number of quotes (%d) counted\n",
	      progname, quotecount);
   }
   if(fil != NULL) fclose(fil);
   output_str("\\end{document}",'\0');
   if (verbose)
	fprintf(stderr,"\nIf there are any LaTeX errors or warnings,\n\
have a look in the man page section troubleshooting \n\n");
   return(0);
}
/*****************************************************************************
 *
 * Token class callbacks
 */
static void
UnknownClass()
{
   fprintf(stderr,"%s: Unknown Token: %s\n",progname,rtfTextBuf);
}
/*****************************************************************************/
static void
GroupClass()
{
   switch (rtfMajor) {
    case rtfBeginGroup:
      if(initialised && !text_out) {
	 start_para();
      }
      if (!table_mode)		/*it's hard to know where the end of    */
	end_table();          /*       a table is, maybe here           */
      push_rtf_group();
      rtf_group++;
      break;
    case rtfEndGroup:
      if(--rtf_group == -1) {
	 fprintf(stderr,"%s: Unbalanced group\n", progname);
      } else {
	 while(pop_LaTeX_stack()) continue;
	 pop_rtf_group();
	 if(end_of_par) {
	    end_para();
	 }
      }
      break;
   }
}
static void
initialise()
{
   inDefineStyle=TRUE;
   DefineStyles();
   inDefineStyle=FALSE;
   if(pageno != 1) {
      sprintf(buff,"\\setcounter{page}{%d}\n",pageno);
      output_str(buff,'\0');
   }
   output_str("\n%*****************************************************************",'\0');
   output_str("\n\\begin{document}\n",'\0');
   tabstopsInit();
   initialised = 1;			/* don't do it twice */
}
/*****************************************************************************/
static void
TextClass()
{
   output(rtfMajor,1);
}
/*****************************************************************************
 *
 * Process control symbol.
 */
static void
ControlClass()
{
   switch (rtfMajor) {
    case rtfVersion:
      if(verbose) fprintf(stderr,"RTF version %d\n",rtfParam);
      break;
    case rtfDefFont:
      default_font = rtfParam;		/* this may not be in the font table */
      break;
    case rtfCharSet:
      CharSet ();
      break;
    case rtfDestination:
      Destination();
      break;
    case rtfFontFamily:			/* only occurs within font table */
      fprintf(stderr,"%s: You shouldn't see rtfFontType: minor %d\n",
	progname,rtfMinor);
      break;
    case rtfColorName:			/* only occurs within color table */
      fprintf(stderr,"%s: You shouldn't see rtfColorName: minor %d\n",
	progname,rtfMinor);
      break;
    case rtfStyleAttr:			/* only occurs within stylesheet */
      switch (rtfMinor) {
       case rtfBasedOn:
	 if(rtfParam != rtfNoParam) {
	    static int count = 0;
	 
	    if(verbose > 1 || (verbose && count++ == 0)) {
	       msg_not_yet("sbasedon");
	    }
	 }
	 break;
       case rtfNext:
	 if(rtfParam != rtfNoParam) {
	    static int count = 0;
	 
	    if(verbose > 1 || (verbose && count++ == 0)) {
	       msg_not_yet("snext");
	    }
	 }
	 break;
       default:
	 fprintf(stderr,"%s: Illegal minor number for StyleAttr: %d\n",
	    progname,rtfMinor);
	 break;
      }
      break;
    case rtfSpecialChar:
      SpecialChar();
      break;
    case rtfDocAttr:
      DocAttr();
      break;
    case rtfSectAttr:
      SectAttr();
      break;
    case rtfTblAttr:
      TblAttr();
      break;
    case rtfParAttr:
      ParAttr();
      break;
    case rtfCharAttr:
      if (Cformatting_char)
	      CharAttr();
      break;
    case rtfPictAttr:
      fprintf(stderr,"%s: You shouldn't see rtfPictAttr: minor %d\n",
	progname,rtfMinor);
      break;
    case rtfFieldAttr:
      FieldAttr();
      break;
    case rtfTOCAttr:
      TOCAttr();
      break;
    case rtfPosAttr:
      PosAttr();
      break;
   }
}
/*****************************************************************************
 *
 * Control class major number handlers.  Each one switches on the
 * minor numbers that occur within the major number.  rtfStyleSheet,
 * rtfFontTbl, and rtfColorTbl are not in the switch because they're
 * handled by the reader. rtfPict has its own callback.
 */
static void
CharSet()
{
   switch (rtfMinor) {
    case rtfAnsiCharSet:
      break;
    case rtfMacCharSet:
      break;
    case rtfPcCharSet:
      break;
    case rtfPcaCharSet:
      break;
   }
}
static void
Destination()
{
   switch (rtfMinor) {
    case rtfFootnote:
      output_str("%\n",'\0');
      output_str("\\footnote{",'\0');
      push_LaTeX_stack("}%\n",Footnote,0);
      break;
    case rtfHeader:
      if (!initialised)
	initialise();
      if (header_on)
	{
	output_str("\\markright{",'\0');
	push_LaTeX_stack(" }\n",Header,0);
	}
      else
	{
	RTFSkipGroup();
	RTFUngetToken();
	}
      break;
    case rtfHeaderLeft:
    case rtfHeaderRight:
    case rtfHeaderFirst:
      if (verbose)
	 msg_not_supported(rtfTextBuf+1);
      break;
    case rtfFooter:
      if (header_on)
	{
	if (verbose)
		fprintf(stderr,"LaTeX  supports only the header\n");
	output_str("% LaTeX  supports only the header\n",'\0');
	}
	RTFSkipGroup();
	RTFUngetToken();
      break;
    case rtfFooterLeft:
      break;
    case rtfFooterRight:
      break;
    case rtfFooterFirst:
      break;
    case rtfFNSep:
      break;
    case rtfFNContSep:
      break;
    case rtfFNContNotice:
      break;
    case rtfInfo:
      break;
    case rtfField:
      break;
    case rtfFieldInst:
      {
      char buf[80];
      buf[0]='\0';
      (void)RTFGetToken();
      while(rtfClass==rtfText)
	{
	strcat(buf,rtfTextBuf);
	(void)RTFGetToken();
	}
      RTFUngetToken();
      if (strncmp(buf,"date",4)==0)
	output_str("\\today",'\0');
      else
	if (verbose)
	   {
	   char msg_buf[80];
	   strcpy(msg_buf,rtfTextBuf+1);
	   strcat(msg_buf,buf);
	   msg_not_yet(msg_buf);
	   }
      break;
      }
    break;
    case rtfFieldResult:
      break;
    case rtfIndex:
      break;
    case rtfIndexBold:
      break;
    case rtfIndexItalic:
      break;
    case rtfIndexText:
      break;
    case rtfIndexRange:
      break;
    case rtfTOC:
      break;
    case rtfBookmarkStart:
      break;
    case rtfBookmarkEnd:
      break;
    case rtfITitle:
	(void) RTFGetToken ();
	while (rtfClass == rtfText)
		(void) RTFGetToken ();
	RTFUngetToken();
      break;
    case rtfISubject:
	(void) RTFGetToken ();
	while (rtfClass == rtfText)
		(void) RTFGetToken ();
	RTFUngetToken();
       break;
    case rtfIAuthor:
	(void) RTFGetToken ();
	while (rtfClass == rtfText)
		(void) RTFGetToken ();
	RTFUngetToken();
      break;
    case rtfIOperator:
      break;
    case rtfIKeywords:
	(void) RTFGetToken ();
	while (rtfClass == rtfText)
		(void) RTFGetToken ();
	RTFUngetToken();
      break;
    case rtfIComment:
	(void) RTFGetToken ();
	while (rtfClass == rtfText)
		(void) RTFGetToken ();
	RTFUngetToken();
      break;
    case rtfIVersion:
      break;
    case rtfIVerscomm:
/* \verscomm is a token, made by Macintosh's WORD.
 * I don't know the meaning,
 * because it isn't specified in the RTF-specification.
 */
       RTFSkipGroup();
       RTFUngetToken();
       break;
    case rtfIDoccomm:
	(void) RTFGetToken ();
	while (rtfClass == rtfText)
		(void) RTFGetToken ();
	RTFUngetToken();
      break;
   }
}
static void
SpecialChar()
{
   switch (rtfMinor) {
    case rtfCurHeadPage:
      if (verbose && header_on)
	fprintf(stderr,"LaTeX always puts the page number in right corner\n");
      break;
    case rtfCurFNote:
      {
      static int count=0;
      if (verbose && count++ == 0)
	msg_not_needed(rtfTextBuf+1);
      break;
      }
    case rtfCurHeadPict:
      msg_not_supported("chpict");
      break;
    case rtfCurHeadDate:
    case rtfCurHeadTime:
      if (verbose)
	 msg_not_supported(rtfTextBuf+1);
      break;
    case rtfFormula:
      msg_not_yet("|");
      break;
    case rtfNoBrkSpace:
      if(!text_out) start_para();
      output_str("~",'\0');
      break;
    case rtfNoReqHyphen:
      output_str("\\-",'\0');
      break;
    case rtfNoBrkHyphen:
      if(!text_out) start_para();
      output('-',1);
      break;
    case rtfPage:
      end_para();
      end_table();			/* if there is a table */
      output_str("\n\\newpage\n",'\0');
      break;
    case rtfLine:
      if (!other_linebreak)
	output_str("\\\\ \n",'\0');
      else
      	output_str(" \\hfill \\break \n",'\0');
      break;
    case rtfPar:
      if (top_LaTeX_flags(Header))
	  {
          if (!other_linebreak)
	      output_str("\\\\ \n",'\0');
          else
	      output_str(" \\hfill \\break \n",'\0');
	  return;
	  }
      if (top_LaTeX_flags(SpecialWORDstyle))
	  pop_LaTeX_stack();
      if (tab==2 && text_out)
	  {
	  while (!top_LaTeX_flags(Tabstops) )
	     if (pop_LaTeX_stack()==0) break;
	  rtf_current=rtf_default;
	  output_str("\\\\ \n",'\0');
	  update_current();
	  }
    					/* we may want to deal with this
					   elsewhere, so as to pop the stacks
					   before printing the newline */
      RTFGetToken();
      if(RTFCheckCM(rtfGroup,rtfEndGroup) ||
	 RTFCheckCMM(rtfControl,rtfParAttr,rtfParDef)) {
	 end_of_par = 1;
/* Don't know if this one is needed anymore
 *      } else if(in_table && RTFCheckCMM(rtfControl,rtfSpecialChar,rtfPar)) {
 *	 end_table();			* two \par's in a row *
 */
      } else {
	 end_para();
      }
      RTFUngetToken();
      break;
    case rtfSect:
      rtfMinor = rtfPar;		/* pretend that it's just a para */
      RTFUngetToken();
      break;
    case rtfTab:
      if (top_LaTeX_flags(SpecialWORDstyle)) 
	return;				/* no tab stops in header, haeding, ...*/
      if(!text_out) start_para();
      if (!tabstops_on)
	break;
      if (tab)
	 {
	 while (!top_LaTeX_flags(Tabstops) )
		if (pop_LaTeX_stack()==0) break;
	 rtf_current=rtf_default;
	 output_str("\\> ",'\0');
	 update_current();
	 }
      else
	 {
	 output(' ',1);
	 if (verbose && tabstops_on)
		fprintf(stderr,"this tab stop is ignored\n   you have to specify the position of the tab stop before\n");
	 }
      break;
    case rtfCell:
      while (!top_LaTeX_flags(Tabular) )
	if (pop_LaTeX_stack()==0) break;
      rtf_current=rtf_default;
      cellnr++;
      if (cellnr<max_cellnr)
	      output_str(" & ",'\0');
      update_current();
      break;
    case rtfRow:
      while (!top_LaTeX_flags(Tabular) )
	if (pop_LaTeX_stack()==0) break;
      rtf_current=rtf_default;
      cellnr=0;
      output_str("\\\\",'\0');
      output('\n',1);
      update_current();
      break;
    case rtfCurAnnot:
      break;
    case rtfAnnotation:
      break;
    case rtfAnnotID:
      break;
    case rtfCurAnnotRef:
      break;
    case rtfFNoteSep:
      break;
    case rtfFNoteCont:
      break;
    case rtfColumn:
      break;
    case rtfOptDest:
      break;
    case rtfIIntVersion:
      break;
    case rtfICreateTime:
      break;
    case rtfIRevisionTime:
      break;
    case rtfIPrintTime:
      break;
    case rtfIBackupTime:
      break;
    case rtfIEditTime:
      break;
    case rtfIYear:
      break;
    case rtfIMonth:
      break;
    case rtfIDay:
      break;
    case rtfIHour:
      break;
    case rtfIMinute:
      break;
    case rtfINPages:
      break;
    case rtfINWords:
      break;
    case rtfINChars:
      break;
    case rtfIIntID:
      break;
    case rtfBullet:
      output_str("\\bullet ",'\0');
      break;
    case rtfEmDash:
      output_str("---",'\0');
      break;
    case rtfEnDash:
      output_str("--",'\0');
      break;
    case rtfLQuote:
      if(german_squotes)
	 output_str("\\glq ",'\0');
      else
	 output_str("`",'\0');
      break;
    case rtfRQuote:
      if(german_squotes)
	 output_str("\\grq ",'\0');
      else
	 output_str("'",'\0');
      break;
    case rtfLDblQuote:
      if(german_dquotes)
	 output_str("\"`",'\0');
      else
	 output_str("``",'\0');
      break;
    case rtfRDblQuote:
      if(german_dquotes)
	 output_str("\"'",'\0');
      else
	 output_str("''",'\0');
      break;
   }
}
static void
DocAttr()
{
   switch (rtfMinor) {
    case rtfPaperWidth:
    case rtfPaperHeight:
    case rtfLeftMargin:
    case rtfRightMargin:
    case rtfTopMargin:
    case rtfBottomMargin:
      {
      static int count = 0;

      if(verbose > 1 || (verbose && count++ == 0)) {
	       msg_not_yet(rtfTextBuf+1);
	    }
       }
      break;
    case rtfFacingPage:
      if(verbose)
	       msg_not_yet(rtfTextBuf+1);
       break;
    case rtfGutterWid:
      msg_not_yet("gutter");
      break;
    case rtfDefTab:
      msg_not_yet("deftab");
      break;
    case rtfWidowCtrl:
      msg_not_yet("widowctrl");
      break;
    case rtfFNoteEndSect:
      msg_not_yet("endnotes");
      break;
    case rtfFNoteEndDoc:
      break;
    case rtfFNoteBottom:
      break;
    case rtfFNoteText:
      msg_not_yet("ftntj");
      break;
    case rtfFNoteStart:
      if(footnote_num0 != rtfParam) {
	 footnote_num0 = rtfParam;
	 change_headfoot = 1;
      }
      break;
    case rtfFNoteRestart:
      if(footnotes_restart_each_page != 1) {
	 footnotes_restart_each_page = 1;
	 change_headfoot = 1;
      }
      break;
    case rtfHyphHotZone:
      break;
    case rtfPageStart:
      pageno = rtfParam;
      break;
    case rtfLineStart:
      lineno = rtfParam;
      break;
    case rtfLandscape:
      msg_not_supported("landscape");
      break;
    case rtfFracWidth:
      break;
    case rtfNextFile:
      break;
    case rtfTemplate:
      break;
    case rtfMakeBackup:
      break;
    case rtfRTFDefault:
      break;
    case rtfRevisions:
      break;
    case rtfMirrorMargin:
      break;
    case rtfRevDisplay:
      break;
    case rtfRevBar:
      break;
   }
}
/*****************************************************************************/

static void
SectAttr()
{
   switch (rtfMinor) {
    case rtfSectDef:
      set_headfoot_lines();
      break;
    case rtfNoBreak:
      break;
    case rtfColBreak:
      break;
    case rtfPageBreak:
      break;
    case rtfEvenBreak:
      break;
    case rtfOddBreak:
      break;
    case rtfPageStarts:
      break;
    case rtfPageCont:
      break;
    case rtfPageRestart:
      break;
    case rtfPageDecimal:
      if(pageno_style != Pageno_Decimal) {
	 pageno_style = Pageno_Decimal;
	 change_headfoot = 1;
      }
      break;
    case rtfPageURoman:
      if(pageno_style != Pageno_URoman) {
	 pageno_style = Pageno_URoman;
	 change_headfoot = 1;
      }
      break;
    case rtfPageLRoman:
      if(pageno_style != Pageno_LRoman) {
	 pageno_style = Pageno_LRoman;
	 change_headfoot = 1;
      }
      break;
    case rtfPageULetter:
      msg_not_yet("pgnucltr");
      break;
    case rtfPageLLetter:
      msg_not_yet("pgnlcltr");
      break;
    case rtfPageNumLeft:
      if(pageno_x != rtfParam) {
	 pageno_x = rtfParam;
	 change_headfoot = 1;
      }
      break;
    case rtfPageNumTop:
      if(pageno_y != rtfParam) {
	 pageno_y = rtfParam;
	 change_headfoot = 1;
      }
      break;
    case rtfLineModulus:
      if(rtfParam != 0) msg_not_supported("linemod");
      break;
    case rtfLineStarts:
      break;
    case rtfLineDist:
      msg_not_supported("linex");
      break;
    case rtfLineRestart:
      msg_not_supported("linerestart");
      break;
    case rtfLineRestartPg:
      msg_not_supported("lineppage");
      break;
    case rtfLineCont:
      msg_not_supported("linecont");
      break;
    case rtfHeaderY:
      msg_not_yet("headery");
      break;
    case rtfFooterY:
      msg_not_yet("footery");
      break;
    case rtfTopVAlign:
      break;
    case rtfBottomVAlign:
      break;
    case rtfCenterVAlign:
      break;
    case rtfJustVAlign:
      break;
    case rtfColumns:
      if(rtfParam != 1) msg_not_yet("cols");
      break;
    case rtfColumnLine:
      break;
    case rtfColumnSpace:
      msg_not_yet("colsx");
      break;
    case rtfENoteHere:
      msg_not_supported("endnhere");
      break;
    case rtfTitleSpecial:
      msg_not_supported("titlepg");
      break;
   }
}
static void 
TblAttr()
{
   switch (rtfMinor) {
    case rtfCellBordBottom:
    case rtfCellBordTop:
    case rtfCellBordLeft:
    case rtfCellBordRight:
      {
      static int count = 0;

      if(verbose > 1 || (verbose && count++ == 0)) {
	       msg_not_yet(rtfTextBuf+1);
	    }
       }
      break;
    case rtfRowDef:
      table_mode=1;
      push_LaTeX_stack("",TabularInit,1);
      strcpy(tabinitnew,"\n\\begin{tabular}{");
      endOfLastCell=-70;
      max_cellnr=0;
      break;
    case rtfRowLeft:
    case rtfRowRight:
    case rtfRowCenter:
    case rtfRowGapH:
    case rtfRowHt:
    case rtfRowLeftEdge:
      {
      static int count = 0;

      if(verbose > 1 || (verbose && count++ == 0)) {
	       msg_not_yet(rtfTextBuf+1);
	    }
       }
      break;
    case rtfCellPos:
      {
      unsigned int cell_bright;

      max_cellnr++;
      cell_bright=(rtfParam-endOfLastCell)*smaller_cell_factor;
      sprintf(buff,"p{%gpt}",TW_TO_PT(cell_bright));
      strcat(tabinitnew,buff);
      endOfLastCell=rtfParam;
      break;
      }
    case rtfCellShading:
/* \clshdng is a token, made by Macintosh's WORD
 * I don't know the meaning,
 * because it isn't specified in the RTF-specification
 */
      break;
    case rtfMergeRngFirst:
      break;
    case rtfMergePrevious:
      break;
   }
}
/*****************************************************************************/
static void
ParAttr()
{
   switch (rtfMinor) {
    case rtfParDef:
      if(!initialised) {		/* it's hard to know where to call it*/
	 initialise();
      }
      while(top_LaTeX_flags(Font) || top_LaTeX_flags(Font_Num) ||
	    top_LaTeX_flags(Font_Size) || top_LaTeX_flags(Style) ||
	    top_LaTeX_flags(Undefined) || top_LaTeX_flags(Underline) ||
	    top_LaTeX_flags(Sub_Super) || 
	    top_LaTeX_flags(Paragraph) ||
	    top_LaTeX_flags(NormalWORDstyle) ||
	    top_LaTeX_flags(LRskip) || top_LaTeX_flags(SpecialWORDstyle)) {
	 (void)pop_LaTeX_stack();
      }
      rtf_current.par_attr.leftskip=rtf_current.par_attr.rightskip=0;
      if (top_LaTeX_flags(Tabstops))
	{
	 (void)pop_LaTeX_stack();
	Cformatting_char=formatting_char;
	Cformatting_para=formatting_para;
	}
      if (!table_mode && top_LaTeX_flags(Tabular))
	end_table();                  /* it's hard to know where to call it*/
      if ((table_mode) &&               /* begin of a table in rtf */
	    top_LaTeX_flags(TabularInit)  )
	 if (strcmp(tabinitold,tabinitnew)==0)
	    {                          /*we haven't finished the last */
	    (void)pop_LaTeX_stack();   /* table in LaTeX and the parameters */
	    }                          /* of both the current and last      */
				       /* rtf-table are equal so we needn't */
				       /* start a new LaTeX-table      */
	 else
		{
		end_table();         /* we will have to finish the last table, if there is one  */
		strcpy(tabinitold,tabinitnew);
		table_mode=1;
		output_str(tabinitnew,'\0'); /* and to start a new one */
		output_str("}\n",'\0');
		push_LaTeX_stack("\\end{tabular}\n",Tabular,0);
		Cformatting_char=formatting_char&&formatting_table;
		Cformatting_para=formatting_para&&formatting_table;
		}
      if(end_of_par /*&& !table_mode*/) {
	 end_para();
      }
      ntabs = 0;
      table_mode=0;
      tab=0;
      rtf_default.LaTeX_stack = rtf_ptr->LaTeX_stack;
      rtf_default.prev = rtf_ptr->prev;
      *rtf_ptr = rtf_default;
      rtf_current.char_attr = rtf_default.char_attr;
      (void)RTFSetClassCallback(rtfText, start_para); /* not really start a new pragraph
							 but have a look if there is a 
							 table end */
      break;
    case rtfStyleNum:
      if(inDefineStyle)
	 RTFExpandStyle(rtfParam);
      else
	 {
	 if(!initialised)
	     {		/* it's hard to know where to call it*/

	     RTFUngetToken();   /* store the Token, because initialise  */
	     initialise();      /* changes it                           */
	     RTFGetToken();
	     }
	 if (!table_mode && top_LaTeX_flags(Tabular))
		end_table();                  /* it's hard to know where to call it*/
	 setstylecommand(rtfParam);
	 }
      break;
    case rtfQuadLeft:
      {
	 static int count = 0;
	 
	 if(verbose > 1 || (verbose && count++ == 0)) {
	    msg_map_to("gl","gj");
	 }
	 rtf_ptr->par_attr.flags |= LeftAlign;
      }
      break;
    case rtfQuadRight:
      if (text_out)
	{
        if (!Cformatting_para)				/* no paragraph formatting */
		break;
	output_str("\n\\begin{flushright}",'\0');
	push_LaTeX_stack("\n\\end{flushright}",Paragraph,0);
	}
      else
	rtf_ptr->par_attr.flags |= RightAlign;
      break;
    case rtfQuadJust:
      rtf_ptr->par_attr.flags &= ~(LeftAlign | Centred | RightAlign);
      break;
    case rtfQuadCenter:
      if (text_out)
	{
        if (!Cformatting_para)				/* no paragraph formatting */
		break;
	output_str("\n\\begin{center}",'\0');
	push_LaTeX_stack("\n\\end{center}",Paragraph,0);
	}
      else
	rtf_ptr->par_attr.flags |= Centred;
      break;
    case rtfFirstIndent:
      rtf_ptr->par_attr.parindent = rtfParam;
      break;
    case rtfLeftIndent:
      rtf_ptr->par_attr.leftskip = rtfParam;
      break;
    case rtfRightIndent:
      rtf_ptr->par_attr.rightskip = rtfParam;
      break;
    case rtfSpaceBefore:
      rtf_ptr->par_attr.skip_before = rtfParam;
      break;
    case rtfSpaceAfter:
      rtf_ptr->par_attr.skip_after = rtfParam;
      break;
    case rtfSpaceBetween:
      break;
    case rtfInTable:
      table_mode=1;
      break;
    case rtfKeep:
      break;
    case rtfKeepNext:
      break;
    case rtfSideBySide:
      break;
    case rtfPBBefore:
      break;
    case rtfNoLineNum:			/* ignored */
      break;
    case rtfBorderTop:
      break;
    case rtfBorderBottom:
      break;
    case rtfBorderLeft:
      break;
    case rtfBorderRight:
      break;
    case rtfBorderBar:
      break;
    case rtfBorderBox:
      break;
    case rtfBorderBetween:
      break;
    case rtfBorderSingle:
      break;
    case rtfBorderThick:
      break;
    case rtfBorderShadow:
      break;
    case rtfBorderDouble:
      break;
    case rtfBorderDot:
      break;
    case rtfBorderHair:
      break;
    case rtfBorderSpace:
      break;
    case rtfTabPos:
      if (top_LaTeX_flags(SpecialWORDstyle))
	return;				/*no tab stops in header, heading, ...*/
      if (!tabstops_on)
	break;
      if (!table_mode && top_LaTeX_flags(Tabular))
	end_table();
      if (table_mode)
	{
	if (verbose)
		fprintf(stderr,"can't deal with tab stops in tables");
	}
      else
	{
	tab=1;
	if(ntabs >= NTABS) {
		if(ntabs == NTABS)
			fprintf(stderr,"%s: Attempt to set more than %d tabs\n",
			    progname,NTABS);
	} else {
		tabstops[ntabs++].pos = rtfParam;
		tabstops[ntabs].type = TabLeft;
	}
      }
      break;
    case rtfTabRight:
      if(ntabs < NTABS) {
	 tabstops[ntabs].type = TabRight;
      }
      break;
    case rtfTabCenter:
      if(ntabs < NTABS) {
	 tabstops[ntabs].type = TabCentre;
      }
      break;
    case rtfTabDecimal:
      if(ntabs < NTABS) {
	 tabstops[ntabs].type = TabDecimal;
      }
      break;
    case rtfTabBar:
      {
	 static int count = 0;
	 
	 if(verbose > 1 || (verbose && count++ == 0))
	   msg_not_yet("tb");
      }
      break;
    case rtfLeaderDot:
      break;
    case rtfLeaderHyphen:
      break;
    case rtfLeaderUnder:
      break;
    case rtfLeaderThick:
      break;
   }
}
/*procedure not needed yet*/
static void PictAttr ()
{
   switch (rtfMinor) {
    case rtfMacQD:
      break;
    case rtfWinMetafile:
      break;
    case rtfWinBitmap:
      break;
    case rtfPicWid:
      break;
    case rtfPicHt:
      break;
    case rtfPicGoalWid:
      break;
    case rtfPicGoalHt:
      break;
    case rtfPicScaleX:
      break;
    case rtfPicScaleY:
      break;
    case rtfPicScaled:
      break;
    case rtfPicCropTop:
      break;
    case rtfPicCropBottom:
      break;
    case rtfPicCropLeft:
      break;
    case rtfPicCropRight:
      break;
    case rtfPixelBits:
      break;
    case rtfBitmapPlanes:
      break;
    case rtfBitmapWid:
      break;
    case rtfPicBinary:
      break;
   }
}
/*****************************************************************************/
static void
FieldAttr()
{
   switch (rtfMinor) {
    case rtfFieldDirty:
      break;
    case rtfFieldEdited:
      break;
    case rtfFieldLocked:
      break;
    case rtfFieldPrivate:
      break;
   }
}
/*****************************************************************************/
static void
TOCAttr()
{
   switch (rtfMinor) {
    case rtfTOCType:
      break;
    case rtfTOCLevel:
      break;
   }
}
/*****************************************************************************/
static void
PosAttr()
{
   switch (rtfMinor) {
    case rtfPosX:
      break;
    case rtfPosXCenter:
      break;
    case rtfPosXInside:
      break;
    case rtfPosXLeft:
      break;
    case rtfPosXOutSide:
      break;
    case rtfPosXRight:
      break;
    case rtfPosY:
      break;
    case rtfPosYInline:
      break;
    case rtfPosYTop:
      break;
    case rtfPosYCenter:
      break;
    case rtfPosYBottom:
      break;
    case rtfAbsWid:
      break;
    case rtfTextDist:
      break;
    case rtfRPosMargV:
      break;
    case rtfRPosPageV:
      break;
    case rtfRPosMargH:
      break;
    case rtfRPosPageH:
      break;
    case rtfRPosColH:
      break;
   }
}
/*****************************************************************************
 *
 * Deal with Pict destinations
 */
static void
read_pict()
{
static int count=0;
if (verbose && count++==0)
    fprintf(stderr,"%s: Don't support any picture-things yet; be patient\n",
	progname);
if (verbose>1)
    msg_not_yet(rtfTextBuf+1);
    RTFSkipGroup ();
    RTFRouteToken ();       /* feed "}" back to router */

}
/*****************************************************************************
 *
 * Deal with things like footnote numbering and page numbers; things
 * that involve the headline or footline
 */
static void
set_headfoot_lines()
{
   int pageno_top = (pageno_y < paper_height/2 ? 1 : 0);
   if(!change_headfoot) return;
# ifdef notdef /* I think this is left over from rtf2tex */
/*
 * The headline first
 *
   output_str("\\headline={\\tenrm ",'\0');
   if(footnotes_restart_each_page) {
      sprintf(buff,"\\footnum=%d",footnote_num0);
      output_str(buff,' ');
 }
   if(pageno_top) {
      sprintf(buff,"\\kern %gpt %s\\hfil",TW_TO_PT(pageno_x),page_num());
      output_str(buff,' ');
   }
   output_str("}",'\n');
/*
 * And now the foot
 *
   output_str("\\footline={\\tenrm ",'\0');
   if(!pageno_top) {
      sprintf(buff,"\\kern %gpt %s\\hfil",TW_TO_PT(pageno_x),page_num());
      output_str(buff,' ');
   }
   output_str("}",'\n');
   change_headfoot = 0;			/* we've done it *
*/
# endif /* notdef */
}
/*****************************************************************************
 *
 * Convert the pageno to the desired form
 */
static char *
page_num()
{
   switch (pageno_style) {
    case Pageno_Decimal:
      return("\\number\\pageno");
    case Pageno_LRoman:
      return("\\romannumeral\\pageno");
    case Pageno_URoman:
      return("\\uppercase\\expandafter{\\romannumeral\\pageno}");
    default:
      return("");
   }
}
/*****************************************************************************
 *
 * This is called when we see the first text token after each \par
 */
#define CURRENT(WHAT)			/* is WHAT up-to-date? */ \
   (rtf_current.WHAT == rtf_ptr->WHAT)
static void
start_para()
{
   if(!initialised) {			/* this could be the place */
      initialise();
   }

   if(!table_mode && top_LaTeX_flags(Tabular))
		end_table();
   if (tab==1 && !table_mode)
	start_tabstops();
   update_current();
	text_out = 1;
	(void)RTFSetClassCallback(rtfText, TextClass);
	if(rtfClass == rtfText) {
		RTFUngetToken();			/* re-schedule the text */
   }
}
/*
 * End a paragraph
 */
static void
end_para()
{
   if(in_table) {
      tab_num = 0;
   } else {
      if (top_LaTeX_flags(SpecialWORDstyle) || top_LaTeX_flags(Header))
	pop_LaTeX_stack();
      output('\n',1);
      output('\n',1);
      }
   text_out = 0;
   end_of_par = 0;
   (void)RTFSetClassCallback(rtfText, start_para);
}
/*****************************************************************************
 *
 * Force an update of the current state, only emitting commands
 * that actually change anything.
 */
static void
update_current()
{
   RTFStyle *style;

if (Cformatting_char)
{
   if(!CURRENT(char_attr.FontSize))
      set_fontsize(rtf_ptr->char_attr.FontSize);
   if(!CURRENT(char_attr.sub_super_height))
      set_subsuper(rtf_ptr->char_attr.sub_super_height);
   if(!CURRENT(char_attr.smallcaps))
      set_smallcaps();
   if(!CURRENT(char_attr.font))
   if(rtf_ptr->char_attr.font == Bold) {
	if (initialised)
	      set_font(Bold,1,"\n{\\bf ","}");
	else
	      set_font(Bold,1,"\n\\bf ","");
   }
   if(!CURRENT(char_attr.font))
   if(rtf_ptr->char_attr.font == Italic) {
	if (initialised)
	      set_font(Italic,1,"\n{\\it ","}");
	else
	      set_font(Italic,1,"\n\\it ","");
   }
}
if (Cformatting_para)
{
   if(!CURRENT(par_attr.flags))
	switch (rtf_ptr->par_attr.flags)
	  {
	  case Centred:
		output_str("\n\\begin{center}",'\0');
		push_LaTeX_stack("\n\\end{center}",Paragraph,0);
		break;
	  case RightAlign:
		output_str("\n\\begin{flushright}",'\0');
		push_LaTeX_stack("\n\\end{flushright}",Paragraph,0);
		break;
	  case LeftAlign:
		output_str("\n\\begin{flushleft}",'\0');
		push_LaTeX_stack("\n\\end{flushleft}",Paragraph,0);
		break;
	  default: 			    /* block modus (LaTeX default)*/
		break;
  }
   if(!CURRENT(par_attr.parindent))
	{
	if (rtf_ptr->par_attr.parindent==LaTeXdefault)
		sprintf(buff,"\n\\setlength{\\parindent}{\\defaultparindent}");
	else
		sprintf(buff,"\n\\setlength{\\parindent}{%gpt}",
			 TW_TO_PT(rtf_ptr->par_attr.parindent));
	output_str(buff,'\0');
	}
   if (!CURRENT(par_attr.skip_before) ||
       !CURRENT(par_attr.skip_after))
	{
	int skip;

	skip=rtf_ptr->par_attr.skip_after+rtf_ptr->par_attr.skip_before;
	sprintf(buff,"\n\\setlength{\\parskip}{%gpt}",
		 TW_TO_PT(skip));
	output_str(buff,'\0');
	}
   if((!CURRENT(par_attr.leftskip) || !CURRENT(par_attr.rightskip)) &&
       rl_skip_on)
	{
	if ((rtf_ptr->par_attr.leftskip!=0) ||
	    (rtf_ptr->par_attr.rightskip!=0) )
		{
		output_str("\n\\begin{list}",'\0');
		output_str("{ }{",'\0');
		sprintf(buff,"\n\\setlength{\\leftmargin}{%gpt}",
			 TW_TO_PT(rtf_ptr->par_attr.leftskip));
		output_str(buff,'\0');
		sprintf(buff,"\\setlength{\\rightmargin}{%gpt}",
			 TW_TO_PT(rtf_ptr->par_attr.rightskip));
		output_str(buff,'\0');
		output_str("\n\\setlength{\\topsep}{0pt}",'\0');
		output_str("\\setlength{\\partopsep}{0pt}",'\0');
		output_str("}\n\\item ",'\0');
		push_LaTeX_stack("\n\\end{list}",LRskip,0);
		}
	}

}
   rtf_current = *rtf_ptr;
   rtf_current.LaTeX_stack = NULL;
   rtf_current.prev = NULL;
}
/*****************************************************************************
 *
 * ALLDONE
 */

#define SET_FONT(FONT,START,END)	/* set a Font */\
  if(text_out && initialised) { \
     set_font(FONT,(rtfParam == 0 ? 0 : 1),START,END); \
  } \
  rtf_ptr->char_attr.font = (rtfParam == 0 ? 0 : FONT);
#define SET_FONTSIZE(FONTSIZE)	/* set a Fontsize */\
  if(text_out && initialised) { \
     set_fontsize(FONTSIZE); \
  } \
  rtf_ptr->char_attr.FontSize = FONTSIZE;


static void
CharAttr()
{
   switch (rtfMinor) {
    case rtfPlain:
      if(text_out) {
         while(top_LaTeX_flags(Underline) || top_LaTeX_flags(Sub_Super)
	    || top_LaTeX_flags(Font) || top_LaTeX_flags(Font_Num))
	    (void)pop_LaTeX_stack();
      }
      rtf_ptr->char_attr = rtf_default.char_attr;
      rtf_current.char_attr = rtf_default.char_attr;
      break;
    case rtfBold:
      SET_FONT(Bold,"\n{\\bf ","}");
      break;
    case rtfItalic:
      SET_FONT(Italic,"\n{\\it ","}");
      break;
    case rtfAllCaps:
       {
       static int count;
	 if(verbose > 1 || (verbose && count++ == 0)) {
		    msg_map_to("ac","sc");
		 }
       }
    case rtfSmallCaps:
     if(text_out && initialised)
	set_smallcaps();
     rtf_ptr->char_attr.smallcaps = 1;
      break;
    case rtfStrikeThru:
    case rtfOutline:
    case rtfShadow:
    case rtfInvisible:
      {
	 static int count = 0;
	 
	 if(verbose > 1 || (verbose && count == 0))
	   msg_not_supported(
			     rtfMinor == rtfStrikeThru ? "strike" :
			     rtfMinor == rtfOutline ? "outl" :
			     rtfMinor == rtfShadow ? "shad" :
			     rtfMinor == rtfInvisible ? "v" : "Unknown");
	 count++;
      }
      break;
    case rtfFontNum:
      break;
    case rtfFontSize:
      SET_FONTSIZE(rtfParam/2);
      break;
    case rtfDbUnderline:
    case rtfDUnderline:
      if (!noUnderline)
      {
	if (initialised)
	 {
	 output_str("\n\\underline{\\underline{",'\0');
	 push_LaTeX_stack("}}",Underline,0);
	 }
/*	else         doesn't work in LaTeX
	 {
	 output_str("\n\\underline \\bgroup \\underline \\bgroup",'\0');
	 push_LaTeX_stack("\\egroup \\egroup",Underline,0);
	 }
*/
	break;
      }
    case rtfUnderline:
    case rtfWUnderline:
      {
	 static int count = 0;
	 
	 if (!noUnderline)
	 {
	    if (initialised)
		{
		output_str("\n\\underline{",'\0');
		push_LaTeX_stack("}",Underline,0);
		}
/*	    else 	doesn't work in LaTeX
		{
		output_str("\n\\underline \\bgroup",'\0');
		push_LaTeX_stack("\\egroup",Underline,0);
		}
*/
	 }
	 else
	 {
		 if(verbose > 1 || (verbose && count++ == 0)) {
		    msg_map_to((rtfMinor == rtfUnderline ? "ul" : "ulw"),"i");
		 }
		rtfMinor = rtfItalic;
		CharAttr();
	 }
      }
      break;
    case rtfNoUnderline:
      break;
    case rtfSubScript:
    case rtfSuperScript:
      if(rtf_ptr->char_attr.sub_super_height == rtfParam) break;
      if(!text_out && initialised) start_para();
  if(text_out && initialised) {
     set_subsuper(rtfParam);
  }
  rtf_ptr->char_attr.sub_super_height = rtfParam;
  break;
    case rtfForeColor:
      msg_not_supported("cf");
      break;
    case rtfBackColor:
      break;
    case rtfExpand:
      msg_not_needed("expnd");
      break;
    case rtfRevised:
      break;
   }
}

/*****************************************************************************
 *
 * Various ways of refusing to deal with a keyword
 *
 *
 * Treat \from as \to (e.g. treat \ul as \i)
 */
static void
msg_map_to(from,to)
char *from, *to;
{
   if(verbose && !writing_defs) {
      fprintf(stderr,"I'm going to treat \\%s as \\%s\n",from,to);
   }
}
/*
 * Keyword is neither needed by LaTeX or supported by rtf2LaTeX
 * For example, \expnd to fiddle with inter-character spacing.
 */

static void
msg_not_needed(name)
char *name;
{
   if(verbose && !writing_defs) {
      fprintf(stderr,"\\%s is neither needed nor supported\n",name);
   }
}
/*
 * Keyword isn't supported, and probably can't be
 * For example, \cf to change colours
 */
static void
msg_not_supported(name)
char *name;
{
   static int pointer = 0;
   for (pointer=0;(name[pointer]!='\0' && isalpha(name[pointer]));pointer++)
      continue;
   /* Should fix problem writing to string constants with gcc */
   if(name[pointer] != '\0')
      name[pointer]='\0'; 		/*No argument will be printed*/
   if(verbose && !writing_defs) {
      fprintf(stderr,"%s: Don't support \\%s; sorry\n",progname,name);
   }
}
/*
 * Keyword will be supported, but I haven't done it yet
 */
static void
msg_not_yet(name)
char *name;
{
   if(verbose && !writing_defs) {
      fprintf(stderr,"%s: Don't support \\%s yet; be patient\n",progname,name);
   }
}




/*****************************************************************************
 *
 * Convert a string to a form that LaTeX can handle
 *
 * Remove spaces and capitalise the following letter, 
 * and converted digits to letters (1 --> A etc., 0 --> O)
 */
static char *
LaTeX_name(str)
char *str;
{
   static char temp[50];
   char *ptr;

   for(ptr = temp;*str != '\0';str++) {
      if(isspace(*str)) {
	 for(str++;isspace(*str);str++) continue;
	 if(*str == '\0') break;
	 *str = islower(*str) ? toupper(*str) : *str;
	 str--; continue;		/* reprocess the character */
      } else if(isdigit(*str)) {
	 if(*str == '0') *ptr++ = 'O';
	 else *ptr++ = *str + 'A' - '1';
      } else {
	 *ptr++ = *str;
      }
   }
   *ptr = '\0';

   return(temp);
}

/*****************************************************************************/

static void
usage()
{
   static char *msg[] = {
      "Your options are:",
      "       -c      No character formatting stuff",
      "       -C file Use another translation-file for characters above 128",
      "       -d      Use WORD formates within special WORD styles ",
      "               like heading, footnote text, ...",
      "       -H      Use LaTeX header and footer, not as default WORD header",
      "       -h      This message",
      "       -L file Use another translation-file for specilal WORD styles",
      "               like heading, footer, footnote text, ...",
      "       -n      Use \\hfill instead of \\\\ for making a new line",
      "       -p      No paragraph formatting stuff",
      "       -r      No left or right skip",
      "       -s      No tab stops",
      "       -t      No formatting in tables",
      "       -T f    Decrease-factor for the cell-width (default:0.7)",
      "       -u      Change underline to italic",
      "       -v[#]   Turn on verbose messages; the higher #, the more messages",
      "       -V      Print the version number",
      "If you omit the filename rtf2LaTeX will read standard input.",
      "\nIf there are any LaTeX errors or warnings,",
      "have a look in the man page section troubleshooting.\n ",
      NULL,
   };

   fprintf(stderr, "Usage: %s [options] [RTF-file]\n", progname);
   print_text(msg,stderr);
}

/*****************************************************************************
 *
 * print some text MSG to a stream FIL
 */
static void
print_text(msg,fil)
char *msg[];
FILE *fil;
{
   char **line;

   for(line = msg;*line != NULL;line++) {
      fprintf(fil,"%s\n",*line);
   }
}

/*****************************************************************************
 *
 * set a Font
 */
static void
set_font(font,turn_on,start,end)
int font;				/* flag for font to set (e.g. Bold) */
int turn_on;				/* should I start the font or end it?*/
char *end;				/* strings to start and */
char *start;				/* end the group that sets the font */
{
   if(turn_on && Cformatting_char) {
	 if(!no_grouping) {
	    push_LaTeX_stack(end,Font,font);
	 }
	 output_str(start,'\0');
   }
}

/*****************************************************************************
 *
 * change fontsize
 */
void set_fontsize(fontsize)
int fontsize;				/* size of fonts default 10 */
{
if (fontsize<0)
	{
	p6("set_fontsize\nfontsize<0");
	return;
	}
if (fontsize==0)
	{
	p6("set_fontsize\nfontsize==0");
	return;
	}
if (!Cformatting_char)
	{
	return;
	}
if (fontsize==8)
	{
	(void)RTFGetToken();
	if (strcmp(rtfTextBuf,"\\up6")==0)
		{
		RTFUngetToken();
		return;			/* mostly we are before a footnote here */
		}                       /* so we need no size-command, because */
	RTFUngetToken();                /* LaTeX deel in a good way with it */
	}
fputc('%',stdout);
output('\n',1);
if (initialised)			/* in newenvironment {} not necessary */
	{
	push_LaTeX_stack("}",Font,0);
	output_str("{",'\0');
	}
if (fontsize<5)
	{
	output_str("\\tiny ",'\0');
	return;
	}
if (fontsize<7)
	{
	output_str("\\scriptsize ",'\0');
	return;
	}
if (fontsize<9)
	{
	output_str("\\small ",'\0');
	return;
	}
if (fontsize<11)
	{
	output_str("\\normalsize ",'\0');
	return;
	}
if (fontsize<13)
	{
	output_str("\\large ",'\0');
	return;
	}
if (fontsize<17)
	{
	output_str("\\Large ",'\0');
	return;
	}
if (fontsize<21)
	{
	output_str("\\LARGE ",'\0');
	return;
	}
if (fontsize<25)
	{
	output_str("\\huge ",'\0');
	return;
	}
output_str("\\Huge ",'\0');
}


/*****************************************************************************
 *
 * set higher or lower text
 */

static void
set_subsuper(param)
int param;
{
      if(param == 0)
	 {		/* end of a sub/superscript */
	 while(!top_LaTeX_flags(Sub_Super))
	    {
	    if(pop_LaTeX_stack() == 0)
	       {
	       if(verbose)
		  {
		  fprintf(stderr,"%s: Failed to find end of sub/superscript\n",
		    progname);
		  }
	       return;
	       }
	     }
	 pop_LaTeX_stack();		/* pop off the '}' */
	 if(top_LaTeX_flags(Math)) pop_LaTeX_stack(); /* and pop math too */
	 return;
	 }
      if (rtfMinor == rtfSuperScript)
	      {
	      (void)RTFGetToken();
	      if (strcmp(rtfTextBuf,"\\chftn")==0)
		 return; 		/* we are before a footnote here */
	      RTFUngetToken();		/* so we need no command, because */
	      } 			/* LaTeX deels with it in a good way */
      output_str("$",'\0');
      push_LaTeX_stack("$",Sub_Super,1);
      if (initialised)
	      {
	      output_str(rtfMinor == rtfSuperScript ? "^{" : "_{",'\0');
	      push_LaTeX_stack("}",Sub_Super,rtfParam);
	      }
      else
	      {
	      output_str(rtfMinor == rtfSuperScript ? "^" : "_",'\0');
	      output_str(" \\bgroup",'\0');
	      push_LaTeX_stack(" \\egroup",Sub_Super,rtfParam);
	      }
}
/*****************************************************************************
 *
 * set smallcaps
 */

static void
set_smallcaps()
{
fputc('%',stdout);
output('\n',1);
if (initialised)
      {
      output_str("{",'\0');
      push_LaTeX_stack("}",Font,0);
      }
output_str("\\sc ",'\0');
}

/*****************************************************************************
 *
 * Print a string, ensuring that we are in math mode at the time
 */
static void
in_math(str)
char *str;
{
      output('$',0);
      output_str(str,'\0');
      output('$',0);
}

/*****************************************************************************
 *
 * Write a character, filling the the output text as we go. Characters
 * special to LaTeX are treated appropriately.
 */
#define FILL_COLUMN 60			/* column to fill to */
#define MAX_COLUMN 80			/* max of column*/
static int column=0;			/* current column */
static void
output(c,quote)
int c;					/* The char to print */
int quote;				/* quote LaTeX's special chars? */
{
   char temp[25];
   c &= '\377';				/* prevent sign extension */
   
   if(isspace(c))
      {
      if(c == '\n')
	{
	fputc('\n',stdout);
	column=0;
	}
      else
	{
	fputc(' ',stdout);
	column++;
	if (column>FILL_COLUMN)
		{
		fputc('\n',stdout);
		column=0;
		}
	}
      return;
      }

   if(quote) {
      switch (rtf_ptr->char_attr.FontType) {
       case rtfFFTech:			/* A technical font */
	 {
	    char *str;
	    
	    str = (c < 128) ? symbol[c] : symbol8[c & '\177'];
	    if(*str == '\0') {
	       /* if(verbose) { */
		  fprintf(stderr,"%s: Unknown Tech character: 0x%x\n",
		    progname,c);
	       /* } */
	    }
	    if(verbose) {
		  fprintf(stderr,"A Tech character: 0x%x\n",c);
	    }
	    in_math(str);
	 }
	 return;
       default:
	 switch (c)
	  {			/* deal with various characters */
	  case '%': case '$':
	  case '#': case '&':
	  case '_':
	    fputc('\\',stdout);
	    column++;
	    break;
	  case '^':
	    output_str("$^{\\wedge}$",'\0');
	    return;
	  case '"':
	    if(translate_quotes)
		c = (quotecount++ % 2) ? '\'' : '`';
	    else
		c = '`';
	    fputc(german_dquotes ? '"' : c, stdout);
	    column++;
	    break;
	  case '<': case '>':
	  case '|':
	    sprintf(temp,"%c",c);
	    in_math(temp);
	    return;
	  case '{': case '}':
	    sprintf(temp,"\\%c",c);
	    in_math(temp);
	    return;
	  case '\\':	 
	    in_math("\\backslash");
	    return;
	  case '~':
	    in_math("\\sim");
	    c = ' ';
	    return;
	  default:
	    if(!isascii(c))
	       {
	       output_8bit(c);
	       return;
	       }
	    if(!isalnum(c) && !ispunct(c))
	       {
	       if (verbose)
		  fprintf(stderr,"%s: Unknown 7-bit character: 0x%x\n",
		     progname,c);
	       return;
	       }
	    break;
	 }
      }
   }
fputc(c,stdout);
column++;
}
/*****************************************************************************
 *
 * Output an entire word, without trying to quote any special characters.
 * The character C is then output using output(), which allows proper page
 * breaks.
 */

static void
output_str(str,c)
char *str;
int c;
{
int len = strlen(str);
int zeiger=0;
if(c != '\0')
      {
      output(c,1);
      }
if (column==0 && str[0]=='\n')
      str++;
if (str[0]=='\n')
	fputc('%',stdout);
fprintf(stdout,"%s",str);
column+=len;
if (str[0] =='\n')
	column=len;
if (str[len-1] == '\n')
	column=0;
}

/*****************************************************************************
 *
 * Deal with special characters above \177.
 */


typedef struct Char8bit
{
int nr;					/* RTF-code */
char *str;                        	/* LaTeX command  */
struct Char8bit *next;
}char8;
 char8 *list_8bit;			/* begin of the 8bit list */
 char8 *help;


/*****************************************************************************
 *
 *   write a 8bit character
 */

static void
output_8bit(c)
int c;
{
   char *str;

help=list_8bit;
while(help->nr!=c && help->next!=NULL)		/* search for the character*/
	help=help->next;
if (help->nr==c)
      {
      output_str(help->str,'\0');            /* and write it */
      }
else
      {                                        /* character not found */
      if(verbose)
	 {
	 static count=0;
	 fprintf(stderr,"%s: Unknown 8-bit character: 0x%x\n",progname,c);
	 if (count++<1||verbose>1)
		fprintf(stderr,"   Have a look in the file .cod\n");
	 }
      }
}
/*****************************************************************************
 *
 *   read the file mac.code (or an other file e.g. ansi.code: use flag -C) 
 *   and store the commands for characters with the 8bit set in the list
 *   "list_8bit"
 */


static void
read_code_file(codefile)
char *codefile;
{

char line[line_length];
int pos;

open_code_file(codefile);
if (fgets(line,line_length,fpcode)==NULL)
	{
	fprintf(stderr,"\n%s: Incorrect file a8bit    \
			\nat first there must be a number of the ascii character with msb set  \
			\n(between 128 and 255)\n",progname);
	exit(1);
	}
	for (pos=23;line[pos]==' ';pos--);
	line[pos+1]='\0';			/* cut the comment in the file*/
	list_8bit=(struct Char8bit *)malloc((int)sizeof(struct Char8bit));
	if (list_8bit==(struct Char8bit *)NULL)
		{
		fprintf(stderr,"%s: TCErr - cannot allocate a 8bit-character name\n", progname);
		exit(1);
                }
	sscanf(line,"%d",&(list_8bit->nr));
	list_8bit->str=StrSave(line+4);
	if (list_8bit->nr<128 || list_8bit->nr>255)
		{
		fprintf(stderr,"\n%s: Incorrect file a8bit  \
				\nat first there must be a number of the ascii character with msb set  \
				\n(between 128 and 255)\n", progname);
		exit(1);
		}
	list_8bit->next=NULL;
while (fgets(line,line_length,fpcode)!=NULL)
	{
	for (pos=23;line[pos]==' ';pos--);
	line[pos+1]='\0';
	help=(struct Char8bit *)malloc((int)sizeof(struct Char8bit));
	if (help==(struct Char8bit *)NULL)
		{
		fprintf(stderr,"%s: SSErr - cannot allocate a 8bit-character name\n", progname);
		exit(1);
                }
	help->next=list_8bit;
	list_8bit=help;
	sscanf(line,"%d",&(list_8bit->nr));
	list_8bit->str=StrSave(line+4);
	if (list_8bit->nr<128 || list_8bit->nr>255)
		{
		fprintf(stderr,"\n%s: Incorrect file a8bit  \
				\nat first there must be a number of the ascii character with msb set  \
				\n(between 128 and 255)\n", progname);
		exit(1);
                }
	}
if (fpcode!=NULL) fclose(fpcode);
}


/*****************************************************************************
 *
 * write an errormassage to stderr
 *
 */
static void
p6(proc_name)
char *proc_name;	/*name of ther procedure where the mistake must be */
{
     fprintf(stderr," %s: Problem in procedure %s\n",progname,proc_name);
     fprintf(stderr,"           please call Erwin Wechtl\n");
     fprintf(stderr,"                       W""ortgasse 2/18\n");
     fprintf(stderr,"                       A-2500 Baden\n");
     fprintf(stderr,"                       Austria\n");
     fprintf(stderr,"                       Tel.: 43/2252/44686\n");
}

/*****************************************************************************
 *
 * set end af table
 */

static void
end_table()
{
	table_mode=0;
	if (top_LaTeX_flags(Tabular))
		{
		Cformatting_char=formatting_char;
		Cformatting_para=formatting_para;
		pop_LaTeX_stack();
		tabinitold[0]='\0';
		output_str("\n  \n",'\0');
		}
}


/*****************************************************************************
 *
 *  translate each RTF-style into a new LaTeX environment
 *  and look for special WORD styles like heading (tranlated into section)
 *  or footer (ignored)
 */
LATEXStyle *LaTeXstyleList;		/* we can't use the RTFstylelist
					   because we need more variables */

void DefineStyles()
{
RTFStyle   *rtfstyle;			/* the style to deel with */
LATEXStyle *LaTeXstyle;			/* the style to deel with */

output_str("\n \n",'\0');
LaTeXstyleList=(LATEXStyle *)NULL;
for(rtfstyle=RTFGetStyle(-1);rtfstyle!=(RTFStyle *)NULL;rtfstyle=rtfstyle->rtfNextStyle)
   {
   LaTeXstyle=(LATEXStyle *)malloc(sizeof(struct LATEXStyle));
   if (LaTeXstyle==NULL)
	{
	fprintf(stderr,"\n%s: Can't alloc LaTeXstyle\n",progname);
	exit(1);
	}
   LaTeXstyle->stacktype=Undefined;
   LaTeXstyle->BeginCommand[0] = LaTeXstyle->EndCommand[0] = '\0';
   LaTeXstyle->special_WinwordStyle=TRUE;
   if (!is_specialWORDstyle(rtfstyle,LaTeXstyle))      /* looking for special styles */
	{
	char commandbuf[80];
	RTF_STACK rtf_save;

	push_rtf_group();
	rtf_save = rtf_current;
	LaTeXstyle->special_WinwordStyle=FALSE;
	LaTeX_name(rtfstyle->rtfSName);
	strcpy(commandbuf,"\n\\");
	strcat(commandbuf,"begin{");
	strcat(commandbuf,rtfstyle->rtfSName);
	strcat(commandbuf,"}\n");
	strcpy(LaTeXstyle->BeginCommand,commandbuf);
	strcpy(commandbuf,"\n\\");
	strcat(commandbuf,"end{");
	strcat(commandbuf,rtfstyle->rtfSName);
	strcat(commandbuf,"}\n");
	strcpy(LaTeXstyle->EndCommand,commandbuf);

	output_str("\n% definition of ",'\0');
	output_str(rtfstyle->rtfSName,'\0');
	output_str("\n\\newenvironment{",'\0');
	output_str(rtfstyle->rtfSName,'\0');
	output_str("}{",'\0');

	RTFExpandStyle(rtfstyle->rtfSNum);
	LaTeXstyle->char_attr=rtf_ptr->char_attr;
	LaTeXstyle->par_attr=rtf_ptr->par_attr;
	LaTeXstyle->stacktype=NormalWORDstyle;
	update_current();
	output_str("}{",'\0');
	while(pop_LaTeX_stack()) continue;
	output_str("}\n",'\0');

	rtf_current = rtf_save;
	pop_rtf_group();
	}
  LaTeXstyle->rtfSNum=rtfstyle->rtfSNum;
  LaTeXstyle->rtfSName=rtfstyle->rtfSName;
  LaTeXstyle->LaTeXNextStyle=LaTeXstyleList;
  LaTeXstyleList=LaTeXstyle;
   }
if (fpland!=NULL) fclose(fpland);
}

/*****************************************************************************
 *
 *   begin a style environment
 */


void setstylecommand(n)
int	n;			/* rtfStyleNumber */
{
LATEXStyle	*LaTeXstyle;
RTFStyle        *rtfstyle;
char buf[80];

	if(!table_mode && top_LaTeX_flags(Tabular))
		end_table();
	LaTeXstyle=LaTeXstyleList;
	while (LaTeXstyle!=NULL && LaTeXstyle->rtfSNum!=n) LaTeXstyle=LaTeXstyle->LaTeXNextStyle;
	if (LaTeXstyle==NULL)
		{
		static int count=0;

		rtfstyle=RTFGetStyle(n);
		if (verbose>1 || (verbose && count++==0))
			{
			fprintf(stderr,"%s: There are some troubles with the style %s with the number %d, \n  so this style is ignored\n",
			    progname,rtfstyle->rtfSName,n);
			}
# ifdef notdef /* Don't know if this is needed anymore */
/*		sprintf(buf,"\n%% The Style %s with the number %d may begin here\n",rtfstyle->rtfSName,n);
		output_str(buf,'\0');
		output_str("%%But rtf2LaTeX has had some troubles with it",'\0');
		sprintf(buf,"\n%  The Style %s with the number %d may end here\n",rtfstyle->rtfSName,n);
		push_LaTeX_stack(buf,NormalWORDstyle,0);
*/
# endif /* notdef */
		return;
		}
	if (LaTeXstyle->special_WinwordStyle)	/* if heading,footer, ... */
		{       /* use paragraph(character) formating only
			   if the flag -d is on             */
		Cformatting_para=formatting_sWORD&&formatting_para;
		Cformatting_char=formatting_sWORD&&formatting_char;
		}
	else
		{
		update_current();	/* format */
		rtf_current.par_attr=LaTeXstyle->par_attr;
		rtf_current.char_attr=LaTeXstyle->char_attr;
		rtf_ptr->par_attr=LaTeXstyle->par_attr;
		rtf_ptr->char_attr=LaTeXstyle->char_attr;
		rtf_current.LaTeX_stack = NULL;
		rtf_current.prev = NULL;
		}
	output_str(LaTeXstyle->BeginCommand,'\0');
	push_LaTeX_stack(LaTeXstyle->EndCommand,LaTeXstyle->stacktype,0);
}

/*****************************************************************************
 *
 *  look in the file english.land (or an other file e.g. german.land:
 *  use flag -L) 
 *  if this is a Spezial WORD style like heading, footer, ...
 */


int
is_specialWORDstyle(rtfstyle,LaTeXstyle)
RTFStyle	*rtfstyle;
LATEXStyle	*LaTeXstyle;

{
char line[line_length];                         /* the line which is read from the file */

if (formatting_sWORD)				/* if flag -d is on */
	return(0);				/* use WORD formate instead of LaTeX formate within header, ... */
fseek(fpland, 0, SEEK_SET);
while (fgets(line,line_length,fpland)!=NULL)
	{
	if (strncmp(rtfstyle->rtfSName,line,strlen(rtfstyle->rtfSName))==0)
		{
		LaTeXstyle->stacktype=SpecialWORDstyle;
		if (strncmp(line+20,"           ",10)!=0)
			sscanf(line+20,"%20s%20s",LaTeXstyle->BeginCommand,LaTeXstyle->EndCommand);
		else
			LaTeXstyle->BeginCommand[0] = LaTeXstyle->EndCommand[0] = '\0';
		output_str("% ",'\0');
		output_str(line+60,'\0');
		return(1);
		}
	}
return(0);
}

/*****************************************************************************
 *
 *   malloc for a string
 */


static char *StrSave (s)
char	*s;
{
char	*p;

	if ((p = (char *)malloc (strlen (s) + 1)) == (char *) NULL)
		fprintf(stderr,"%s: Error in malloc\n",progname);
	return (strcpy (p, s));
}


/*****************************************************************************
 *
 *   set the position of the Tabstops and output the begin environment
 */


static void
start_tabstops()
{
   int i,j;
   int width;				/* width of table entry (twips) */
   char buf[1];

   if (top_LaTeX_flags(SpecialWORDstyle)) 
	return;   			/* no tab stops in header, heading, ...*/
   Cformatting_char=formatting_char&&formatting_table;
   Cformatting_para=formatting_para&&formatting_table;
   output_str("\n\\begin{tabbing}\n",'\0');
   for(i = 0;i < NTABS;i++)
      {
      width = tabstops[i].pos;
      if(i > 0)
	width -= tabstops[i - 1].pos;
      width=TW_TO_CA(width);
      if (width<1)
	continue;
      for(j=1;j<=width;j++)
	{
	sprintf(buf,"%d",(j % 10));
	output_str(buf,'\0');
	}
      output_str("\\=",'\0');
      }
   output_str("\\kill\n",'\0');
   push_LaTeX_stack("\\end{tabbing}\n",Tabstops,0);
   tabstopsInit();
   tab=2;
}

/*****************************************************************************
 *
 *   initialise the array of the Tabstops-positions
 */

static void
tabstopsInit()
{
int i;

for (i=0;i<NTABS;i++)
	{
	tabstops[i].pos=CA_TO_TW(i*defaultTabWidth);
	tabstops[i].type=0;
	}
	ntabs=0;
}

/*****************************************************************************
 *
 * Stack stuff -- RTF and LaTeX grouping go on separate stacks
 *
 * pop the status stack, putting the free'd element on the free list
 */
static RTF_STACK *rtf_free_list = NULL;
static void
pop_rtf_group()
{
   RTF_STACK *temp;
   
   if(rtf_ptr->prev == NULL) {
      fprintf(stderr,"%s: Attempt to pop an empty stack\n", progname);
      abort();
   }
   temp = rtf_ptr->prev;
   rtf_ptr->prev = rtf_free_list;
   rtf_free_list = rtf_ptr;
   rtf_ptr = temp;
}
/*
 * push the RTF status stack
 */
static void
push_rtf_group()
{
   RTF_STACK *temp;
   
   if(rtf_free_list != NULL) {
      temp = rtf_free_list;
      rtf_free_list = rtf_free_list->prev;
   } else {
      if((temp = (RTF_STACK *)malloc(sizeof(RTF_STACK))) == NULL) {
	 fprintf(stderr,"%s: Can't allocate storage for stack\n",progname);
	 exit(1);
      }
   }
   memcpy((char *)temp,(char *)rtf_ptr,sizeof(RTF_STACK));
   temp->prev = rtf_ptr;
   rtf_ptr = temp;
   rtf_ptr->LaTeX_stack = NULL;
}
/*****************************************************************************
 *
 * Now the LaTeX stacks. Use the stack in the current rtf_ptr frame
 */
static LATEX_STACK *myTeX_free_list = NULL;
static int
pop_LaTeX_stack()
{
   char *str;
   LATEX_STACK *temp;
   
   if(rtf_ptr->LaTeX_stack == NULL) {
      return(0);
   }
   if (rtf_ptr->LaTeX_stack->type == SpecialWORDstyle)
	{					/* reset formatting      */
	Cformatting_para =formatting_para;	/* after heading, footer, .. */
	Cformatting_char=formatting_char;
	}
   LaTeX_group--;
   str = rtf_ptr->LaTeX_stack->str;
   temp = rtf_ptr->LaTeX_stack->prev;
   rtf_ptr->LaTeX_stack->prev = myTeX_free_list;
   myTeX_free_list = rtf_ptr->LaTeX_stack;
   rtf_ptr->LaTeX_stack = temp;
   output_str(myTeX_free_list->str,'\0');
   return(1);
}
/*
 * push the string STR onto the LaTeX stack, with attributes TYPE and FLAGS
 */
static void
push_LaTeX_stack(str,type,flags)
char *str;				/* string to save */
int type;				/* type of string */
long flags;				/* and corresponding flags */
{
   LATEX_STACK *temp;
   LaTeX_group++;
   if(myTeX_free_list != NULL) {
      temp = myTeX_free_list;
      myTeX_free_list = myTeX_free_list->prev;
   } else {
      if((temp = (LATEX_STACK *)malloc(sizeof(LATEX_STACK))) == NULL) {
	 fprintf(stderr,"%s: Can't allocate storage for stack\n",progname);
	 exit(1);
      }
   }
   
   temp->prev = rtf_ptr->LaTeX_stack;
   rtf_ptr->LaTeX_stack = temp;
   rtf_ptr->LaTeX_stack->str = str;
   rtf_ptr->LaTeX_stack->type = type;
   rtf_ptr->LaTeX_stack->flags = flags;
   return;
}
/*****************************************************************************
 *
 * Return the flags of the proper type for the top element of the LaTeX stack
 */
static int
top_LaTeX_flags(type)
int type;
{
   return((rtf_ptr->LaTeX_stack != NULL && rtf_ptr->LaTeX_stack->type == type) ?
	  1 : 0);
}
/*****************************************************************************/


static void
open_code_file (codefile)
char *codefile;
{
      char *filename;
      char line[line_length];
      char c;
      if((filename = malloc(strlen(codefile) + strlen(RTFDIR) + 7)) == NULL)
      {
	fprintf(stderr,"%s: Error in malloc\n",progname);
	exit(3);
      }
      strcpy(filename,RTFDIR);
#if !defined (THINK_C)
      strcat(filename,"/");
#endif /* !THINK_C */
      strcat(filename,codefile);
      if ((strchr(codefile,'.')) == NULL)
      	strcat(filename,".code");
      if((fpcode = fopen(filename,"r")) == NULL)
	 {
	 fprintf(stderr,"%s: Can't open %s\n",progname,filename);
	 exit(1);
	 }
      free(filename);
      if (fgets(line,line_length,fpcode)==NULL)
	{
	fprintf(stderr,"\n%s: Incorrect file a8bit   \
			\nthere must be a comment in the first line\n",
			progname);
	exit(1);
	}
}
static void
open_land_file (landfile)
char *landfile;
{
      char *filename;
      if((filename = malloc(strlen(landfile) + strlen(RTFDIR) + 7)) == NULL)
      {
	fprintf(stderr,"%s: Error in malloc\n",progname);
	exit(3);
      }
      strcpy(filename,RTFDIR);
#if !defined (THINK_C)
      strcat(filename,"/");
#endif /* !THINK_C */
      strcat(filename,landfile);
      if ((strchr(landfile,'.')) == NULL)
      	strcat(filename,".land");
      if((fpland = fopen(filename,"r")) == NULL) {
	 fprintf(stderr,"%s: Can't open %s\n",progname,filename);
	 exit(1);
      }
      free(filename);
}
