[comp.lang.c] MS-word

schopfer@cui.unige.ch (SCHOPFER Olivier) (05/22/89)

word2mif 1.10

This is a new version of the microsoft Word IV (PC) to MIF (Maker Interchange
Format) filter, working correctly with footnotes in almost every case.

Please send comments, congratulations, bug reports to
                Olivier Schopfer
                3, rue des Moraines
                CH-1227 CAROUGE
                SWITZERLAND

Electronic mail:
                 schopfer@cgeuge51.bitnet
                 schopfer@uni2a.unige.ch
                 schopfer@uni2a.uucp

Cut here:
------------------------------------------------------------------------
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# Makefile README word2mif.c word2mif.data word4.h

echo x - Makefile
cat > "Makefile" << '//E*O*F Makefile//'
word2mif : word2mif.c word4.h word2mif.data
	cc -o word2mif word2mif.c -s

//E*O*F Makefile//

echo x - README
cat > "README" << '//E*O*F README//'
	@(#)README	1.2 5/19/89

Filter to convert word processor files from Microsoft Word 4.0
to Framemaker "MIF" (Maker Interchange Format)

Files in this package:

    README		This file
    Makefile
    word2mif.c		Source file
    word4.h		Definition of MS-Word IV files data structures
    word2mif.data	Character translation table (IBM-PC -> SUN)

Calling sequence:

un1sun1% word2mif input_file word2mif.data [-l] > output_file.mif

word2mif.data is a data file containing the character translation information

If there is a style sheet, it's supposed to be on the same directory than
the input_file. The name of the style sheet is specified in the main
text file, so you don't have to specify it. It has to be in lowercase.
 
Footnotes are handled by creating a variable size anchored frame that you
will will probably have to adjust. There might be problems if you have too many big 
footnotes, because Frame sometimes doesn't handle them correctly.

The -l option puts footnotes after the last page of the document.

Hidden text fields are treated as normal text. A marker is inserted at
the beginning and at the end of the section.

The page format defaults to A4.


THIS PROGRAM IS NOT FOR COMMERCIAL USE.

Please send bug reports to:


	Olivier Schopfer, 
        Faculty of theology,
	University of Geneva, Switzerland

Electronic mail:
	schopfer@divsun.unige.ch
	schopfer@cui.uucp
	schopfer@cgeuge51.BITNET


//E*O*F README//

echo x - word2mif.c
cat > "word2mif.c" << '//E*O*F word2mif.c//'
/* 
	@(#)word2mif.c	1.10 1.10

Olivier Schopfer, University of Geneva, Switzerland
schopfer@cui.uucp
schopfer@cgeuge51.BITNET

Filter to convert word processor files from Microsoft Word 4.0
to Framemaker "MIF" (Maker Interchange Format)

Calling sequence:

un1sun1% word2mif input_file word2mif.data [-l] > output_file.mif

word2mif.data is a data file containing the character translation information

If there is a style sheet, it's supposed to be on the same directory than
the input_file.  The name of the style sheet is specified in the main
text file, so you don't have to specify it. It has to be in lowercase. 
  
Footnotes are handled by creating a fixed size anchored frame that you 
will have to adjust. There might be problems if you have too many big  
footnotes, because Frame sometimes doesn't handle them correctly. 

Options:
    -l : Footnotes go to last page instead of page footer.
 
Hidden text fields are treated as normal text. A marker is inserted at
the beginning and at the end of the section.
 
The page format defaults to A4. 
 
 
THIS PROGRAM IS NOT FOR COMMERCIAL USE. 

*/

#include <ctype.h>
#include <stdio.h>
#include <sys/file.h>
#include "word4.h"

#define STRING_LENGTH 80

struct Header header,			/* File header */
              s_header;			/* Style sheet header */

char *text_array;			/* The text itself */
Uint	text_array_size;		/* # of text bytes */

struct Page 	*CharPage, *ParPage, 
		*SecTablePage, *SecPage;	/* Pointers to format info pages */

Uint	CharPageNb, ParPageNb, FntbPageNb, 	/* Number of pages */
	SecTablePageNb, SecPageNb;

/* Style sheet data */

struct Page 	*s_CharPage, *s_ParPage, 
		*s_SecTablePage, *s_SecPage;	/* Pointers to format info pages */

Uint	s_CharPageNb, s_ParPageNb, s_FntbPageNb, 	/* Number of pages */
	s_SecTablePageNb, s_SecPageNb,

/* End of style sheet data */

        last_text_byte;                     /* Offset of last real text byte 
                                               (Except footnotes) */

struct FOD_ptr                            /* Internal structure for FOD's pointers */
  { Uint i_page,    /* Page number of FOD */
         i_FOD,     /* FOD number inside current page */
         fcLimit;     /* Byte after last one concerned with this FOD */
    char *PROP;     /* Pointer to CHP or PAP */
    char cch;	    /* Nb of defined bytes in CHP or PAP */
  };

struct FOD_ptr ch_FOD,       /* Current character FOD */
	       prev_ch_FOD,
               pa_FOD,       /* Current paragraph FOD */
               prev_pa_FOD;

struct STYLE_KEY
{  Uchar KEY[2];	/* Two letters style code */
   char  *PROP;		/* Pointer to pgf's font */
   char  cch;
};

struct STYLE_KEY *style_key;	/* Pointer to array of keys */

struct STYLE_PTR
  {
     char *PROP;	/* Pointer to CHP */
     char cch;		/* Nb of defined bytes in CHP */
  };

struct STYLE_PTR	styles[30];		/* Pointers to styled CHP's */

struct FormatPROP *FPROP;

struct PROPerty_of_CHaracter *Chp,		/* Pointer to Char Property */
				Current_CHP,	/* Current char. settings */
				s_Current_CHP,	/* Current char. settings (styled) */
				Default_CHP,	/* Default values */
				Temp_CHP;	/* Temporary storage */

struct PAragraphProperty *PAP,			/* Pointer to Paragraph Property */
			Current_PAP,		/* Current parag. settings */
			Default_PAP,		/* Default values */
			Temp_PAP;		/* Temporary storage */

struct TaBDescriptor *TBD;

struct FootNoteTaBle *FNTB;
struct FootNoteDescriptor *FND;
struct SEctionProperty *SEP;
struct SEctionTaBle *SETB;
struct SEctionDescriptor *SED;

char new_paragraph,		/* Boolean, to tell if we are at the beginning of */
	new_page,		/* a Paragraph (i.e. the last byte was the end */
				/*  of one)  */
     processing_notes,		/* Flag to tell if processing main text or notes */
     styled_flag,		/* Has a style sheet been read? */
     styled_paragraph,		/* Is current paragraph styled? */
     notes_on_last_page,	/* Footnotes are on last page */

     current_string[81];	/* String for output */
Uint string_ptr;		/* Index into array */

Uint Current_footnote = 1;          /* Number of current footnote */

/* Conversion table for characters */

char   *DataFileName;		/* Data filename */

Uchar char_def[256];        /* Char translation table */

/* Miscellaneous conversion functions */

short Short(var) /* PC 16 bits to 68000 16 bits conversion */

  PCshort var;
  
  { Ushort res;
    res = 0;
    res = (Ushort) ((var.byte[1]) << 8) | ((Ushort) var.byte[0]) ;
    return(res);
  }

unsigned int Int(var)  /* PC 32 bits to 68000 32 bits conversion */

  PCint var;

  { unsigned int res;
    res = ((Uint)(Ushort)Short(var.word[1]) <<16 ) | ((Uint)(Ushort)Short(var.word[0])) ;
    return(res);
  }

unsigned long Long(var)  /* 64 bits conversion */

  PClong var;

  { unsigned int res;
    res = ((Ulong)Int(var.lword[0]) << 32) | ((Ulong)Int(var.lword[1]));
    return(res);
  }

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

   Functions to handle formating properties
   ======================================== */



/* Set paragraph properties */

void Set_PAP(destPAP, srcPAP, defPAP, bytes_defined)

   struct PAragraphProperty
		 	*destPAP,	/* Destination */
			*srcPAP,	/* Source PAP */
			*defPAP;	/* Default PAP, for undef. bytes */

   Uchar		bytes_defined;	/* Number of defined bytes in srcPAP */

  { char *dest_ptr, *src_ptr, *def_ptr; /* Pointer to corresponding char arrays */
    int i;

    dest_ptr = (char *) destPAP;
    src_ptr = (char *) srcPAP;
    def_ptr = (char *) defPAP;

	/* Copy defined bytes from srcPAP, and others from defPAP */

    for (i=0; i<sizeof(struct PAragraphProperty); i++)
      if (i <  bytes_defined)
	dest_ptr[i] = src_ptr[i];
      else
        dest_ptr[i] = def_ptr[i];
    return;
  }

/* Set character properties */
 
void Set_CHP(destCHP, srcCHP, defCHP, bytes_defined)
 
   struct PROPerty_of_CHaracter
                        *destCHP,       /* Destination */
                        *srcCHP,        /* Source CHP */
                        *defCHP;        /* Default CHP, for undef. bytes */
 
   Uchar                bytes_defined;  /* Number of defined bytes in srcCHP */
 
  { char *dest_ptr, *src_ptr, *def_ptr; /* Pointer to corresponding char arrays */
    int i;
 
    dest_ptr = (char *) destCHP;
    src_ptr = (char *) srcCHP;
    def_ptr = (char *) defCHP;
 
        /* Copy defined bytes from srcCHP, and others from defCHP */
 
    for (i=0; i<sizeof(struct PROPerty_of_CHaracter); i++)
      if (i < bytes_defined)
        dest_ptr[i] = src_ptr[i];
      else
        dest_ptr[i] = def_ptr[i];

    /* If character is styled, copy styled char data instead of standard data */

    if (destCHP->word00.fStyled && styled_flag)
      Set_CHP(destCHP, styles[destCHP->word00.stc].PROP, defCHP,
              styles[destCHP->word00.stc].cch);		/* Recursive call */

    return;
  }

/* Convert char if it's a normal font */
Uchar char_conv(carac)

  Uchar carac;
 
  {
    if (Current_CHP.word00.ftc < 50)  /* Font code 50 is hebrew */
      return(char_def[carac]);
    else
      return(carac);
  }

 
/* *************************************************************
   Function to set FOD pointer arguments to descr
   prev_descr gets the old values                               */

void set_FOD(page, descr, prev_descr)

  struct Page	 *page;  /* Formatting information page (CharPage or ParPage) */
  struct FOD_ptr *descr,  /* pointer to current format descriptor to be set */
                 *prev_descr; /* old value of descr */

  {
    struct FOrmatDescriptor *FOD;

    prev_descr->i_page = descr->i_page;
    prev_descr->i_FOD  = descr->i_FOD;
    prev_descr->fcLimit  = descr->fcLimit;
    prev_descr->PROP   = descr->PROP;
    prev_descr->cch    = descr->cch;

    FOD = (struct FOrmatDescriptor *)
      &page[descr->i_page].FODs[descr->i_FOD  * sizeof(struct FOrmatDescriptor)];

    descr->fcLimit = Int(FOD->fcLim);

    if (((Ushort)Short(FOD->bfprop)) != 0xFFFF)      /* Property defined? */
    {
      FPROP =  (struct FormatPROP *)
                &page[descr->i_page].FODs[(Ushort)Short(FOD->bfprop)];

      descr->cch = FPROP->cch;

      descr->PROP = (char *)
                    &page[descr->i_page].FODs[((Ushort)Short(FOD->bfprop)+1)];
    }
    else
    {
      descr->cch = 0;
      descr->PROP = (char *) NULL;
    }
    return;
  }



/* Find FOD associated with offset, into specified formatting page,
   set descr to point the Format descriptor, prev_descr the last descriptor 
   Returns 0 if format didn't change, 1 if it did */

int find_FOD(page, offset, descr, prev_descr, pageNb)

   struct Page	*page;		/* Pointer to formatting info page */
   Uint		offset; 	/* current offset into file */
   struct FOD_ptr *descr,	/* Descriptor of current FOD */
        	*prev_descr;	/* Last descriptor */
   Uint		pageNb;		/* Number of available pages */

  {
    if (descr->fcLimit == 127)
      set_FOD(page, descr, prev_descr); /* Force reading of 1st FOD */

    if (offset == descr->fcLimit)    /* Right at beginning of new section */
    {
      if (page[descr->i_page].cfod <= (descr->i_FOD + 1))
      {
        if (descr->i_page+1 >= pageNb)  /* Thers is no more FOD */
        {
          descr->PROP=(char *) NULL;
          descr->cch =0;
          descr->fcLimit = offset+1;
          return(0);
        }

        descr->i_page++;
        descr->i_FOD = 0;      /* Beginning of a new page */
      }
      else
        descr->i_FOD++;        /* Skip to next FOD in the same page */

      set_FOD(page, descr, prev_descr);
      return(1);
    }
    else     /* offset <> fcLim */
    {
      if (prev_descr->fcLimit <= offset && offset < descr->fcLimit)
      {
        if (prev_descr->fcLimit == 127) /* First section */
        {
          prev_descr->fcLimit = 0;
          return(1);
        }
        else
          return(0);                           /* prev_lim <= offset < lim */
      }

      if (offset < descr->fcLimit)
      {
        /* offset < prev_lim < lim */

        descr->i_page=0;
        descr->i_FOD=0;
        descr->fcLimit=0;
        descr->cch = 0;
        descr->PROP = (char *) NULL;
  
        set_FOD(page, descr, prev_descr);
      }

      while ((prev_descr->fcLimit) < offset)
      {
        if (page[descr->i_page].cfod <= (descr->i_FOD + 1)) 
        {  
          if (descr->i_page+1 >= pageNb)  /* Thers is no more FOD */
          {
            descr->PROP=(char *) NULL;
            descr->cch =0;
            descr->fcLimit = offset+1;
            return(0);
          }

          descr->i_page++; 
          descr->i_FOD = 0;      /* Beginning of a new page */ 
        } 
        else 
          descr->i_FOD++;        /* Skip to next FOD in the same page */ 
 
        set_FOD(page, descr, prev_descr);
      }
      return(1);
    }
  }

/* Initialisation
   ************** */
 
void init_defaults()
 
  {  char *ptr;
    int n;    
    
    /* Paragraphe par defaut */
 
    ptr = (char *) &Default_PAP;
    for (n=0; n<sizeof(struct PAragraphProperty); n++)
      ptr[n]=0;                          /* Every default value are zeroes */

    ptr[0]=61;
    ptr[2]=30; 
    ptr[10]=240;
 
    Set_PAP(&Current_PAP, &Default_PAP, NULL, sizeof(struct PAragraphProperty));
 
    /* Charactere par defaut */
 
    ptr = (char *) &Default_CHP;
    for (n=0; n<sizeof(struct PROPerty_of_CHaracter); n++)
      ptr[n]=0;                            /* Everything is zero except... */
    ptr[2]=24;
    Default_CHP.word00.ftc = 6;                 /* Default font is Times */
 
    Set_CHP(&Current_CHP, &Default_CHP, NULL, sizeof(struct PROPerty_of_CHaracter));

    /* Initialiser les pointeurs de formattage */
    ch_FOD.i_page=0;
    ch_FOD.i_FOD=0;
    ch_FOD.cch=0;
    ch_FOD.PROP=(char *) NULL;
    ch_FOD.fcLimit=127;            /* Force reading of FOD */
    prev_ch_FOD.fcLimit=0;

    pa_FOD.i_page=0;
    pa_FOD.i_FOD=0; 
    pa_FOD.cch=0;
    pa_FOD.PROP=(char *) NULL; 
    pa_FOD.fcLimit=127;            /* Force reading of FOD */
    prev_pa_FOD.fcLimit=0;

    string_ptr = 0;		/* Init string pointer */
 
  }

/* Ouput character data */

void output_CHP2(sourceCHP, currentCHP, explicit_flag)

  struct PROPerty_of_CHaracter
                *sourceCHP, *currentCHP;
   char                 explicit_flag;  /* If set, every value is printed */

  {
    if (explicit_flag || (sourceCHP->word00.ftc != currentCHP->word00.ftc))
    {
      printf(" <FFamily ");
      switch(sourceCHP->word00.ftc)
      { case 0:
        case 6: puts("Courier>"); break;
        case 8: puts("Helvetica>"); break;
        case 9: puts("AvantGarde>"); break;
        case 10: puts("HelveticaNarrow>"); break;
        case 16: puts("Bookman>"); break;
        case 24: puts("Times>"); break;
        case 25: puts("NewCenturySchlbk>"); break;
        case 26: puts("Palatino>"); break;
        case 50: puts("Hebrew>");   break;
        case 56: puts("Symbol>");   break;
        case 57: puts("LineDraw>"); break;
        case 58: puts("SuperGreek>"); break;
        case 59: puts("SSuperGreek>"); break;
        default: printf("Courier> # Font %u unknown, using default\n",
                         sourceCHP->word00.ftc); break;
      }
    }

    if (explicit_flag || (sourceCHP->word01.hps != currentCHP->word01.hps))
      printf (" <FSize %u>\n", sourceCHP->word01.hps / 2); 

    if (explicit_flag || (sourceCHP->hpsPos != currentCHP->hpsPos))
      printf (" <FDY %d>\n", -(((char)sourceCHP->hpsPos) / (char)2));

    if (explicit_flag || (sourceCHP->word00.fItalic != currentCHP->word00.fItalic))
    {
      printf(" <FItalic ");
      if (sourceCHP->word00.fItalic)
        puts("Yes>");
      else
        puts("No>");
    }

    if (explicit_flag || (sourceCHP->word00.fBold != currentCHP->word00.fBold))
    {
      printf(" <FBold ");
      if (sourceCHP->word00.fBold)
        puts("Yes>");
      else
        puts("No>");
    }

    if (explicit_flag || (sourceCHP->word01.fUline != currentCHP->word01.fUline)
         || (sourceCHP->word01.fDline != currentCHP->word01.fDline))
    {
      printf(" <FUnderline ");
      if ((sourceCHP->word01.fUline) || (sourceCHP->word01.fDline))
        puts("Yes>");
      else
        puts("No>");
    }

    if (explicit_flag || (sourceCHP->word01.fStrike != currentCHP->word01.fStrike))
    {
      printf(" <FStrike ");
      if (sourceCHP->word01.fStrike)
        puts("Yes>");
      else
        puts("No>");
    }

/* This entry has to be the last one... */
    if (sourceCHP->word01.fHidden != currentCHP->word01.fHidden)
    {
      printf("> # End of font\n");
      printf("<Marker\n  <MText `Hidden text ");
      if (sourceCHP->word01.fHidden)
        printf("begin'>\n  <MType 9>\n");
      else
        printf("end'>\n  <MType 10>\n");
    }
  }

/* Ouput Character properties */

void output_CHP(sourceCHP, currentCHP, explicit_flag)

  struct PROPerty_of_CHaracter
		*sourceCHP, *currentCHP;
   char                 explicit_flag;  /* If set, every value is printed */

  { int i, flag;
    char *s_ptr, *c_ptr;

    /* is there any difference? */

    flag = 0;
    s_ptr = (char *) sourceCHP;
    c_ptr = (char *) currentCHP;

    for (i=0; i<sizeof(struct PROPerty_of_CHaracter); i++)
      if (s_ptr[i] != c_ptr[i])
        flag++;
 
    if (!(explicit_flag) && flag == 0)
      return;                         /* Character format not changed */

    if (sourceCHP->word00.fStyled)	/* Should only appear if translation bad */
    {
      printf("# Styled Font nb %u\n", sourceCHP->word00.stc);
      return;
    }

    puts("<Font");

    output_CHP2(sourceCHP, currentCHP, explicit_flag);

    puts("> # End of Font or Marker");

  }

/* Ouput paragraph property data */

void output_PAP2(sourcePAP, currentPAP, explicit_flag)
 
   struct PAragraphProperty
                        *sourcePAP,     /* Source of changes */
                        *currentPAP;    /* Current values */
   char                 explicit_flag;  /* If set, every value is printed */
 
  { 
    int i,k,n;

    if (explicit_flag || sourcePAP->word0.jc != currentPAP->word0.jc)
      { printf(" <PgfAlignment ");
        switch(sourcePAP->word0.jc)
         {
          case 0: puts("Left>"); break;
          case 1: puts("Center>"); break;
          case 2: puts("Right>"); break; 
          case 3: puts("LeftRight>"); break;
         }
      }

     if (explicit_flag || sourcePAP->word0.fKeep != currentPAP->word0.fKeep)
       { printf(" <PgfSplit ");
         if (sourcePAP->word0.fKeep)
           puts("Yes>");
         else
           puts("No>");
       }

     if (explicit_flag || sourcePAP->word0.fKFollow != currentPAP->word0.fKFollow)
       { printf(" <PgfWithNext ");
         if (sourcePAP->word0.fKFollow) 
           puts("Yes>"); 
         else 
           puts("No>"); 
       } 

     if (explicit_flag || Short(sourcePAP->dxaRight) != Short(currentPAP->dxaRight))
       printf(" <PgfRIndent %dpt>\n", (Short(sourcePAP->dxaRight)/20) );

     if (explicit_flag 
               || (Short(sourcePAP->dxaLeft) != Short(currentPAP->dxaLeft))
               || (Short(sourcePAP->dxaLeft1) != Short(currentPAP->dxaLeft1)))
     {
       printf(" <PgfLIndent %upt>\n", (Short(sourcePAP->dxaLeft)/20) );
       printf(" <PgfFIndent %upt>\n", (Short(sourcePAP->dxaLeft)/20) + (((int)Short(sourcePAP->dxaLeft1))/20) );
     }

     if (explicit_flag || Short(sourcePAP->dyaLine) != Short(currentPAP->dyaLine))
     {
       i = ((short) Short(sourcePAP->dyaLine))/20 - (Current_CHP.word01.hps/2);
       printf(" <PgfLeading ");
       if (i > 0)
         printf("%upt>\n",i);
       else
         printf("0>\n");
     }

     if (explicit_flag || Short(sourcePAP->dyaBefore) != Short(currentPAP->dyaBefore))
       printf(" <PgfSpBefore %upt>\n", (Short(sourcePAP->dyaBefore)/20) );

     if (explicit_flag || Short(sourcePAP->dyaAfter) != Short(currentPAP->dyaAfter))
       printf(" <PgfSpAfter %upt>\n", (Short(sourcePAP->dyaAfter)/20) );

     /* Process Tabs */

     TBD = (struct TaBDescriptor *) &sourcePAP->rgTBDs[0];

     n=0;
     for (i=0; i<20 ; i++)    /* Count the tabs */
       if (Short(TBD[i].dxa))
         n++;

     if (n>0)
       printf(" <PgfNumTabs %u>\n", n);
     
     n=0;

     for (i=0; i<20; i++)
     {
       if (Short(TBD[i].dxa))
       {
         printf("  <TabStop\n    <TSX %u>\n    <TSType", (Ushort)Short(TBD[i].dxa)/20);
         switch(TBD[i].word2.jcTab)
         {
           case 1: puts(" Center>"); break; 
           case 2: puts(" Right>"); break; 
           case 3: puts(" Decimal>"); break; 
           default: puts(" Left>"); break;
         }
         switch(TBD[i].word2.tlc)         /* TAB leader code */
         {
           case 0: k=' '; break;
           case 1: k='.'; break;
           case 2: k='-'; break;
           case 3: k='_'; break;
         }
         printf("    <TSLeader %u>\n  > # End TAB\n", k);
       }
     }
    return; 
  }
  
  
/* Output new paragraph properties (only those which changed) */

void output_PAP(sourcePAP, currentPAP, explicit_flag)

   struct PAragraphProperty
			*sourcePAP,	/* Source of changes */
			*currentPAP;	/* Current values */
   char			explicit_flag;	/* If set, every value is printed */

  { int i, flag;
    char *s_ptr, *c_ptr, k;

    /* is there any difference? */
  
    flag = 0;
    s_ptr = (char *) sourcePAP;
    c_ptr = (char *) currentPAP;

    for (i=0; i<sizeof(struct PAragraphProperty); i++)
      if (s_ptr[i] != c_ptr[i])
        flag++;

    if ((!(explicit_flag)) && (flag == 0) && (new_page == 0))
      return;                         /* Paragraph format not changed */

    styled_paragraph=0;

    if (sourcePAP->word0.fStyled)		/* Style code */
    {
      if (styled_flag)
      {  printf(" <PgfTag `Para%c%c'>  # Styled paragraph\n",
                  style_key[sourcePAP->word0.stc].KEY[0],
                  style_key[sourcePAP->word0.stc].KEY[1]);
         styled_paragraph=1;
         return;
      }
      else
      {  printf(" <PgfTag `Para%u'>  # Styled paragraph\n",sourcePAP->word0.stc);
         return;
      }
    }

    puts("<Pgf");                     /* Begin of Pgf */

    if (new_page==2)   /* Reset flag */
    {
      printf(" <PgfColumnTop No>\n");
      new_page=0;
    }
    if (new_page==1)
    {
      printf(" <PgfColumnTop Yes>\n");
      new_page++;		/* Flag will be reset next time */
    }

    output_PAP2(sourcePAP, currentPAP, explicit_flag);

    puts(">      # End of Pgf");

  }

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

/* String processing */

void flush_string()          /* Ouput current string as it is */
  {
    if (string_ptr>0)
    {
      current_string[string_ptr]=0;           /* String must be zero terminated */
      printf("<String `%s'>\n", current_string);
    }
    string_ptr=0;
    return;
  } 


Uint add2string(carac)      /* Add character to current string */
  Uchar carac;
  {
    if (string_ptr >= STRING_LENGTH)
      flush_string();

    current_string[string_ptr]=carac;
    string_ptr++;
    return(string_ptr);
  }

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

/* Text processing */

Uint handle_byte(offset)  /* Handle byte of text, convert it and output
                             to stdout. Returns the offset of the next byte
                             to be treated */

  Uint offset;      /* Current byte is at this offset in the file (not in
                       the array: text_array[offset-128] ) */

  { Uint ch_ptr, k;
    char *ptr;
    
    ch_ptr = offset-128;

    /* Check paragraph information */

    if (find_FOD(ParPage, offset, &pa_FOD, &prev_pa_FOD, ParPageNb) 
        || new_paragraph)

    { /* Handle Pgf info */

      if (!new_paragraph)   /* Simulate new paragraph even if there was no CR-LF */
      {
        flush_string();
        printf(" > # End ParaLine\n> # End Para\n");
        new_paragraph++;
      }

      printf("<Para\n");

      {
        Set_PAP(&Temp_PAP, &Current_PAP, NULL, sizeof(struct PAragraphProperty));

        PAP = (struct PAragraphProperty *) pa_FOD.PROP;
 
        Set_PAP(&Current_PAP, PAP, &Default_PAP, pa_FOD.cch);

        output_PAP(&Current_PAP, &Temp_PAP, 0);  /* Output new properties */

        Set_CHP(&Current_CHP, &Default_CHP, NULL, sizeof(struct PROPerty_of_CHaracter));
      }
      puts(" <ParaLine");
    }



    /* Check character information */

    if (   find_FOD(CharPage, offset, &ch_FOD, &prev_ch_FOD, CharPageNb)
        || new_paragraph)
    { 
      flush_string();

      Set_CHP(&Temp_CHP, &Current_CHP, NULL, sizeof(struct PROPerty_of_CHaracter));

      Chp = (struct PROPerty_of_CHaracter *) ch_FOD.PROP;

      if (ch_FOD.cch==0 && styled_paragraph)    /* Use default pgf font? */
      {
        Set_CHP(&Current_CHP, style_key[Current_PAP.word0.stc].PROP,
                &Default_CHP, style_key[Current_PAP.word0.stc].cch);
      }
      else
      {
        /* Use direct formatting */
        Set_CHP(&Current_CHP, Chp, &Default_CHP, ch_FOD.cch);  
      }

      output_CHP(&Current_CHP, &Temp_CHP, 0);  /* Output new properties */
    } 
    new_paragraph=0;

    /* Caracteres speciaux ? */

#define ch       (Uchar)text_array[ch_ptr]
#define ch2      (Uchar)text_array[ch_ptr+1]

    if (ch==RETURN && ch2==LF)    /* End of paragraph */
    {
    flush_string();
    puts(" >   # End ParaLine");
    puts(">   # End Para");
    new_paragraph=1;
    return(offset+2);
    }

    if (ch==NL)              /* Hard line break */
    {
    flush_string();
    puts("<Char HardReturn>");
    puts(" >   # End ParaLine");
    puts(" <ParaLine ");
    return(offset+1);
    }

    if (ch==FF)             /* Form Feed */
    {
    flush_string();
    puts(" >   # End ParaLine"); 
    puts(">   # End Para");
    puts("# New Page");
    new_paragraph=1;                /* Real form feed */
    new_page=1;
    return(offset+1);
    }

    /* Handle special characters */

    if (Current_CHP.word01.fSpecial || ch == 5)
    {
      if (ch==FOOTNOTE || ch ==5)                  /* This is a footnote */
      {
        flush_string();
        printf("<String `%u'> # Footnote ref\n", Current_footnote);
        if (! (processing_notes||notes_on_last_page))
          printf("<AFrame %u> # Footnote text Frame\n", (Current_footnote)*2 );

        Current_footnote++;
        return(offset+1);
      }
      flush_string();
      printf("# Special char %u ignored\n", ch);
      return(offset+1);        /* Other special characters are ignored %%% */
    }

    if (char_conv(ch) == 0)  /* Ignorer char 0 */
      return(offset+1);

    if (char_conv(ch)<' ' || char_conv(ch)>=0x7f    /* Non standard ASCII */
        || char_conv(ch) == 0x27
        || char_conv(ch) == TAB
        || char_conv(ch) == '\\'
        || char_conv(ch) == '>'
        || char_conv(ch) == 0x60 )
    {
      if (string_ptr+7>=STRING_LENGTH)
        flush_string();
      ptr=(char *) &current_string[string_ptr];
      sprintf(ptr, "\\x%x ",(Uint) char_conv(ch));
      string_ptr += strlen(ptr);
    }
    else 		/* Standard ASCII */
    {
      if (islower(char_conv(ch)) && Current_CHP.word01.csm)  /* Convert to upper case */
        add2string((Uchar)toupper(char_conv(ch)));
      else
        add2string(char_conv(ch));
    }
    return(offset+1);
  }

/* Process text */

void process_text(start_offset, end_offset, text_ID)

  Uint start_offset,   /* Offset into text_array of the text portion to handle */
       end_offset,     /* Offset of byte following end of portion */
       text_ID;        /* ID of textrect */

  {
   Uint i;
   /* Initialisation */

   /*
   ch_FOD.i_page=0; ch_FOD.i_FOD=0; 
   ch_FOD.fcLimit=127;

   pa_FOD.i_page=0; pa_FOD.i_FOD=0; 
   pa_FOD.fcLimit=127; */

   puts("<TextFlow");

   if ((text_ID != 0) && ! notes_on_last_page)
     printf(" <TextRectID %u>\n", text_ID);

   Set_PAP(&Current_PAP, &Default_PAP, NULL, sizeof(struct PAragraphProperty));

   new_paragraph=1;

   /* Go through text */

   for (i=start_offset+128; i < end_offset+128;)
     i=handle_byte(i);

   flush_string();
   if (! new_paragraph)
   {
     printf("  > # End ParaLine\n > # End Para\n");
     new_paragraph++;
   }
   puts("> # End of TextFlow"); 

  }


/* ******************************************************************* */
/* READ STYLE SHEET */

int read_style(StyleFileName)
  char *StyleFileName;

  {
  int   FileIn,         /* Input file descriptor */
        i,n;
  char *ptr;

  struct st_line *s_line;	/* pointer to current line */

  FileIn = open(StyleFileName,O_RDONLY);

  if (FileIn == -1)
    { fprintf(stderr,"# Impossible de lire la feuille de style : %s\n",
		      StyleFileName);
      return(0);
    }
  if (read(FileIn,&s_header,sizeof(s_header)) != sizeof(s_header))
    { fprintf(stderr," Impossible de lire l'entete (Style)\n");	
      return(0);
    }
  if ((Ushort)Short(header.Wident) != 0137061)
    { fprintf(stderr," Not a Word 4.0 style sheet\n");
      return(0);
    }
 
  text_array_size = Int(s_header.fcMac) - 128;
  last_text_byte = text_array_size;
 
  printf("# Style sheet text size:%u bytes\n", text_array_size);

  text_array = (char *) malloc(text_array_size);        /* Allocation de memoire */
  if (text_array == NULL)
    { fprintf(stderr,"Erreur d'allocation\n");
      exit(1);
    }
  if (read(FileIn, text_array, text_array_size) != text_array_size)
    { fprintf(stderr,"Erreur lors de la lecture du texte\n");
      exit(1);
    }
  puts("# Style sheet text read ");

  /* Lecture des pages de formatage */
 
  /* Caracteres */
#define         s_pnChar  ((short)((Int(s_header.fcMac) + 127) / 128))
                                /* Page number of beginning of Char info */
 
  s_CharPageNb = (Ushort)Short(s_header.pnPara) - s_pnChar;
  s_CharPage = (struct Page *) malloc(s_CharPageNb*128);
  if (s_CharPage == NULL)
    { fprintf(stderr," (style) Erreur d'allocation, caracteres\n");
      return(0);
    }
  lseek(FileIn, (s_pnChar*128), L_SET);           /* Go to beginning of pages */
     
  if (read(FileIn, s_CharPage, (s_CharPageNb*128)) != (s_CharPageNb*128))
    { fprintf(stderr," (style) Erreur lors de la lecture du format de caractere\n");
      return(0);
    }
  printf("# (style) Char table read, %u pages\n",s_CharPageNb);

  /* Paragraphes */

  s_ParPageNb = (Ushort)Short(s_header.pnFntb) - (Ushort)Short(s_header.pnPara);
  s_ParPage = (struct Page *) malloc(s_ParPageNb*128);
  if (s_ParPage == NULL)
    { fprintf(stderr," (style) Erreur d'allocation, paragraphes\n");
      return(0);
    }
  lseek(FileIn, ((Ushort)Short(s_header.pnPara)*128), L_SET); /* Go to beginning of pages */
 
  if (read(FileIn, s_ParPage, (s_ParPageNb*128)) != (s_ParPageNb*128))
    { fprintf(stderr," (style) Erreur lors de la lecture du format de paragraphe\n");
      return(0); 
    }
  printf("# Para table read, %u pages\n",s_ParPageNb);

  close(FileIn);

  /* Initialisation des styles de caracteres */

  for (n=0; n<31; n++);
  {
    styles[n].PROP = (char *) &Default_CHP;
    styles[n].cch = sizeof(struct PROPerty_of_CHaracter);
  }

  style_key = (struct STYLE_KEY *) malloc(sizeof(struct STYLE_KEY)*128);
  if (style_key == NULL)
    { fprintf(stderr," Erreur d'allocation\n");
      return(0);
    }


  for (n=0; n<128; n++)
  {
    style_key[n].KEY[0]=' ';
    style_key[n].KEY[1]=' ';
  }

  s_line = (struct st_line *) text_array;

  ch_FOD.fcLimit = 127;
  pa_FOD.fcLimit = 127;

  /* Impression du catalogue des paragraphes */

  puts("<Catalog");

  for (i=0; sizeof(struct st_line)*i < last_text_byte; i++) 
  {
    printf("# Processing style sheet line %u\n",i);

    /* Copy 2 char key */
    strncpy(style_key[s_line[i].stc].KEY, s_line[i].KEY, 2);

    if (s_line[i].stc<30) /* Character style is in 0..30 */
    {
      printf("# Storing character style %u\n", s_line[i].stc);

      if (find_FOD(s_CharPage, (i*32)+128, &ch_FOD, &prev_ch_FOD, s_CharPageNb))
      {
        styles[s_line[i].stc].PROP = (char *) ch_FOD.PROP;
        styles[s_line[i].stc].cch  = ch_FOD.cch;
      }
    }
    else
    {
      if (s_line[i].stc<105) /* Paragraph style is in 31..104 */
      {
        find_FOD(s_ParPage, (i*32)+128, &pa_FOD, &prev_pa_FOD, s_ParPageNb);
        Set_PAP(&Current_PAP, pa_FOD.PROP, &Default_PAP, pa_FOD.cch);

        find_FOD(s_CharPage, (i*32)+128, &ch_FOD, &prev_ch_FOD, s_CharPageNb);

        /* Store pgf's character format */
        style_key[s_line[i].stc].PROP = (char *) ch_FOD.PROP;
        style_key[s_line[i].stc].cch = ch_FOD.cch;
        Set_CHP(&Current_CHP, ch_FOD.PROP, &Default_CHP, ch_FOD.cch);

        printf("<Pgf\n <PgfTag `Para%c%c'>  # Styled paragraph\n", 
               s_line[i].KEY[0], s_line[i].KEY[1]);
        output_PAP2(&Current_PAP, &Default_PAP, 1);
        printf("<Font\n");
        output_CHP2(&Current_CHP, &Default_CHP, 1);
        printf("> # End of Font\n> # End of Pgf\n");
      }
    }
  }

  puts("> # End Catalog");
  init_defaults();

  free(text_array);

  return(1);
  }

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

/* MAIN PROGRAM
   ============    */
main(argc,argv)
  int argc;
  char *argv[];

{
  int 	FileIn,		/* Input file descriptor */
 	i,n,a,b;
  char *ptr;
  FILE *DataFile;
  char  input_path[90];	/* storage for input file path */
  
  Uint n_lines;		/* Number of lines inside one pgf */

  DataFileName = (char *) argv[2];
  
  /* Option -l means notes on last page */
  notes_on_last_page = (Uchar) ! strncmp("-l",argv[argc-1],2);

  for (n=0; n<256; n++)
    char_def[n]=n;

  DataFile = fopen(DataFileName,"r");
  if (DataFile != NULL)
  {  
    while (fscanf(DataFile,"<%u %u>\n",&b,&a) == 2)
    char_def[b]=a;

    close(DataFile);
  }

  init_defaults();     /* Initialise some constants */

  FileIn = open(argv[1],O_RDONLY);
  if (FileIn == -1)
    { fprintf(stderr,"Impossible d'ouvrir le fichier d'entree\n");
      exit(1);
    }
  if (read(FileIn,&header,sizeof(header)) != sizeof(header))
    { fprintf(stderr,"Impossible de lire l'entete\n");
      exit(1);
    }
  if ((Ushort)Short(header.Wident) != 0137061)
    { fprintf(stderr,"Not a Word 4.0 file\n");
      exit(1);
    } 

  /* Impression de l'entete */

  puts("<MIFFile 1.01> # Generated by word2mif release 1.10 5/19/89, University of Geneva");
  puts("include(mif_read.m4)");
  puts("#");
  printf("# File Name:%s\n", argv[1]);
  if (notes_on_last_page)
    puts("# Notes on last page");
  else
    puts("# Notes on current page");
  puts("<Units Ucm>");
  puts("<Document");
   puts("<DPageSize  21.21 cm 30.00 cm>");
   puts("<DMargins  2.50 cm 2.50 cm 2.50 cm 2.50 cm>");
   puts("<DColumns 1>");
   puts("<DHeadOnFirst Yes >");
   puts("<DFootOnFirst Yes >");
   puts("<DStartPage 1>");
   puts("<DTwoSides No >");
   puts("<DParity FirstRight >");
   puts("<DFrozenPages No >");
  puts("> # end of Document");

  /* Lecture et analyse de la feuille de style */

  styled_flag = 0;

  i=0;
  for (n=0; n<80 && argv[1][n]; n++)		/* Isolate the path of input file */
    if (argv[1][n]=='/')
      i=n+1;		/* End of path is at last slash */
  
  if (i)
    strncpy(input_path, argv[1], i);	/* Copy input path */

  input_path[i]=0;	/* End of string */

  i=0;		/* Ignore the PC tree path */
  for (n=0; n<33 && header.szSsht[n]; n++)
  {
    if (isupper(header.szSsht[n])) 	/* map filename to lower case */
      header.szSsht[n]= tolower(header.szSsht[n]);

    if (header.szSsht[n]=='\\')		/* Filename starts after last backslash */
      i=n+1;
  }

  if (n)
  {
    strncat(input_path, &header.szSsht[i],90);
    printf("# Style sheeet name:%s i=%u\n", input_path, i);
    styled_flag = read_style(input_path);
  }

  /* Lecture du texte proprement dit */

  text_array_size = Int(header.fcMac) - 128;
  last_text_byte = text_array_size;

  printf("# Text size:%u bytes\n", text_array_size);

  text_array = (char *) malloc(text_array_size);	/* Allocation de memoire */
  if (text_array == NULL)
    { fprintf(stderr,"Erreur d'allocation\n");
      exit(1);
    }
  if (read(FileIn, text_array, text_array_size) != text_array_size)
    { fprintf(stderr,"Erreur lors de la lecture du texte\n"); 
      exit(1); 
    }
  puts("# Text read ");
  /* Lecture des pages de formatage */

  /* Caracteres */

  CharPageNb = (Ushort)Short(header.pnPara) - pnChar;
  CharPage = (struct Page *) malloc(CharPageNb*128);
  if (CharPage == NULL)
    { fprintf(stderr,"Erreur d'allocation, caracteres\n"); 
      exit(1); 
    } 
  lseek(FileIn, (pnChar*128), L_SET);		/* Go to beginning of pages */

  if (read(FileIn, CharPage, (CharPageNb*128)) != (CharPageNb*128))
    { fprintf(stderr,"Erreur lors de la lecture du format de caractere\n");  
      exit(1);  
    }  
  printf("# Char table read, %u pages\n",CharPageNb);
  /* Paragraphes */
 
  ParPageNb = (Ushort)Short(header.pnFntb) - (Ushort)Short(header.pnPara); 
  ParPage = (struct Page *) malloc(ParPageNb*128); 
  if (ParPage == NULL) 
    { fprintf(stderr,"Erreur d'allocation, paragraphes\n");  
      exit(1);  
    }  
  lseek(FileIn, ((Ushort)Short(header.pnPara)*128), L_SET); /* Go to beginning of pages */ 

  if (read(FileIn, ParPage, (ParPageNb*128)) != (ParPageNb*128)) 
    { fprintf(stderr,"Erreur lors de la lecture du format de paragraphe\n");   
      exit(1);   
    }   
  printf("# Para table read, %u pages\n",ParPageNb);

  /* Footnotes */

  FntbPageNb = (Ushort)Short(header.pnSep) - (Ushort)Short(header.pnFntb);  
  
  if (FntbPageNb == 0)
    FNTB == NULL;
  else
    {
      FNTB = (struct FootNoteTaBle *) malloc(FntbPageNb*128);  
      if (FNTB == NULL)  
        { fprintf(stderr,"Erreur d'allocation, notes\n");   
          exit(1);   
        }   
      lseek(FileIn, ((Ushort)Short(header.pnFntb)*128), L_SET); /* Go to beginning 
							   of pages */
     
      if (read(FileIn, FNTB, (FntbPageNb*128)) != (FntbPageNb*128))  
        { fprintf(stderr,"Erreur lors de la lecture de la table des notes\n");    
          exit(1);
        }
      printf("# Footnote table read, %u pages\n", FntbPageNb);

      FND = (struct FootNoteDescriptor *) &(FNTB->FNDs); /* Address of first FND */

      /* Process footnotes */

      /* 1: Define anchored Frames */

      if (!notes_on_last_page)
      {
        puts("<AFrames");
        for (i=1; i < (Ushort)Short(FNTB->cfnd); i++)  /* create one Frame per footnote */
          {
             puts(" <Frame");
             printf("  <ID %u>\n",(i*2));	   /* Frame ID, begins at 2 (4,6,8...) */
	     puts("  <Pen 15>");
             puts("  <PenWidth `0.500 '>");
	     puts("  <Fill 7>");
	     puts("  <Inverted No>");
printf("  # Text size: %u chars\n", Int(FND[i].cpFtn)-Int(FND[i-1].cpFtn));
             n_lines = (Int(FND[i].cpFtn)-Int(FND[i-1].cpFtn))/90+1;
	     printf("  <BRect 0 0 6.25\" %upt>\n", 
                       n_lines*15+2);
	     puts("  <FrameType Bottom>");
	     puts("  <NSOffset 0\">");
	     puts("  <BLOffset 0\">");
	     puts("  <AnchorAlign Left>");
	     puts("  <Cropped Yes>");
	     puts("  <TextRect");
	     printf("    <ID %u>\n", (i*2)+1); /* TextRectID, value 3,5,7,9... */
	     printf("   <BRect 0\" 0\" 6.13\" %upt>\n",
                       n_lines*15);
	     puts("   <TRAutoConnect No>");
	     puts("  > # End of TextRect");
	     puts(" > # End of Frame");
     	  }
        puts("> # End of AFrames");
      }
/*    else */
      if (0)  /* %%%%%%%% */
      {
        for (i=1; i < (Ushort)Short(FNTB->cfnd); i++)  /* create one TextRect per footnote */
        {
          puts("  <TextRect");
          n_lines = (Int(FND[i].cpFtn)-Int(FND[i-1].cpFtn))/90+1;
	  printf("  <BRect 0 0 6.25\" %upt>\n", 
                    n_lines*15);
	  puts("   <TRAutoConnect No>");
          puts("  > # End of TextRect");
        }
      }

      last_text_byte = Int(FND[0].cpFtn)-1;
    }

  /* Process main text */
  printf("# Main text: First byte:0, last byte:%u\n", last_text_byte+1);
  processing_notes=0;
  process_text(0, last_text_byte+1, 0);          /* Main loop */

  if (FntbPageNb)
    {
      /* 2: Process footnote contents */
      processing_notes = 1;
      Current_footnote = 1;
      puts("# Footnotes section");
      for (i=1; i < (Ushort)Short(FNTB->cfnd); i++)
      {
        printf("  # Start:%u Stop:%u\n", Int(FND[(i-1)].cpFtn), 
		Int(FND[i].cpFtn));

	process_text(Int(FND[(i-1)].cpFtn), Int(FND[i].cpFtn), (i*2)+1);

      }
      puts("# End of footnotes");
    }

  printf("# End of MIFFILE\n");
  close(FileIn);
  exit(0);
}
//E*O*F word2mif.c//

echo x - word2mif.data
cat > "word2mif.data" << '//E*O*F word2mif.data//'
<31 6>
<128 130>
<129 159>
<130 142>
<131 137>
<132 138>
<133 136>
<134 140>
<135 141>
<136 144>
<137 145>
<138 143>
<139 149>
<140 148>
<141 147>
<142 128>
<143 129>
<144 131>
<145 190>
<146 174>
<147 153>
<148 154>
<149 152>
<150 158>
<151 157>
<152 217>
<153 133>
<154 134>
<155 162>
<156 163>
<157 180>
<159 196>
<160 135>
<161 146>
<162 151>
<163 156>
<164 150>
<165 132>
<166 187>
<167 188>
<168 192>
<173 193>
<174 199>
<175 200>
<196 5>
<255 4>
//E*O*F word2mif.data//

echo x - word4.h
cat > "word4.h" << '//E*O*F word4.h//'

/* Microsoft Word 4.0 Binary file format (IBM-PC)

O. Schopfer, University of Geneva, August 1988

 "@(#) word4.h 1.2.1.2 8/25/88 Release 1.4
*/

/* Constantes */

#define		RETURN	13	/* Paragraphs end with RETURN+LF */
#define		LF	10
#define		NL	11	/* Hard line break */
#define		FF	12	/* Explicit page break */
#define		TAB	9	/* Tabulator */
#define		SPACE	32	/* Normal space */
#define		NBSPACE	255	/* Non-breaking space */
#define		HYPHEN	45	/* Normal Hyphen */
#define		NBHYPHEN 196	/* Non-breaking Hyphen */
#define		NRHYPHEN 31	/* Non-required Hyphen */
#define		PAGE	1	/* (page) */
#define		DATE	2	/* (date_d'impression) */
#define		TIME	3	/* (heure_d'impression) */ 
#define		FOOTNOTE 4	/* Footnote reference mark (automatic numbering) */

/* Types */

typedef unsigned int Uint;
typedef unsigned char Uchar;
typedef unsigned short Ushort;
typedef unsigned long Ulong;
 
struct PCSHORT
  { Uchar byte[2]; };
typedef struct PCSHORT PCshort;

struct PCINT
  { PCshort word[2]; };
typedef struct PCINT PCint;

struct PCLONG
  { PCint lword[2]; };
typedef struct PCLONG PClong;

/* Entete */

struct Header
  {
	PCshort Wident,		/* Should be 0137061 */ 
		dty,		/* Document type, should be 0 */
		wTool,		/* Reserved, 0125400 */
		Reserved[4];
	PCint	fcMac;		/* Number of bytes of actual text PLUS 128
				   (bytes in one sector, low order first) */
	PCshort	pnPara,		/* Page number of start of Paragraph info (a page
				   is a 128-byte chunk) */
#define		pnChar	((short)((Int(header.fcMac) + 127) / 128))
				/* Page number of beginning of Char info */
		pnFntb,		/* Page number of Footnote table FNTB 
					(pnSep if none) */
		pnSep,		/* Page number of start of division info 
					(pnSetb if none) */
		pnSetb,		/* Page number of start of SETB 
					(pnPgtb if none) */
		pnPgtb,		/* Page number of start of Page Table PGTB */
		pnSumd;		/* Page number of Sumary Information */
	char	szSsht[66],	/* Style sheet filename, zero terminated */
		Reserv[2],
		PRD[8];		/* PRD filename without path+extension */
	PCshort	pnMac,		/* Count of disk pages in whole file
				   (last page number + 1) */
		fMarkRev,	/* Revision mark */
		Reserv02[9];
  };


struct Page 
  {
	PCint	fcFirst;	/* Byte # in file of first character covered by 
				   this page of formatting info. The byte # of 
				   the 1st character in the text is 128. 
					(low order byte first) */
	Uchar	FODs[123],	/* FOrmat Descriptor and Format PROPerties */
		cfod;		/* Number of FOD's on this page */
  };

/* FOD Format Descriptor (fixed size) */

struct FOrmatDescriptor
  {
	PCint	fcLim;		/* Byte # in file AFTER last character covered 
					by this FOD */
	PCshort	bfprop;		/* Byte offset from beginning of FODs[] to 
				   corresponding FPROP for these characters or 
				   this paragraph. A value
				   of FFFF means that there is no FPROP */
  };

/* Formatting PROPerty (variable size) */

struct FormatPROP 
  {
	Uchar	cch;		/* Number of bytes in this FPROP, excluding this byte */
  };



/* CHP CHaracter Property */

  struct Word0
    {
	unsigned	stc:7;		/* Style code */
/* 0 */	unsigned	fStyled:1; 	/* Is character styled */
	unsigned	ftc:6;		/* Font code */
	unsigned	fItalic:1;	/* Italic */
/* 1 */	unsigned	fBold:1;	/* Bold flag */
    }; 
  struct Word1
    { 
/* 2 */	Uchar		hps;		/* Size of font in half pts (def:24 dec) */
/* 3 */ unsigned	fHidden:1;	/* Hidden char. */
	unsigned	fSpecial:1;	/* Special character (i.e. Footnote) */
	unsigned	csm:2;		/* Case modifier:
						0 normal
						1 upper
						2 small caps */
	unsigned	fNew:1;		/* Revised char(s) */
        unsigned	fDline:1;	/* Double Underline */
	unsigned	fStrike:1;	/* Strikethrough */
/* 3 */	unsigned	fUline:1;	/* Underline */
    };

struct PROPerty_of_CHaracter 
  {
	struct Word0	word00;
	struct Word1	word01;
/* 4 */	Uchar		hpsPitch;	/* Reserved */
/* 5 */	char		hpsPos,		/* Position: 0 Normal
						<0 Subscript
						>0 Superscript */
			Reserv02[4];

  };


/* PAP PAragraph Property */
  struct Word00 
    {
        unsigned        stc:7;          /* Style code */
/* 0 */ unsigned        fStyled:1;      /* Is character styled */
	unsigned	:3;		/* Reserved */
	unsigned	fSBS:1;		/* Parag. Side by side */
	unsigned	fKeep:1;	/* Keep paragraph on one page */
        unsigned	fKFollow:1;	/* Keep this parag. together with next */
/* 1 */ unsigned	jc:2;		/* Justification	0=left
								1=center
								2=right
								3=both */
     };
   struct Word01
     {
	unsigned	:1;             /* Reserved */
/* 2 */	unsigned	stcNorm:7;	/* Style code of normal chars. */
	unsigned	fHidden:1;	/* Paragraph is Hidden in outline view 
						(mode plan) */
/* 3 */	unsigned	level:7;	/* Level number (outline) */
     };
  struct Word08
   {
        unsigned        bsc:2;		/* Border style code (0=Normal borders) */
	unsigned	btc:2;		/* Border type code (0=normal parag) */
/* 16 */ unsigned	rhc:4;		/* Running-head code (0=normal parag) */
/* 17 */unsigned	:8;		/* Reserved */
   };

struct PAragraphProperty
  {
	struct Word00	word0;
	struct Word01	word1;
/* 4-5 */ PCshort	dxaRight,	/* Right indent in twips(=1/1440 inch) */
/* 6-7 */		dxaLeft,	/* Left indent in twips */
/* 8-9 */		dxaLeft1,	/* First line indent */
/* 10-11 */		dyaLine,	/* Line spacing (standard 240 ) */
/* 12-13 */		dyaBefore,	/* Space before */
/* 14-15 */		dyaAfter;	/* Space after */
	struct Word08	word8;
/* 18 */ char 		Reserv03[4];	/* Reserved */
/* 22 */ char		rgTBDs[80];	/* Room for 20 tab stops */
  };

/* TBD Tab descriptor */
  struct Word002
    {
	unsigned	:2;		/* Reserved */
	unsigned	tlc:3;		/* Tab leader code: 0=none, 1=dots, 
					   2=hyphens, 3=underline. */
/* 2 */ unsigned	jcTab:3;	/* Justification after tab: 
						0=left, 1=center, 2=right,
						3=decimal, 4=vertical bar */
/* 3 */ char		chAlign;	/* Char to decimal align on (0=".") */
    };

struct	TaBDescriptor
  {
	PCshort		dxa;		/* Distance from left margin in twips */
	struct Word002	word2;
  };

/* FOOTNOTE SECTION

   The footnote section (optional) starts at the first complete page after the
PARAGRAPH section, and contains the FNTB which contains an array of FND, 
footnote descriptors */

/* FNTB Footnote Table */

struct FootNoteTaBle
  {
	PCshort	cfnd,		/* Number of FND + 1 (1 or more) */
		cfndMax;	/* Same as word 0 */
	char	FNDs;		/* First char of first FND (just to have
				   its address) */
  };

/* FND Footnote Descriptor */

struct FootNoteDescriptor
  {
	PCint	cpRef,		/* Byte offset into text area of footnote ref */
		cpFtn;		/* Byte offset into text area of footnote text */
  };

/* SECTION PROPERTY (Division)

   The SEP section (optional) is on the page immediately after the footnote
section, and contains one or more SEPS */
   struct SEP_Word0
    {
	Uchar	cch;			/* Count of bytes, EXCLUDING this one */
	unsigned	stc:7;		/* Style code */
	unsigned	fStyled:1;	/* Section is styled */
    };

struct SEctionProperty
  {
	struct SEP_Word0	word0;	/* 0-1 */
	char		Bkc_Pgn;	/* Break code, and page numbering */
	PCshort		yaMac,		/* Page length in Twips */
			xaMac,          /* Page width  in Twips */
			pgnStart,	/* Start numbering at ... (def: -1) */
			yaTop,		/* Top margin Twips */
			dyaText,	/* Text height */
			xaLeft,		/* Left margin */
			dxaText;	/* Text width */
	char		Reserved,	/* Running heads etc. */
			cColumns;	/* Number of columns */
	PCshort		yaRH1,		/* Position of top header */
			yaRH2,		/* Position of bottom header */
			dxaCol,		/* Gap between columns */
			dxaGutter,	/* Marge de reliure */
			yaPgn,		/* Y position of page # */
			xaPgn,          /* X position of page # */ 
			dxaLnn;		/* distance of line # from left */
	char		Reserved02;
  };

struct SEctionTaBle
  {
	PCshort		csed,		/* # of sections (1 or more ) */
			csedMax;	/* Undefined (=csed?) */
  };

struct SEctionDescriptor
  {
	PCint		cp;	/* Byte offset in text area of the end-of-section
					mark */
	PCshort		fn;	/* Undefined */
	PCint		fcScp;	/* Byte offset (into file) of associated SEP */
  };

/* ************************************************
    STYLE SHEET SPECIFICATIONS                         */

struct st_line			/* Text line of style sheet */
  {
	char	stc,		/* Style code */
		KEY[2],		/* Two letters of style code */
		remark[28],	/* DEscription */
		cr;
  };
//E*O*F word4.h//

exit 0