/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Microsoft Corporation, 1989                                 */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = PPD2BIN.C
 *
 * DESCRIPTIVE NAME = PPD Formatter
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION  Parses a PPD files and puts the information in an
 *              output file
 *
 *
 * FUNCTIONS
 *                 AmbFilename
 *                 atoRound
 *                 RepWarning
 *                 RepError
 *                 SkipNumber
 *                 SkipBlank
 *                 MovePast
 *                 CopyString
 *                 CopyInQuote
 *                 Openppd
 *                 ScanParam
 *                 ScanProcedure
 *                 AddExtension
 *                 FreeAll
 *                 RemoveExtension
 *                 GetArgs
 *                 SaveCommand
 *                 SaveProcedure
 *                 SaveString
 *                 FormPpd
 *                 bld_compare
 *                 CntInpFiles
 *                 WriteRCFile
 *                 main
 *
 *
 * NOTES        Uses the following format for output file:
 *              The output file consists of following segments:
 *
 *              1. Signature
 *              2. Printer directory segment
 *              3. One or more printer information segments
 *
 *              Signature has got the following structure:
 *              Identifying name               40 bytes,
 *              Total no of entries in dir      2 bytes,
 *              Present no of entries in dir    2 bytes,
 *              free                            4 bytes.
 *
 *              Each entry in Printer directory segment has got the
 *              following structure:
 *              Printer name                   40 bytes,
 *              Offset of printer segment       4 bytes,
 *              free                            4 bytes.
 *
 *              Each printer information segment has got the structure
 *              stored in format DESPPD. Towards the end of printer info
 *              segment lies the list buffer of length specified by the
 *              first two bytes of DESPPD structure. The buffer contains
 *              various command string lists and dimension lists.
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "ppd2bin.h"
#include "..\inc\ppdialog.h"
#include "..\inc\fontres.h"
#define  IBUFFSIZE     2048
#define  MAX_ESC_STR_LEN 256L          /*                                    */

#define int SHORT
#define unsigned USHORT


int SkipBlank(char *);

FILE *fhIn, *fhOut;
short iInfiles;                          /* count of input files               */
long ofsOutfile = 0;                   /* to indicate current offset in
                                          output file                        */
char *apszInfiles[MAX_INPUT];          /* input file names pointer list      */
char szOutDir[MAX_FNAMESIZE];
char szGeneric[MAX_FNAMESIZE];
char abBuffin[IBUFFSIZE];              /* buffer required for reading input  */
char acDefFont[] = "Courier";
int cbBuffout = 0;                     /* number of bytes filled in output
                                          buffer                             */
DESPPD desPpd;                         /* printer descriptor segments        */
DRENTRY *pdrTblEntry;
SIGNATURE *psigFile;
char *pbDirBuffer;                     /* pointer to directory buffer tobe
                                          allocated                          */
PBYTE pbItemsBuffer;                   /* pointer to items                   */
static char pbPrBuffer[1024];

#define MAX_FORM_SIZE 127
SHORT sFormCount;
PCH   pFormTable[64];                   /* allow 64 forms */

/*
** D74609
*/
#define TRUNCATE_FLOAT   (float) 0.0
#define ROUND_FLOAT      (float) 0.9999

int MovePast( char *, char );
VOID roundImgAreaVals( INT *, float, CHAR );

/*            */
BOOL VerifyPPDLineSize( PCHAR );
BOOL BErrorWasDisplayed = FALSE;

#if 0
///***************************************************************************
// *
// * FUNCTION NAME = AmbFilename
// *
// * DESCRIPTION   = This routine checks whether a file name given is
// *                 having any wild card characters.Returns TRUE if
// *                 there are any wildcard characters else FALSE.
// *
// * INPUT         = szFile - pointer to file name
// *
// * OUTPUT        = NONE.
// *
// * RETURN-NORMAL = NONE.
// * RETURN-ERROR  = NONE.
// *
// *************************************************************************   */
//
//BOOL AmbFilename(char *szFile)
//{
//  int i,j;
//
//  i = strlen( szFile );
//  j = 0;
//
//  while (j < i)
//  {
//    if (*(szFile+j) == '*' || *(szFile+j) == '?')
//    {
//      break;
//    }
//    else
//    {
//      j++;
//    }
//  }
//
//  if (j >= i)
//  {
//    return( FALSE );
//  }
//  else
//  {
//    return( TRUE );
//  }
//}
#endif



/*
** D74609
*/
/***************************************************************************
 *
 * FUNCTION NAME = roundImgAreaVals
 *
 * DESCRIPTION   = Used for the *ImageableArea key.  This function either
 *                 rounds the floating point value to the nearest integer, or
 *                 truncates the floating point value to the base integer.
 *                 The new integer value is stored in the output buffer.
 *
 * INPUT         = i - Offset to the input buffer where the floating point
 *                   string is read.
 *                 fIncFrac - Contains one of the following values:
 *                   TRUNCATE_FLOAT - Truncate the floating point value to the
 *                   base integer (i.e.  25.2 -> 25, 14.8 -> 14).
 *                   ROUND_FLOAT - Rounds the floating point value to the next
 *                   higher integer value, providing that there is a fractional
 *                   value (i.e 25.1 -> 26, 79.8 -> 80, 15.0 -> 15, 4.0 -> 4).
 *                   Any other value will yield unpredictable results.
 *                 cMovePastChar - Character value that is passed on to
 *                   MovePast to indicate what character to move past on the
 *                   buffer.  For this function's first call, the argument
 *                   is usually '"' (quote), and most subsequent calls are ' '
 *                   (space).
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = Returns the latest offset (passed in from i above).
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */
VOID roundImgAreaVals( INT *i, float fIncFrac, CHAR cMovePastChar )
{
  USHORT j;

  *i += MovePast( pbPrBuffer + *i, cMovePastChar );

  /*
  **           
  ** Since spaces are used as terminators in this function, a leading space
  ** may cause the string offset to stop before skipping to the next value.
  ** By removing all leading spaces, this ensures that the string offset moves
  ** to the next value.
  */
  /*
  ** @V3.0100963
  ** Check for all valid spaces, not just for the whitespace.  This is to
  ** prevent a repeat performance in what was happening with MovePast().
  */
  while (isspace( *(pbPrBuffer + *i) ) )
  {
    (*i)++;
  }

  /*
  ** For the imageable area, only the integer value is to be stored.  By
  ** adding a fraction (fIncFrac) to the whole number taken from the PPD, it
  ** either increase the integer value by one, or keep the integer unchanged.
  ** Then the fraction can be discarded (convert it to a USHORT).
  */
  j = (USHORT) (atof( pbPrBuffer + *i ) + fIncFrac);

  memcpy((pbItemsBuffer + cbBuffout), (PCHAR) &j, sizeof( USHORT ) );
  cbBuffout += sizeof( USHORT );
}



/***************************************************************************
 *
 * FUNCTION NAME = atoRound
 *
 * DESCRIPTION   = rounds off a fractional number to nearest integer
 *
 * INPUT         = pchBuffer - pointer to buffer containing number
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

int atoRound( char *pchBuffer )
{
  int i;

  i = atoi( pchBuffer );

  while (*pchBuffer >= '0' && *pchBuffer <= '9')
  {
    pchBuffer++;
  }

  if (*pchBuffer == '.')
  {
    pchBuffer++;

    if (*pchBuffer >= '5')
    {
      i++;
    }
  }
  return( i );
}

/***************************************************************************
 *
 * FUNCTION NAME = RepWarning
 *
 * DESCRIPTION   = prints the given message (pszMsg) with the given
 *                 line fragment (pszLine), including the current
 *                 input line number.  If line fragment is NULL, then
 *                 only the message is displayed.
 *
 * INPUT         = err     - error number
 *                 pszLine - optional text
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

RepWarning( ErrType err, char *pszLine )
{
  fprintf( stderr, "%s", szErrmsgs[err] );

  if (pszLine)
  {
    fprintf( stderr, " %s", pszLine );
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = RepError
 *
 * DESCRIPTION   = Same as RepWarning, but terminates as well.
 *
 * INPUT         = err     - error number
 *                 pszLine - optional text
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

RepError( ErrType err, char *pszLine )
{
  RepWarning( err, pszLine );
  exit( 1 );
}

/***************************************************************************
 *
 * FUNCTION NAME = SkipNumber
 *
 * DESCRIPTION   = This routine moves the input buffer pointer forward
 *                 to skip the next number. Returns the number of bytes
 *                 skipped.
 *
 * INPUT         = pszLine - line to skip
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

int SkipNumber( char *pszLine )
{
  int i;

  i = SkipBlank( pszLine );

  if (*(pszLine+i) == '+' || *(pszLine+i) == '-' || *(pszLine+i) == '.')
  {
    i++;
  }

  while (*(pszLine+i) >= '0' && *(pszLine+i) <= '9')
  {
    i++;
  }

  if (*(pszLine + i) == '.')
  {
    i++;

    while (*(pszLine+i) >= '0' && *(pszLine+i) <= '9')
    {
      i++;
    }
  }
  return( i );
}

/***************************************************************************
 *
 * FUNCTION NAME = SkipBlank
 *
 * DESCRIPTION   = This routine moves the input buffer pointer forward
 *                 to the next non-white character.  Returns the
 *                 number of bytes skipped.
 *
 * INPUT         = pszLine - line to skip
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

int SkipBlank( char *pszLine )
{
  int i;

  i = 0;

  while (*(pszLine+i) && (*(pszLine+i) == ' ' || *(pszLine+i) == '\t'))
  {
    i++;
  }
  return( i );
}

/***************************************************************************
 *
 * FUNCTION NAME = MovePast
 *
 * DESCRIPTION   = This routine returns the offset to skip past the
 *                 first occurrence of character chSkip.
 *
 * INPUT         = pbBuffer - pointer to buffer containing text
 *                 chSkip   - character to skip
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

int MovePast( char *pbBuffer, char chSkip )
{
  int i;

  i = 0;

  /*
  **            
  ** Check for tab characters (0x09) as well as whitespaces.  Theoretically, it
  ** would be easier to replace the ' ' and 0x09 check with isspace(), but
  ** to make things safer, just add the 0x09 check (with the excpetion of the
  ** HP 4V, it has been working up to now.  We don't want to possibly break
  ** another PPD by replacing with isspace() ).
  */
  while (*(pbBuffer+i) != chSkip && (*(pbBuffer+i) >= ' ' ||
         *(pbBuffer + i) == 0x09))
  {
    i++;
  }
  i++;
  return( i );
}


/*
**           
** This function previously copied the quoted contents to a destination buffer
** and stored the string length in the first byte.  Now, this function does a
** standard NULL-terminated string copy for the contents within the quotes.
*/
/***************************************************************************
 *
 * FUNCTION NAME = CopyString
 *
 * DESCRIPTION   = This routine copies a string from source to
 *                 destination with delimiters as a double Quote,
 *                 blank or colon.  The resulting string is NULL terminated.
 *
 * INPUT         = szDestn  - destination string
 *                 szSource - source string
 *                 iMaxLen  - length of destination string
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

int CopyString( char *szDestn, char *szSource, int iMaxlen )
{
  int i = 0;

  while (*szSource != '"' && (*szSource >= ' ' || *szSource < 0) &&
         *szSource != ':' && i < iMaxlen)
  {
    *(szDestn + i++) = *(szSource++);
  }
  *(szDestn + i++) = 0;

  return( i );
}


/*
**           
** This function previously copied the quoted contents to a destination buffer
** and stored the string length in the first byte.  Now, this function does a
** standard NULL-terminated string copy for the contents within the quotes.
*/
/***************************************************************************
 *
 * FUNCTION NAME = CopyInQuote
 *
 * DESCRIPTION   = This routine copies a NULL-terminated string from source to
 *                 destination with delimiters as a double Quote.  This
 *                 function returns the string length, in bytes, including
 *                 the terminator.
 *
 *                 If fRemoveDots is TRUE the dots in the target
 *                 string will be replaced with underscores.  This is
 *                 to get around a in the IBM spooler which chokes on
 *                 more than one dot in a printer model name.
 *
 * INPUT         = szDestn     - destination string
 *                 szSource    - source string
 *                 fRemoveDots - flag
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

int CopyInQuote(char *szDestn,char *szSource,BOOL fRemoveDots)
{
  register int i = 0;

  /*
  **           
  ** Remove MAX_ESC_STR_LEN.  Some PPD commands may exceed 256 characters.
  */
#if 0
//  while (*szSource != '"' && i < MAX_ESC_STR_LEN)
#endif

  while (*szSource != '"')
  {
    if (fRemoveDots && *szSource == '.')
    {
      *szSource = '_';
    }
    /*
    ** Keep it a space Not tab CR LF etc...
    */
    else if (isspace( *szSource ))
    {
      *szSource = ' ';
    }
    *(szDestn + i++) = *(szSource++);

    if (*(szSource - 1) == ' ')
    {
      /*
      ** Remove excess spaces
      */
      while (isspace( *szSource ))
      {
        szSource++;
      }
    }
  }

  /*
  ** NULL-terminate the destination string.
  */
  *(szDestn + i++) = 0;

  return( i );
}

/***************************************************************************
 *
 * FUNCTION NAME = Openppd
 *
 * DESCRIPTION   = Opens the file specified in read only text mode and
 *                 returns True if open successful ,else FALSE.  The
 *                 file handle is stored in fhIn
 *
 * INPUT         = szFileName - filename
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

BOOL Openppd( char *szFilename )
{
  fhIn = fopen( szFilename, "rb" );

  if (!fhIn)
  {
    RepWarning( err_cantopen, szFilename );
    return( FALSE );
  }
  printf( "Converting  %s\n", szFilename );
  return( TRUE );
}

/***************************************************************************
 *
 * FUNCTION NAME = ScanParam
 *
 * DESCRIPTION   = This routine scans the szSrchstring in the input
 *                 file and provides the remaining parameter in the
 *                 return buffer provided.  If szSrchstring is found
 *                 this routine returns TRUE else FALSE.
 *
 * INPUT         = szSrchstring - search string address
 *
 * OUTPUT        = pbBufaddress - return buffer address
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

BOOL ScanParam( char *szSrchstring, char *pbBufreturn )
{
  BOOL fIseof, fIsFound;
  int  i, j, k;
  long li, lc;
  UINT uiStrLen = strlen( szSrchstring );

  fIseof = FALSE;

  /*
  ** search for parameter till token found or file eof encountered
  */
  while (!fIseof)
  {
    if ((lc = ftell(fhIn)) == -1L)
    {
      return( FALSE );
    }

    if ((i = fread(abBuffin,1,IBUFFSIZE,fhIn)) != IBUFFSIZE)
    {
      fIseof = TRUE;
    }

    /*
    **           
    ** Verify that the line size does not exceed IBUFFSIZE bytes.
    ** Report an error and skip the command if this exists.
    */
    if (VerifyPPDLineSize( abBuffin ) == TRUE)
    {
      if (i <= 0)
      {
        break;
      }

      /*
      ** Ignore the last partially read line
      */
      for (li = 1;i;li++, i--)
      {
        if ((abBuffin[IBUFFSIZE - li] == '*') &&
            (abBuffin[IBUFFSIZE - li - 1] == '\n'))
        {
          break;
        }
      }
      i--;

      /*
      ** shift back the current access pointer of the file
      */
      if (li > 1 && li < IBUFFSIZE)
      {
        if (fseek( fhIn, -li, SEEK_CUR) == -1L)
        {
          return( FALSE );
        }
      }

      j = 0;
      fIsFound = FALSE;
      while (j < i)
      {
        if (!strncmp( abBuffin+j, szSrchstring, uiStrLen ))
        {
          if (isspace( *(abBuffin + j + uiStrLen) ) ||
              *(abBuffin + j + uiStrLen) == ':')
          {
            fIsFound = TRUE;
          }
        }
        k = j;

        for (;;j++)
        {
          /*
          **           
          ** Check to see if a comment is on the next line.  This will
          ** prevent a trap if the compiler finds a comment immediately
          ** following a command line.  The compiler won't read the
          ** comment and possibly exceed buffer space.
          */
          if ((abBuffin[j] == 0xA) && (abBuffin[j+1] == 0x2A ||
               abBuffin[j+1] == '%'))
          {
            j++;
            break;
          }

          if  (j == i)
          {
            break;
          }
        }

        if (fIsFound)
        {
          k += uiStrLen;
          k += SkipBlank( abBuffin + k );
          memcpy( pbBufreturn, abBuffin + k, j - k );
          break;
        }
      }

      /*
      ** set the access pointer so that in next access the current
      ** token is not reencountered
      */
      if (fIsFound)
      {
        fseek( fhIn, lc+(long)j, SEEK_SET );
        break;
      }
    }
  }
  return( fIsFound );
}

/***************************************************************************
 *
 * FUNCTION NAME = ScanProcedure
 *
 * DESCRIPTION   = This routine scans the szSrchstring in the input
 *                 file and provides the remaining parameter in the
 *                 return buffer provided.  If szSrchstring is found
 *                 this routine returns TRUE else FALSE.
 *
 * INPUT         = szSrchstring - search string address
 *
 * OUTPUT        = pbBufaddress - return buffer address
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

BOOL ScanProcedure( char *szSrchstring,char *pbBufreturn )
{
  BOOL fIseof, fIsFound;
  int  i, j, k, iStrlen;
  long li, lc;

  fIseof = FALSE;

  /*
  ** search for parameter till token found or file eof encountered
  */
  while (!fIseof)
  {
    if ((lc = fseek( fhIn, 0L, SEEK_CUR )) == -1L)
    {
      return (FALSE);
    }

    if ((i = fread( abBuffin, 1, IBUFFSIZE, fhIn )) != IBUFFSIZE)
    {
      fIseof = TRUE;
    }

    if (i <= 0)
    {
      break;
    }

    /* Ignore the last partially read line */
    for (li = 1;i;li++, i--)
    {
      if ((abBuffin[IBUFFSIZE - li] == 0x2A) &&
          (abBuffin[IBUFFSIZE - li - 1] == 0xA))
      {
        break;
      }
    }

    i--;

    /* shift back the current access pointer of the file */
    if (li > 1 && li < IBUFFSIZE)
    {
      if (fseek( fhIn, -li, SEEK_CUR ) == -1L)
      {
        return (FALSE);
      }
    }

    j = 0;
    fIsFound = FALSE;
    iStrlen = 0;

    while (*(szSrchstring + iStrlen) != '\0')
    {
      iStrlen++;
    }

    while (j < i)
    {
      if (!strncmp(abBuffin+j, szSrchstring, iStrlen))
      {
        if (*(abBuffin+j+iStrlen) == ' ' || *(abBuffin+j+iStrlen) == ':')
        {
          fIsFound = TRUE;
        }
      }
    k = j;

    for (;;j++)
    {
      if ((abBuffin[j] == 0xA) && (abBuffin[j+1] == 0x2A))
      {
        j++;
        break;
      }
      if  (j == i)
      {
        break;
      }
    }

      if (fIsFound)
      {
        /*
        ** now reset the file to start of where the token has been
        ** encountered and read a large block so that entire procedure
        ** might be covered.
        */
        if (fseek( fhIn, (long) - (i - k), SEEK_CUR) == -1L)
        {
          return( FALSE );
        }

        if ((i = fread( abBuffin, 1, IBUFFSIZE, fhIn)) <= 0)
        {
          return( FALSE );
        }
        k = iStrlen;
        k += MovePast( abBuffin+k, '"' );
        j = 0;

        while (abBuffin[k] != '"' && k < i)
        {
          if (abBuffin[k] != '\r')
          {
            *(pbBufreturn + 2 + j++) = abBuffin[k++];
          }
          else
          {
            k++;
          }
        }
        *(pbBufreturn+2+j) = '\0';
        *(int *)pbBufreturn = (1+j);
        return (TRUE);
      }
    }
  }
  return (fIsFound);
}

/***************************************************************************
 *
 * FUNCTION NAME = AddExtension
 *
 * DESCRIPTION   = If given filename has no extension, add the given default
 *
 * INPUT         = pszName   - filename
 *                 pszDefext - default extension
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

AddExtension( char *pszName, char *pszDefext )
{
  char           c;
  int            l;
  register char *p;

  l = strlen( pszName );
  p = pszName + l;
  c = '.';

  while (l-- > 0)
  {
    c = *--p;

    if (c == '.' || c == '\\' || c == ':')
    {
      break;
    }
  }

  if (c != '.')
  {
    strcat( p, pszDefext );
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = FreeAll
 *
 * DESCRIPTION   = To free all the memory allocated from heap.
 *
 * INPUT         = NONE.
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

FreeAll( )
{
  int i;

  for (i = 0; i < iInfiles; i++)
  {
    free( apszInfiles[i] );
  }
  free( pbDirBuffer );
}

/***************************************************************************
 *
 * FUNCTION NAME = RemoveExtension
 *
 * DESCRIPTION   = Removes any extension from the given filename.
 *
 * INPUT         = pszName - file name
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

RemoveExtension( char *pszName )
{
  char           c;
  int            l;
  register char *p;

  l = strlen( pszName );
  p = pszName+l;
  c = '.';

  while (l-- > 0)
  {
    c = *--p;

    if (c == '.' || c == '\\' || c == ':')
    {
      break;
    }
  }

  if (c == '.')
  {
    *p = 0;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = GetArgs
 *
 * DESCRIPTION   = Parses all args passed to the program.
 *
 * INPUT         = argc - number of commandline arguments
 *                 argv - pointer to array of commandline arguments
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

GetArgs( int argc, char **argv )
{
  register char *p;
  int i;

  RepWarning( err_ver, NULL );

  /*
  ** To check the range of arguments
  */
  if (argc <= 4 || argc > MAX_INPUT + 3)
  {
    RepError( err_usage, NULL );
  }
  iInfiles = 0;
  p = *++argv;

  /*
  ** pick up the names of input files
  */

  if (*p == '-' && tolower(*(p + 1)) == 'i')
  {
    p = *++argv;

    while (*p != '-' && iInfiles < MAX_INPUT && --argc > 0)
    {
      apszInfiles[iInfiles] = malloc( MAX_FNAMESIZE );

      if (apszInfiles[iInfiles] == NULL)
      {
        RepError( err_arg, NULL );
      }
      strcpy( apszInfiles[iInfiles], p );

      /*                    
      ** ADDEXTENSION(APSZINFILES[IINFILES], DEF_IEXT );
      */

      p = *++argv;
      iInfiles++;
    }
  }
  else
  {
    RepError( err_usage, NULL );
  }

  if (*p == '-' && tolower(*(p+1)) == 'o' && argc > 0)
  {
    p = *++argv;
    strcpy( szOutDir, p );

    /*                      
    ** ADDEXTENSION(APSZINFILES[IINFILES], DEF_IEXT );
    */

    p = *++argv;
  }
  else
  {
    RepError( err_usage, NULL );
  }

  if (*p == '-' && tolower(*(p+1)) == 'g' && argc > 0)
  {
    p = *++argv;
    strcpy( szGeneric, p );
    AddExtension( szGeneric, DEF_IEXT );
  }
  else
  {
    RepError( err_usage, NULL );
  }

  for (i = 0; i < iInfiles; i++)
  {
    strlwr( apszInfiles[i] );
  }
  strlwr( szOutDir );
  strlwr( szGeneric );
}

/***************************************************************************
 *
 * FUNCTION NAME = SaveCommand
 *
 * DESCRIPTION   = This routine scans the parameter buffer and saves
 *                 the command within quotes in pbItemsBuffer .This
 *                 routine is written to save code.
 *
 * INPUT         = szString - pointer to string to be searched
 *
 * OUTPUT        = piOffset - pointer to variable where offset is to be
 *                            stored
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

SaveCommand(char *szString,short *piOffset)
{
  int  i, j;
  BOOL fPrnName;

  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam(szString, pbPrBuffer))
  {
    /*
    ** skip the " character
    */
    i = MovePast( pbPrBuffer, '"' );
    fPrnName =  (strcmp( szString, "*NickName" ) == 0) |
                (strcmp( szString, "*ShortNickName" ) == 0);
    *piOffset = cbBuffout;

    /*
    ** copies the string delimited by quote with ist byte as length.
    */
    j = CopyInQuote( pbItemsBuffer + cbBuffout, pbPrBuffer + i, fPrnName );
    cbBuffout += j;
  }
  else
  {
    /*
    ** Null pointer
    */
    *piOffset = -1;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = SaveProcedure
 *
 * DESCRIPTION   = This routine scans the parameter buffer and saves
 *                 the procedure within quotes in pbItemsBuffer .This
 *                 routine is written to save code.
 *
 * INPUT         = szString - pointer to string to be searched.
 *
 * OUTPUT        = piOffset - pointer to variable where offset is to be
 *                            stored.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

SaveProcedure( char *szString, short *piOffset )
{
  int i, j;

  fseek( fhIn, (long) 0, SEEK_SET );

  if (ScanProcedure( szString, pbItemsBuffer + cbBuffout ))
  {
    *piOffset = cbBuffout;
    j = *(int *)(pbItemsBuffer + cbBuffout );

    /*
    ** 2 bytes extra to take care of length
    */
    cbBuffout += ( j + 2 );
  }
  else
  {
    /*
    ** Null pointer
    */
    *piOffset = -1;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = SaveString
 *
 * DESCRIPTION   = This routine scans the parameter buffer and saves
 *                 the keyword following colon in pbItemsBuffer . This
 *                 routine is written to save code/
 *
 * INPUT         = szString - pointer to string to be searched.
 *
 * OUTPUT        = piOffset - pointer to variable where offset is to be
 *                            stored.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

SaveString( char *szString, short *piOffset )
{
  int i, j;

  fseek( fhIn, (long) 0, SEEK_SET );

  if (ScanParam( szString, pbPrBuffer ))
  {
    /*
    ** skip the " character
    */

    i = MovePast( pbPrBuffer, ':' );
    *piOffset = cbBuffout;
    i += SkipBlank(pbPrBuffer+i );

    /*
    ** copies the string delimited by a blank with ist byte as length.
    ** Strings are not null terminated
    */
    j = CopyString( pbItemsBuffer + cbBuffout, pbPrBuffer + i, 80 );
    cbBuffout += j;
  }
  else
  {
    /*
    ** Null pointer
    */
    *piOffset = -1;
  }
}

/*****************************************************************************\
**
** FUNCTION NameToIndex
**
** Will look up form in table and put index in PPB.  Adds form if not there
**
\*****************************************************************************/

SHORT NameToIndex( VOID )
{
  SHORT i;
  SHORT sNameLen;
  CHAR  acFormName[MAX_FORM_SIZE+1];       /* Buffer for found form name */
  PCH   pFormName;

  /*
  **           
  */
  sNameLen = CopyString( acFormName, pbPrBuffer, MAX_FORM_SIZE );
  acFormName[MAX_PSIZE-1] = '\0';   /* For now limit to 64 char */
  pFormName = acFormName;


  /* find form in table */

  for ( i = 0; i < sFormCount; i++ )
  {
    if ( !strcmp( pFormName, pFormTable[i] ) )
      break ;  /* Found - stop loop */
  }

  /* Warn if about to overflow table */
  if ( sFormCount == 63 )
  {
    printf( "ERROR ERROR Too many form names\n" );
    i = 0;  /* set to first form */
  }

  if ( i >= sFormCount )
  { /* Couldn't find it so add to table */
    pFormTable[ sFormCount ] = (PCH)malloc( strlen( pFormName ) + 1 );
    strcpy( pFormTable[ sFormCount ], pFormName );
    i = sFormCount++;
  }

  *(PSHORT)(pbItemsBuffer+cbBuffout) = i;

  cbBuffout += sizeof(SHORT);

  return sNameLen;
}

/*****************************************************************************\
**
** FUNCTION ProcessFormTable
**
** Writes out the form table and index
**
\*****************************************************************************/

VOID ProcessFormTable( VOID )
{
  SHORT i;
  LONG  lIndexTable[64];

  /*
  ** Do a sanity check
  */
  if ( desPpd.desPage.iCmpgpairs  != sFormCount  ||
       desPpd.desPage.iDmpgpairs  != sFormCount  ||
       desPpd.desPage.iImgpgpairs != sFormCount   )
  {
    printf( "WARNING - Mismatched forms counts: PageRegion %d, PaperDim %d, "
            "ImageableArea %d, Total Count %d\n", desPpd.desPage.iCmpgpairs,
             desPpd.desPage.iDmpgpairs, desPpd.desPage.iImgpgpairs, sFormCount );
  }

  desPpd.desForms.usFormCount  = sFormCount;  /* store form count */
  desPpd.desForms.ofsFormTable = cbBuffout;   /* store start of form table */

  /* Write out the table - it's regular null term strings */
  for ( i = 0; i < sFormCount; i++ )
  {
    lIndexTable[i] = cbBuffout;     /* Keep track of where each form goes */
    strcpy( pbItemsBuffer + cbBuffout, pFormTable[ i ] );
    free( pFormTable[ i ] );
    cbBuffout += strlen( pFormTable[ i ] ) + 1;
  }

  desPpd.desForms.ofsFormIndex = cbBuffout;   /* store start of index table */

  for ( i = 0; i < sFormCount; i++ )
  {
    *(PLONG)(pbItemsBuffer+cbBuffout) = lIndexTable[ i ];
    cbBuffout += sizeof(LONG);
  }

}
/*****************************************************************************\
**
** FUNCTION DoDefaultForm
**
** Converts the default string found by the old method to the index of a form.
** This means that desPpd.desPage.ofsDfpgsz is NOT an offset but an index value
**
\*****************************************************************************/

VOID DoDefaultForm( VOID )
{
  PBYTE ptr;
  PBYTE pImageableArea;
  SHORT sLen;
  SHORT i;
  SHORT j;
  PCH   pchSlash;
  SHORT sFirstForm;


  /* if value -1 no default form so use the first form */
  if ( desPpd.desPage.ofsDfpgsz == -1 )
  {
    desPpd.desPage.ofsDfpgsz = 0;
    printf( "INFO: No default form\n" );
    return;
  }

  ptr = pbItemsBuffer + desPpd.desPage.ofsDfpgsz;
  sLen = strlen( ptr );

  /* Point to imageable area */
  pImageableArea = pbItemsBuffer + desPpd.desPage.ofsImgblPgsz;
  sFirstForm = *((PSHORT)pImageableArea);

  /*
  **           
  */
#if 0
//  sLen = (SHORT)*ptr ;
//  ptr++;              /* point to name */
//  *(ptr+sLen) = 0;    /* NULL terminate */
#endif

  for ( j = 0; j < desPpd.desPage.iImgpgpairs; j++ )
  {

    i = *((PSHORT)pImageableArea);
    pImageableArea +=  sizeof( SHORT ) * 5;

    /*
    ** If Xlate string, block it by temp replacing slash with zero
    */
    if ( ( pchSlash = strchr( pFormTable[i], '/' ) ) )
    {
      *pchSlash = 0;
    }

    if ( !strcmp( (PCH)ptr, pFormTable[i] ) )
    {
      if ( pchSlash )
      {
        *pchSlash = '/';
      }
      break;
    }
    if ( pchSlash )
    {
      *pchSlash = '/';
    }
  }

  if ( j >= desPpd.desPage.iImgpgpairs )  /* Not found, make it zero */
  {
    i = sFirstForm;
    printf( "INFO: Default form is %s\n", ptr );
  }

  desPpd.desPage.ofsDfpgsz = i;

  cbBuffout -= sLen + 1;  /* Erase the name */

  return;
}


/***************************************************************************
 *
 * FUNCTION NAME = FormPpd
 *
 * DESCRIPTION   = To form a binary output segment out of ppd file.
 *                 Returns false if any error encountered in input
 *                 file format else returns True.
 *
 * INPUT         = NONE.
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

BOOL FormPpd( )
{
  /*
  ** D74609
  */
/* register int  i; */
  int           i;
  int           j, k;
  char         *p;
  char          scratch[64 + 1];
  SHORT         uDPIVal;     /*            */
  int           iResType;    /* QMS fix */

  /*
  ** Zero out structure
  */
  memset( &desPpd, 0, sizeof( desPpd ) );

/*SaveCommand( szSearch[password], (short *) &desPpd.desItems.ofsPswrd ); */
  desPpd.desItems.ofsPswrd = -1;

  /*
  **             SAVE THE INITSTRING IN THE .PPB FILE
  */
  /*
  ** @V3.0101290
  ** For v4.2 PPDs, JCLBegin and JCLToPSInterpreter replaces
  ** InitPostScriptMode.
  */
  SaveCommand( szSearch[initstring], (short *) &desPpd.desItems.ofsInitString );
  if (desPpd.desItems.ofsInitString == -1)
  {
    SaveCommand (szSearch[ JCLBegin ], (short *) &desPpd.desItems.ofsInitString );

    /*
    ** @V3.0115171
    ** Add a separate offset for the JCL to PS interpreter command.  Do not
    ** append it to the *JCLBegin command.  This is needed so if JCLResolution
    ** is used, this command converts the device back to Postscript.
    ** JCLResolution must be inserted between the JCLBegin and the
    ** JCL-to-PS commands.
    */
    SaveCommand( szSearch[ JCLToPSInterpreter ],
                 (short *) &desPpd.desItems.ofsJCLToPS );
#if 0
//  /*
//  ** Combine the following two strings: JCLBegin & JCLToPSInterpreter.
//  ** Decrement cbBuffout to remove the terminator between the two strings.
//  */
//  if (desPpd.desItems.ofsInitString != -1)
//  {
//    cbBuffout--;
//    SaveCommand (szSearch[ JCLToPSInterpreter ], (short *) &j );
//  }
#endif
  }

  /*
  **            SAVE THE TERMSTRING IN THE .PPB FILE
  */
  /*
  ** @V3.0101290
  ** For v4.2PPDs, JCLEnd is the command that replaces TermPostScriptMode.
  */
  SaveCommand( szSearch[termstring], (short *) &desPpd.desItems.ofsTermString );
  if (desPpd.desItems.ofsTermString == -1)
  {
    SaveCommand( szSearch[ JCLEnd ], (short *) &desPpd.desItems.ofsTermString );
  }

  /*
  ** scan and read the throughput parameter
  */
  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam( szSearch[throughput], pbPrBuffer ))
  {
    /*
    ** skip the " character
    */

    i = MovePast( pbPrBuffer, '"' );
    desPpd.desItems.iPpm = (short) atoi( pbPrBuffer + i );
  }
  else
  {
    /*
    ** Null value
    */
    desPpd.desItems.iPpm = -1;
  }

  /*
  ** scan and read the printer memory parameter
  */
  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam( szSearch[freevm], pbPrBuffer ))
  {
    /*
    ** skip the " character
    */
    i = MovePast( pbPrBuffer, '"' );
    desPpd.desItems.lFreeVM = atol( pbPrBuffer + i );
  }
  else
  {
    /*
    ** Null value
    */
    desPpd.desItems.lFreeVM = (long) -1;
  }

  /*
  ** scan and read printer type classified under product name
  */

  desPpd.desItems.ofsPrType = cbBuffout;
/*SaveCommand( szSearch[productname], (short *) &desPpd.desItems.ofsPrType );*/
  desPpd.desItems.ofsPrType = -1;

  /*
  ** scan and read printer name
  ** Try ShortNickName first
  */
  desPpd.desItems.ofsPrName = cbBuffout;
  SaveCommand( szSearch[shortnickname], (short *) &desPpd.desItems.ofsPrName );

  if ( desPpd.desItems.ofsPrName == -1 )
  {
    /*
    ** scan and read printer name
    ** Use NickName
    */
    desPpd.desItems.ofsPrName = cbBuffout;
    SaveCommand( szSearch[printername], (short *) &desPpd.desItems.ofsPrName );
  }



  /*
  ** Make sure name is not too long
  */
  /*
  **           
  */
#if 0
//  if ((short) *(pbItemsBuffer + desPpd.desItems.ofsPrName) > NAME_LEN - 1)
#endif
  if (strlen( pbItemsBuffer + desPpd.desItems.ofsPrName ) > NAME_LEN - 1)
  {
    printf( "...ERROR...ERROR...ERROR... Nickname too long\n" );
  }

  /*           
  ** Scan and read available resolutions.
  */
  desPpd.desItems.ResList.uNumOfRes  = 0;
  desPpd.desItems.ResList.uResOffset = 0;

  // @V3.0115171
  desPpd.desItems.ResList.bIsJCLResolution = FALSE;

  fseek( fhIn, (long) 0, SEEK_SET );

  /* QMS Fix
  ** Some printers (QMS) use SetJobResolution instead of SetResolution
  ** Look for SetJobResolution first
  */
  if ( ScanParam( szSearch [SetJobResolution], pbPrBuffer ) )
  {
    iResType = SetJobResolution;
  }
  else
  {
    /*
    ** @V3.0115171
    ** Query for *JCLResolution.
    */
    fseek( fhIn, (long) 0, SEEK_SET );
    if (ScanParam( szSearch[ JCLResolution ], pbPrBuffer ))
    {
      iResType = JCLResolution;
      desPpd.desItems.ResList.bIsJCLResolution = TRUE;
    }
    else
    {
      fseek( fhIn, (long) 0, SEEK_SET );
      if ( ScanParam( szSearch [Resolution], pbPrBuffer ) )
      {
        iResType = Resolution;
      }
      else
      {
        iResType = setresolution;
      }
    }
  }

  fseek( fhIn, (long) 0, SEEK_SET );

  while (ScanParam( szSearch [iResType], pbPrBuffer ))
  {
    /*
    ** Get the resolution value from the string and put it into
    ** the variable buffer.
    */
    uDPIVal = (SHORT) atoi( pbPrBuffer );
    *(unsigned *)(pbItemsBuffer + cbBuffout) =  uDPIVal;

    /*
    ** If the resolution buffer offset indicator is 0, assign it to
    ** the beginning of the resolution buffer.
    */
    if (desPpd.desItems.ResList.uResOffset == 0)
    {
      desPpd.desItems.ResList.uResOffset = cbBuffout;
    }

    /*
    ** Increment cbBuffout because two bytes are being used by
    ** the resolution value.
    ** Also, increment the varaiable that keeps track of the number
    ** of available resolutions.
    */
    cbBuffout += 2;
    desPpd.desItems.ResList.uNumOfRes++;

    /*
    ** skip the " character
    */
    i = MovePast( pbPrBuffer, '"' );

    /*
    ** copies the string delimited by a blank or quote.
    */
    j = CopyInQuote( pbItemsBuffer + cbBuffout, pbPrBuffer + i, FALSE );
    cbBuffout += j;
  }

  /*
  ** @V3.0115171
  ** Move the Default resolution processing after the standard resolution
  ** processing.  If no default resolution is provided, assign the default
  ** to the first resolution found.
  */
  /*
  ** scan and read default resolution
  */
  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam( szSearch[defaultres], pbPrBuffer ))
  {
    /*
    ** skip the : character
    */
    i = MovePast( pbPrBuffer, ':' );
    desPpd.desItems.iResDpi = (short) atoi( pbPrBuffer + i );
  }
  else
  {
    /*
    ** @V3.0115171
    ** No default found.  Assign the default to the first resolution.
    */
    /*
    ** Null value
    */
    desPpd.desItems.iResDpi =
      *((PSHORT) (pbItemsBuffer + desPpd.desItems.ResList.uResOffset));
    printf( "WARNING... No default resolution, set to %d\n",
            desPpd.desItems.iResDpi );
  }

  /*
  ** scan and read screen frequency
  */
  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam(szSearch[screenfreq], pbPrBuffer))
  {
    /*
    ** skip the : character
    */

    i = MovePast( pbPrBuffer, '"' );
    desPpd.desItems.lScrFreq = (long)(atof( pbPrBuffer + i) * 100.00 );
  }
  else
  {
    /*
    ** Null value
    */
    desPpd.desItems.lScrFreq = -1L;
  }

  /*
  ** To read the flag that indicates whether the device supports
  ** colour or not.
  */
  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam( szSearch[colordevice], pbPrBuffer ))
  {
    /*
    ** skip the " character
    */
    i = MovePast( pbPrBuffer, ':' );
    i += SkipBlank( pbPrBuffer + i );

    if (!strnicmp("TRUE", pbPrBuffer+i, 4))
    {
      desPpd.desItems.fIsColorDevice = TRUE;
    }
    else
    {
      desPpd.desItems.fIsColorDevice = NONE;
    }
  }
  else
  {
    desPpd.desItems.fIsColorDevice = NONE;
  }

  /*
  ** To read the True or False value indicating whether the Postscript
  ** device has a built in file system.
  */
  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam( szSearch[filesystem], pbPrBuffer ))
  {
    /*
    ** skip the " character
    */
    i = MovePast( pbPrBuffer, ':' );
    i += SkipBlank(pbPrBuffer + i );

    if (!strnicmp( "TRUE", pbPrBuffer + i, 4 ))
    {
      desPpd.desItems.fIsFileSystem = TRUE;
    }
    else
    {
      desPpd.desItems.fIsFileSystem = FALSE;
    }
  }
  else
  {
    desPpd.desItems.fIsFileSystem = FALSE;
  }

  /*
  ** To read the Postscript sequence that will perform a soft
  ** restart of the printer.
  */
  desPpd.desItems.ofsReset = -1;

  /*
  ** Read the appropriate postscript sequence to exit the job server loop
  */
  desPpd.desItems.ofsExitserver = -1;

  /*
  ** Read the halftone screen angle
  */
  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam( szSearch[screenangle], pbPrBuffer ))
  {
    /*
    ** skip the : character
    */
    i = MovePast( pbPrBuffer, '"' );
    desPpd.desItems.iScreenAngle = (long)(atof( pbPrBuffer + i) * 100.0 );
  }
  else
  {
    /*
    ** Null value
    */
    desPpd.desItems.iScreenAngle = -1L;
  }

/*
**           
** Remove this.  Language version is not needed.
*/
#if 0
///*
//** Read the keyword indicating the natural language used within the body
//** of the printer description file
//*/
//SaveString( szSearch[languageversion], (short *)
//            &desPpd.desItems.ofsLanguageversion );
#endif

  /*
  ** Read the value indicating whether the device supports
  ** infinitely variable paper sizes
  */
  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam( szSearch[variablepaper], pbPrBuffer ))
  {
    /*
    ** skip the " character
    */
    i = MovePast( pbPrBuffer, ':' );
    i += SkipBlank( pbPrBuffer + i );

    if (!strnicmp( "TRUE", pbPrBuffer + i, 4 ))
    {
      desPpd.desPage.fIsVariablePaper = TRUE;
    }
    else
    {
      desPpd.desPage.fIsVariablePaper = FALSE;
    }
  }
  else
  {
    desPpd.desPage.fIsVariablePaper = FALSE;
  }

  /*
  ** Read the default imageable area paper type .
  */
/*SaveString( szSearch[defimagearea], (short *)&desPpd.desPage.ofsDefimagearea );*/
  desPpd.desPage.ofsDefimagearea = -1;

  /*
  ** Read the keyword for the Default paper dimension.
  ** This value should always be letter
  */
/*SaveString( szSearch[defpaperdim], (short *)&desPpd.desPage.ofsDefpaperdim ); */
  desPpd.desPage.ofsDefpaperdim = -1;

  /*
  ** This gives the font name which is the default font provided by
  ** findfont if the requested font is not available
  */
  SaveString( szSearch[defaultfont], (short *)&desPpd.desFonts.ofsDeffont );

  /*
  ** If no default font provided make it Courier
  */
  if (desPpd.desFonts.ofsDeffont == -1)
  {
    /*
    ** Copy the default font (no ending null)
    */
    desPpd.desFonts.ofsDeffont = cbBuffout;
    *(pbItemsBuffer + cbBuffout) = sizeof( acDefFont ) - 1;
    cbBuffout++;

    for (i = 0; i < sizeof( acDefFont )-1; i++, cbBuffout++)
    {
      *(pbItemsBuffer + cbBuffout) = acDefFont[i];
    }
  }

  /*
  ** Read the complete list of page names and page select commands
  */
  fseek( fhIn, (long)0, SEEK_SET );

  /*
  ** count of pairs formed
  */
  k = 0;
  desPpd.desPage.ofsLspgCmnds = cbBuffout;

  while (ScanParam( szSearch[pageregion], pbPrBuffer))
  {
    /*
    ** Copies the string name
    */

/** i = CopyString(pbItemsBuffer+cbBuffout, pbPrBuffer, MAX_PSIZE-1 );
*** cbBuffout += i; **/

    i = NameToIndex( );   /* Change name to index */

    /*
    ** string length is one more than actual scanned
    */
    i--;

    /*
    ** skip the " character
    */
    i += MovePast( pbPrBuffer+i, '"' );

    /*
    ** copies the string delimited by a blank or quote with ist
    ** byte as length. Strings are not null terminated
    */
    j = CopyInQuote( pbItemsBuffer + cbBuffout, pbPrBuffer + i, FALSE );
    cbBuffout += j;
    k++;
  }
  desPpd.desPage.iCmpgpairs = k;

  /*
  ** Read the list of paper type supported and the associated paper sizes
  */
  fseek( fhIn, (long)0, SEEK_SET );

  /*
  ** count of pairs formed
  */
  k = 0;
  desPpd.desPage.ofsDimxyPgsz = cbBuffout;

  while (ScanParam( szSearch[pagesizelist], pbPrBuffer ))
  {
    /*
    ** copies the page name
    */
/** i = CopyString( pbItemsBuffer + cbBuffout, pbPrBuffer, MAX_PSIZE - 1 );
*** cbBuffout += i; **/

    i = NameToIndex( );   /* Change name to index */

    /*
    ** string length is one more than actual scanned
    */
    i--;

    /*
    ** warn if formname longer than 31
    */
    if (i > MAX_PSIZE - 1)
    {
      strncpy( scratch, pbItemsBuffer + cbBuffout - i, i );
      scratch[i] = (char) 0;
      printf( "...ERROR... %s\nFormname > MaxPaperSize [%d]\n", scratch, i );
    }

    /*
    ** skip the " character
    */
    i += MovePast( pbPrBuffer+i, '"' );
    j = atoRound( pbPrBuffer + i );

    /*
    ** copies the x-size into items buffer
    */
    memcpy( (pbItemsBuffer + cbBuffout), (char *) &j, sizeof( SHORT ) );
    cbBuffout += sizeof(SHORT );
    i += SkipNumber( pbPrBuffer + i );
    j = atoRound( pbPrBuffer + i );

    /*
    ** copies the y-size into items buffer
    */
    memcpy( (pbItemsBuffer + cbBuffout), (char *) &j, sizeof( SHORT ) );
    cbBuffout += sizeof( SHORT );
    k++;
  }
  desPpd.desPage.iDmpgpairs = k;


#if 0
//
///*
//** If no DefaultPageSize give use the first PaperDimension entry
//*/
//if (desPpd.desPage.ofsDfpgsz == -1 && desPpd.desPage.iDmpgpairs > 0)
//{
//  desPpd.desPage.ofsDfpgsz = cbBuffout;
//
//  /*
//  ** Get the count of bytes
//  */
//  j = *( pbItemsBuffer + desPpd.desPage.ofsDimxyPgsz );
//
//  /*
//  ** Copy the size and name
//  */
//  for (i = 0; i <= j; i++, cbBuffout++)
//  {
//    *(pbItemsBuffer+cbBuffout) = *(pbItemsBuffer+desPpd.desPage.ofsDimxyPgsz+
//       i );
//  }
//}
#endif

  /*
  ** Read the complete list of paper types and associated image coordinates
  */
  fseek( fhIn, (long)0, SEEK_SET );

  /*
  ** count of pairs formed
  */
  k = 0;
  desPpd.desPage.ofsImgblPgsz = cbBuffout;

  /*
  ** D74609
  ** *ImageableArea: value1, value2, value3, value4
  ** value1 and value2 must be rounded up.
  ** value3 and value4 must be truncated.
  */
  while (ScanParam( szSearch[imageablearea], pbPrBuffer))
  {
    /*
    ** copies the page name
    */
/** i = CopyString( pbItemsBuffer + cbBuffout, pbPrBuffer, MAX_PSIZE-1 );
*** cbBuffout += i; **/

    i = NameToIndex( );   /* Change name to index */

    /*
    ** string length is one more than actual scanned
    */
    i--;

    /*
    ** skip the " character
    */

    /*
    ** D74609
    */
    /*
    ** Bottom left X corner.
    ** Round up to nearest integer.
    */
    roundImgAreaVals( &i, ROUND_FLOAT, '"' );

    /*
    ** Bottom left y corner.
    ** Round up to nearest integer.
    */
    roundImgAreaVals( &i, ROUND_FLOAT, ' ' );

    /*
    ** Top right x corner.
    ** Truncate floating point value.
    */
    roundImgAreaVals( &i, TRUNCATE_FLOAT, ' ' );

    /*
    ** Top right y corner.
    ** Truncate floating point value.
    */
    roundImgAreaVals( &i, TRUNCATE_FLOAT, ' ' );

#if 0
//  j = (atoRound( pbPrBuffer + i) );
//
//  /*
//  ** copies the x-coord bottom left into items buffer
//  */
//
//  memcpy((pbItemsBuffer+cbBuffout), (char *)&j, sizeof(USHORT) );
//  cbBuffout += sizeof(USHORT );
//  i += SkipNumber(pbPrBuffer+i );
//  j = (atoRound(pbPrBuffer+i) );
//
//  /*
//  ** copies the y-coord bottom left into items buffer
//  */
//
//  memcpy( (pbItemsBuffer + cbBuffout), (char *)&j, sizeof(USHORT) );
//  cbBuffout += sizeof( USHORT );
//  i += SkipNumber( pbPrBuffer + i );
//  j = (atoRound( pbPrBuffer + i ) );
//
//  /*
//  ** copies the x-coord top right into items buffer
//  */
//
//  memcpy( (pbItemsBuffer + cbBuffout), (char *)&j, sizeof(USHORT) );
//  cbBuffout += sizeof(USHORT );
//  i += SkipNumber( pbPrBuffer + i );
//  j = atoRound(( pbPrBuffer + i) );
//
//  /*
//  ** copies the y-coord top right into items buffer
//  */
//
//  memcpy( (pbItemsBuffer+cbBuffout), (char *)&j, sizeof(USHORT) );
//  cbBuffout += sizeof( USHORT );
#endif
    k++;
  }
  desPpd.desPage.iImgpgpairs = k;

  /*
  ** This has been moved to after paper names have been read so we can
  ** fill in a default size if not provided.  Done in the next block below
  */
  /*
  ** Read default page size at power on :-whether letter ,A4 etc
  */

  SaveString( szSearch[defaultpsize], (short *)&desPpd.desPage.ofsDfpgsz );

  DoDefaultForm( );  /* Change default form to index value */

  /*
  ** Read the default condition of the manual feed operation.
  ** This can be used to determine the initial setting of the
  ** manualfeed operation
  */

  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam( szSearch[defmanualfeed], pbPrBuffer))
  {
    /*
    ** skip the " character
    */
    i = MovePast( pbPrBuffer, ':' );
    i += SkipBlank( pbPrBuffer + i );

    if (!strnicmp("TRUE", pbPrBuffer+i, 4))
    {
      desPpd.desInpbins.iManualfeed = TRUE;
    }
    else if (!strnicmp("NONE", pbPrBuffer+i, 4))
    {
      desPpd.desInpbins.iManualfeed = NONE;
    }
    else
    {
      desPpd.desInpbins.iManualfeed = FALSE;
    }
  }
  else
  {
    desPpd.desInpbins.iManualfeed = NONE;
  }

  /*
  ** Read the invocation string for disabling or enabling manual feed
  */

  fseek( fhIn, (long)0, SEEK_SET );

  while (ScanParam( szSearch[manualfeed], pbPrBuffer))
  {
    if (!strnicmp("TRUE", pbPrBuffer, 4))
    {
      desPpd.desInpbins.ofsManualtrue = cbBuffout;
    }
    else
    {
      desPpd.desInpbins.ofsManualfalse = cbBuffout;
    }

    /*
    ** skip the " character
    */
    i = MovePast( pbPrBuffer, '"' );

    /*
    ** copies the string delimited by a blank or quote.
    */
    j = CopyInQuote( pbItemsBuffer + cbBuffout, pbPrBuffer + i, FALSE );
    cbBuffout += j;
  }

  /*
  **          
  ** READ THE DEFAULT CONDITION OF THE DUPLEX OPTION.
  ** DUPLEX PROCESSING PUT IN BY DCR 1462
  */

  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam( szSearch[defaultduplex], pbPrBuffer))
  {
    /*
    ** skip the " character
    */

    i = MovePast( pbPrBuffer, ':' );
    i += SkipBlank( pbPrBuffer + i );

    /*
    ** no duplex available
    */

    if (!strnicmp("NONE", pbPrBuffer+i, 4))
    {
      desPpd.desItems.sDefaultDuplex = DUPLEX_NONE;
    }
    else
    {
      /*
      ** duplex avail, turned off
      */
      if (!strnicmp("FALSE", pbPrBuffer+i, 5))
      {
        desPpd.desItems.sDefaultDuplex = DUPLEX_FALSE;
      }
      else
      {
        /*
        ** duplex of some type, turn off
        */
        desPpd.desItems.sDefaultDuplex = DUPLEX_FALSE;
      }
    }
  }
  else
  {
    desPpd.desItems.sDefaultDuplex = DUPLEX_NONE;
  }

  /*
  ** Read the invocation string for disabling or enabling duplex option
  */
  fseek( fhIn, (long)0, SEEK_SET );

  while (ScanParam( szSearch[duplex], pbPrBuffer))
  {
    if (!strnicmp( "FALSE", pbPrBuffer, 5) ||
        !strnicmp( "NONE",  pbPrBuffer, 4) )
    {
      desPpd.desItems.ofsDuplexFalse = cbBuffout;
    }
    else if (!strnicmp( "DUPLEXNOTUMBLE", pbPrBuffer, 14))
    {
      desPpd.desItems.ofsDuplexNoTumble = cbBuffout;
    }
    else if (!strnicmp( "DUPLEXTUMBLE", pbPrBuffer, 12))
    {
      desPpd.desItems.ofsDuplexTumble = cbBuffout;
    }
    else
    {
      desPpd.desItems.ofsDuplexNoTumble = cbBuffout;
    }

    /*
    ** skip the " character
    */
    i = MovePast( pbPrBuffer, '"' );

    /*
    ** copies the string delimited by a blank or quote with ist byte
    ** as length. Strings are not null terminated
    */
    j = CopyInQuote( pbItemsBuffer + cbBuffout, pbPrBuffer + i, FALSE );
    cbBuffout += j;
  }

  /*
  ** Read the default value for the input slot category
  */

  SaveString( szSearch[definputslot], (short *)&desPpd.desInpbins.ofsDefinputslot );
  fseek( fhIn, (long)0, SEEK_SET );

  /*
  ** count of pairs formed
  */

  k = 0;
  desPpd.desInpbins.ofsCmInpbins = cbBuffout;

  while (ScanParam( szSearch[inputbinlist], pbPrBuffer))
  {
    /*
    ** copies the Input bin name
    */
    i = CopyString( pbItemsBuffer + cbBuffout, pbPrBuffer, 80 );
    cbBuffout += i;

    /*
    ** string length is one more than actual scanned
    */
    i--;

    /*
    ** skip the " character
    */
    i += MovePast( pbPrBuffer + i, '"' );

    /*
    ** copies the string delimited by a blank or quote.
    */
    j = CopyInQuote( pbItemsBuffer + cbBuffout, pbPrBuffer + i, FALSE );
    cbBuffout += j;
    k++;
  }
  desPpd.desInpbins.iInpbinpairs = k;

  /*
  ** Read the keyword for the default output order which can be normal
  ** or reverse
  */

  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam( szSearch[defoutputorder], pbPrBuffer))
  {
    /*
    ** skip the " character
    */
    i = MovePast( pbPrBuffer, ':' );
    i += SkipBlank( pbPrBuffer + i );

    if (!strnicmp( "NORMAL", pbPrBuffer + i, 6))
    {
      desPpd.desOutbins.fIsDefoutorder = NORMAL;
    }
    else
    {
      desPpd.desOutbins.fIsDefoutorder = REVERSE;
    }
  }
  else
  {
    desPpd.desOutbins.fIsDefoutorder = REVERSE;
  }

  /*
  ** Read the invocation strings for selecting normal or
  ** reverse output order
  */
  desPpd.desOutbins.ofsOrdernormal = -1;
  desPpd.desOutbins.ofsOrderreverse = -1;
  fseek( fhIn, (long)0, SEEK_SET );

  while (ScanParam( szSearch[outputorder], pbPrBuffer))
  {
    if (!strnicmp( "NORMAL", pbPrBuffer, 4))
    {
      desPpd.desOutbins.ofsOrdernormal = cbBuffout;
    }
    else
    {
      desPpd.desOutbins.ofsOrderreverse = cbBuffout;
    }

    /*
    ** skip the " character
    */
    i = MovePast( pbPrBuffer, '"' );

    /*
    ** copies the string delimited by a blank or quote with ist byte
    ** as length. Strings are not null terminated
    */
    j = CopyInQuote( pbItemsBuffer+cbBuffout, pbPrBuffer+i, FALSE );
    cbBuffout += j;
  }

  /*
  ** Read the printer description keyword for default output bin
  */

/*SaveString( szSearch[defoutputbin], (short *)&desPpd.desOutbins.ofsDefoutputbin );*/

  /*
  ** Read the complete procedure of Transfer Normalized & inverse
  */
  SaveProcedure( szSearch[transfernor], (short *)&desPpd.desItems.ofsTransferNor );
  SaveProcedure( szSearch[transferinv], (short *)&desPpd.desItems.ofsTransferInv );

  /*
  ** Read the invocation strings for various output bins
  */
  fseek( fhIn, (long)0, SEEK_SET );
  k = 0;

#if 0
///*
//** count of pairs formed
//*/
//desPpd.desOutbins.ofsCmOutbins = cbBuffout;
//
//
//while (ScanParam( szSearch[outputbinlist], pbPrBuffer))
//{
//  /*
//  ** copies the output bin name
//  */
//  i = CopyString( pbItemsBuffer+cbBuffout, pbPrBuffer, 80 );
//  cbBuffout += i;
//
//  /*
//  ** string length is one more than actual scanned
//  */
//  i--;
//
//  /*
//  ** skip the " character
//  */
//  i += MovePast( pbPrBuffer+i, '"' );
//
//  /*
//  ** copies the string delimited by a blank or quote with ist byte
//  ** as length. Strings are not null terminated
//  */
//
//  j = CopyInQuote( pbItemsBuffer+cbBuffout, pbPrBuffer+i, FALSE );
//  cbBuffout += j;
//  k++;
//}
#endif
  desPpd.desOutbins.iOutbinpairs = k;
  desPpd.desOutbins.ofsCmOutbins = -1;

  /*
  **           
  ** Insert the section of code that searches for the "*LanguageLevel"
  ** PostScript command.
  */
  fseek( fhIn, (long)0, SEEK_SET );

  if (ScanParam( szSearch[LanguageLevel], pbPrBuffer ))
  {
    /*
    ** Skip past the colon, spaces, and the first quote, until a numeric
    ** character is found.  The reason for the loop below is, even though
    ** the PPD specs require the PS level to be in quotes, this is not the
    ** case for all PPDs.  Since this compiler cannot assume that the
    ** level number is in quotes, it will have to continue to increment
    ** the offset until the first numeric character is found.
    */
    i = 0;
    while (*(pbPrBuffer + i) < '0' || *(pbPrBuffer + i) > '9')
    {
      i++;
    }

    /*
    ** Save the language level offset.
    */
    desPpd.desItems.usLanguageLevel = atoi( pbPrBuffer + i );
  }
  else
  {
    desPpd.desItems.usLanguageLevel = 1;
  }
  /*
  **            - end
  */

  /*
  ** Read the fonts name list supported by printer
  */

  fseek( fhIn, (long)0, SEEK_SET );

  /*
  ** count of pairs formed
  */

  k = 0;
  desPpd.desFonts.ofsFontnames = cbBuffout;

  while (ScanParam( szSearch[fontnamelist], pbPrBuffer))
  {
    /*
    ** check fontres.h to see if font is known
    */
    i = 1;

    while (FontResourceName[i] != 0)
    {
      /*
      ** since FontResourceName is far ptrs must do compare here instead
      ** of str calls
      */
      j = 0;

      while (FontResourceName[i][j] == pbPrBuffer[j])
      {
        j++;
      }

      /*
      ** names matched
      */
      if ((FontResourceName[i][j] == 0) && (pbPrBuffer[j] == ':'))
      {
        break;
      }
      i++;
    }

    /*
    ** couldn't match font
    */
    if (FontResourceName[i] == 0)
    {
      p = strchr(pbPrBuffer, ':' );
      *p = 0;
      printf( "...WARNING..WARNING..WARNING... font %s not found\n", pbPrBuffer );
      continue;
    }
    *((BYTE *)(pbItemsBuffer + cbBuffout)) = i;
    cbBuffout += 1;
    k++;
  }
  desPpd.desFonts.iFonts = k;
  ProcessFormTable();
  fclose( fhIn );
  desPpd.desItems.iSizeBuffer = cbBuffout;
  return( TRUE );
}

#if 0
///***************************************************************************
// *
// * FUNCTION NAME = bld_compare
// *
// * DESCRIPTION   = This routine is used to compare the incoming file
// *                 names for the qsort routine, allowing the build to
// *                 be independent of the order of the files in the
// *                 directory.
// *
// * INPUT         = ppszArg1
// *                 ppszArg2
// *
// * OUTPUT        = NONE.
// *
// * RETURN-NORMAL = NONE.
// * RETURN-ERROR  = NONE.
// *
// *************************************************************************   */
//
//int bld_compare( void **ppszArg1, void **ppszArg2 )
//{
//  return( strcmp( *ppszArg1, *ppszArg2) );
//}
#endif

/***************************************************************************
 *
 * FUNCTION NAME = CntInpFiles
 *
 * DESCRIPTION   = This routine opens the input list and reads the
 *                 list of ppd file names.  It stores all the file
 *                 names by allocating memory for them and saves their
 *                 pointers.  The semicolon is used as comment
 *                 delimiter, semicolons in col 1 means skip the line.
 *
 *                 Note - the list files contain the ppd name with
 *                 extension but no path.
 *
 * INPUT         = szInputList - name of file containing list of ppds.
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = count of ppd files
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

int CntInpFiles( char *szInputList )
{
  char  szPath[256];
  int   i;
  FILE *fh;
  char *p;

  i = 0;

  /*
  ** open the list file
  */
  if ((fh = fopen( szInputList, "r")) == NULL)
  {
    /*
    ** report failure
    */
    RepError( err_cantopen, szInputList );
  }

  /*
  ** read each line in the file saveing the file names
  */
  while (fgets( szPath, sizeof( szPath ) - 1, fh) != NULL)
  {
    /*
    ** check for comment
    */
    if ((p = strchr( szPath, ';' )) != NULL)
    {
      /*
      ** chop it off
      */
      *p = (char)NULL;

      /*
      ** comment marker was in col 1
      ** skip to next line
      */
      if ((p-szPath) == 0)
      {
        continue;
      }
    }
    apszInfiles[i] = malloc( strlen( szPath ) + 1 );
    strcpy( apszInfiles[i++], szPath );
  }
  return( i );
}

/***************************************************************************
 *
 * FUNCTION NAME = WriteRCFile
 *
 * DESCRIPTION   = Will write out the RC file to get the PPBs and
 *                 header into the drv.  First the type_id is #defined
 *                 to the include value The resource_id for header is
 *                 0 The rest of the resource_ids are set to 1 based
 *                 file index
 *
 * INPUT         = iFileCount - count of PPB files
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

void WriteRCFile( int iFileCount, UINT uiOutDirLen )
{
  CHAR  FileName[128];
  FILE *phOutFile;
  int   i;

  /*
  ** open the rc file
  */
  /* @V3.0104222 */
  strcpy( &szOutDir[ uiOutDirLen ], RC_FILE_NAME );
  if ((phOutFile = fopen( szOutDir, "w" )) == 0)
  {
    /*
    ** open failed
    */
    RepError( err_cantcreate, RC_FILE_NAME );
  }
  szOutDir[ uiOutDirLen ] = 0;

  /*
  ** major define statement
  */
  fprintf( phOutFile, "\n#define  ALLPDDS %d\n\n", ALLPPDS );

  /*
  ** what resource signature and directory are in
  */
  strcpy( FileName, szOutDir );
  strcat( FileName, DIRECTORY_NAME );
  fprintf( phOutFile, "RESOURCE ALLPPDS %d LOADONCALL %s\n", DIRECTORY_PPB,
           FileName );

  for (i = 0; i < iFileCount; i++)
  {
    strcpy( FileName, szOutDir );
    strcat( FileName, apszInfiles[i] );
    fprintf( phOutFile, "RESOURCE ALLPPDS %d LOADONCALL %s\n", i + 2, FileName );
  }

  /*
  ** Tack on an blank
  */
  fprintf( phOutFile, "\n" );
  fclose( phOutFile );
}




/*
** V2.191412
** New function.
*/
/***************************************************************************
 *
 * FUNCTION NAME = VerifyPPDLineSize
 *
 * DESCRIPTION   = Since a PPD line with a quoted value may exceed one
 *                 physical file line, it is important to verify that the
 *                 current PPD line that is being read does not exceed the
 *                 buffer.  If the PPD line does exceed the buffer, the
 *                 compiler is not equipped to handle oversized lines, so the
 *                 specific command must be ignored.
 *                 This function verifies that the line does not exceed the
 *                 buffer by searching for both starting and ending quotes of
 *                 the quoted value.  If the starting quote exists, the value
 *                 is a quoted value and the function searches for the ending
 *                 quote.  If an ending quote is found, the line does not
 *                 exceed the buffer.  If an ending quote is not found, the
 *                 line exceeds the buffer and the function returns an error.
 *
 * INPUT         = pBuffer - Pointer to buffer containing current PPD line.
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = TRUE - Buffer does not exceed IBUFFSIZE bytes.
 * RETURN-ERROR  = FALSE - Buffer exceeds IBUFFSIZE bytes.
 *
 *************************************************************************   */
BOOL VerifyPPDLineSize( PCHAR pBuffer )
{
  UINT uiLoop1;
  UINT uiLoop2;
  BOOL bRC = TRUE;

  /*
  ** Search for the first quote.
  */
  for (uiLoop1 = 0 ; uiLoop1 < IBUFFSIZE ; uiLoop1++)
  {
    if (*(pBuffer + uiLoop1) == '"')
    {
      break;
    }
  }

  /*
  ** In the above loop, if uiLoop1 is IBUFFSIZE, it could not find a starting
  ** quote.  Otherwise, a starting quote was found so find the ending quote.
  */
  if (uiLoop1 < IBUFFSIZE)
  {
    for (uiLoop2 = uiLoop1 + 1 ; uiLoop2 < IBUFFSIZE ; uiLoop2++)
    {
      if (*(pBuffer + uiLoop2) == '"')
      {
        break;
      }
    }

    /*
    ** If uiLoop2 equals IBUFFSIZE, no ending quote was found.  The buffer
    ** was exceeded.
    */
    if (uiLoop2 == IBUFFSIZE)
    {
      /*
      ** Since this compiler passes the PPD file for each command, if a
      ** specific command exceeded the buffer, an error will be generated for
      ** each pass.  Rather than display the same error for each pass, display
      ** the error for the first pass only.
      */
      if (BErrorWasDisplayed == FALSE)
      {
        strtok( pBuffer, " " );
        /*
        **           
        ** Change "ERROR" to "INFO".  This was confusing the build group.
        ** They were thinking that an error occurred and that the build was
        ** not successful.
        */
        printf( "INFO - Command %s, line exceeds maximum buffer size of %u K.\nThis line is ignored.\n",
                pBuffer, IBUFFSIZE );
      }
      BErrorWasDisplayed = TRUE;
      bRC = FALSE;
    }
  }

  return( bRC );
}





/***************************************************************************
 *
 * FUNCTION NAME = main
 *
 * DESCRIPTION   = Function Mainline
 *
 *
 * INPUT         = argc - count of commandline arguments
 *                 argv - array of pointers to commandline arguments
 *
 * OUTPUT        = NONE.
 *
 * RETURN-NORMAL = NONE.
 * RETURN-ERROR  = NONE.
 *
 *************************************************************************   */

main( int argc, char **argv )
{
  int   j;
  int   i;
  int   iPPBCount;
  long  lResNum;
  char *pc;
  UINT  uiOutDirLen;

  GetArgs( argc, argv );

  /*
  ** if there is one input file specified
  */
  if (iInfiles == 1)
  {
    iInfiles = CntInpFiles( apszInfiles[0] );
  }

  if (iInfiles == 0)
  {
    RepError( err_cantopen, NULL );
  }

  /*
  **           
  ** Add error checking to make sure that the number of PPD files in the
  ** list does not exceed the maximum amount of PPDs allowed by the
  ** compiler.
  */
  if (iInfiles > MAX_INPUT)
  {
    RepError( err_maxPPDs, NULL );
  }

  /*
  ** create the output file so that ppd segments can be written onto it
  */
  i = 0;

  /*
  ** allocate memory for directory segment
  */
  if ((pbDirBuffer = malloc(ofsOutfile = (long)(iInfiles+1)*DRENTRYSIZE)) ==
     NULL)
  {
    RepError( err_cantopen, NULL );
  }

  /*
  ** fill with zeros
  */
  memset( pbDirBuffer, 0, ofsOutfile );

  /*
  ** allocate memory for items buffer
  */

  if ((pbItemsBuffer = malloc(PRBUFSZ *2)) == NULL)
  {
    RepError( err_cantopen, NULL );
  }
  psigFile = (SIGNATURE *)pbDirBuffer;

  /*
  ** get the printer name of generic printer
  */
  if (!Openppd( szGeneric ))
  {
    RepWarning( err_cantopen, szGeneric );
    return;
  }

  if (!FormPpd())
  {
    RepWarning( err_cantopen, szGeneric );
    return;
  }

  /*
  **           
  */
  strcpy( (char *) psigFile, pbItemsBuffer + desPpd.desItems.ofsPrName );

#if 0
//  j = (int) * (pbItemsBuffer + desPpd.desItems.ofsPrName );
//  memcpy( (char *) psigFile, pbItemsBuffer+desPpd.desItems.ofsPrName+1, j );
//  *((char *) psigFile + j) = '\0';
#endif

  memcpy( (char *) psigFile+40, (char *) &iInfiles, sizeof(USHORT) );
  pdrTblEntry = (DRENTRY *) (pbDirBuffer + DRENTRYSIZE );
  cbBuffout = 0;

  /* V3.0104222 */
  uiOutDirLen = strlen( szOutDir );
  while (i < iInfiles)
  {
    while (!Openppd(apszInfiles[i]))
    {
      RepWarning( err_cantopen, apszInfiles[i] );
      i++;
    }

    sFormCount = 0; /* init for each ppd */
    /*
    ** Parse and create the PPD segment
    */
    BErrorWasDisplayed = FALSE;
    if (FormPpd())
    {
      /*
      ** Create a ppb for each ppd file
      */
      /* @V3.0104222 */
      RemoveExtension( apszInfiles[i] );
      AddExtension( apszInfiles[i], DEF_OEXT );
      strcpy( &szOutDir[ uiOutDirLen ], apszInfiles[ i ] );
      fhOut = fopen( szOutDir, "w+b" );

      if (!fhOut)
      {
        RepError( err_cantcreate, apszInfiles[i] );
      }

      /*
      ** write the printer descriptor segment onto output file
      */
      if (fwrite( (char *) &desPpd,1,sizeof( desPpd ),fhOut) != sizeof(desPpd))
      {
        RepError( err_output, NULL );
      }

      /*
      ** store the resource number (i+1)
      */

      lResNum = i+2;
      memcpy( (char *)pdrTblEntry+MAX_FNAMESIZE, (void *)&lResNum, sizeof(long) );

      /*
      ** write the items buffer which contain various names ,commands and
      ** dimensions lists
      */
      if (fwrite( pbItemsBuffer, 1, cbBuffout, fhOut) != cbBuffout )
      {
        RepError( err_output1, NULL );
      }
      cbBuffout = 0;

      /*
      **           
      */
      strcpy( (char *) pdrTblEntry, pbItemsBuffer + desPpd.desItems.ofsPrName );
#if 0
//    j = min((int)*(pbItemsBuffer + desPpd.desItems.ofsPrName), MAX_FNAMESIZE - 1 );
//    memcpy( (char *)pdrTblEntry, pbItemsBuffer + desPpd.desItems.ofsPrName+1, j );
//    *((char *)pdrTblEntry+j) = '\0';
#endif

      pc = (char *)pdrTblEntry;
      pc += DRENTRYSIZE;
      pdrTblEntry = (DRENTRY *)pc;

      /*
      ** Close the ppb
      */
      fclose( fhOut );
    }
    i++;
  }
  /* @V3.0104222 */
  szOutDir[ uiOutDirLen ] = 0;
  memcpy( (char *)psigFile+40+sizeof(USHORT), (char *)&i, sizeof(USHORT) );
  iPPBCount = i;

  /*
  ** Write out directory
  */
  /* @V3.0104222 */
  strcpy( &szOutDir[ uiOutDirLen ], DIRECTORY_NAME );
  fhOut = fopen( szOutDir, "w+b" );
  szOutDir[ uiOutDirLen ] = 0;

  if (!fhOut)
  {
    RepError( err_cantcreate, DIRECTORY_NAME );
  }
  i = (iInfiles + 1) * DRENTRYSIZE;

  if (fwrite( (char *)psigFile,1,(unsigned)i,fhOut) != i)
  {
    RepError( err_output2, NULL );
  }
  WriteRCFile( iPPBCount, uiOutDirLen );

  /*
  ** release all the allocated memory
  */
  FreeAll( );
  fclose( fhOut );
}
