/*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 = MAKEVECT.C
 *
 * DESCRIPTIVE NAME = CREATE VECTOR TABLE
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : This module creates the vector table used in
 *               prdevect.c to dispatch to the driver's functions.
 *               The table generated also contains the parameter
 *               count for each of the hookable Gre functions so
 *               that the display driver's hdc can be substituted
 *               for the one passed to the driver in the case that
 *               the DC type is a memory DC.
 *
 *
 * FUNCTIONS :   SkipWhite
 *               szIsPrefix
 *               szCopy
 *               szIsEqual
 *               FindFunction
 *               LoadParamCounts
 *               exit
 *               LoadSyms
 *               PrintDefFile
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_DOS
#include <os2.h>
#include <stdlib.h>
#include <stdio.h>
char szOutFile[] = "inc\\prdvect.h";

typedef struct _tabSYM
{
  int nParams;                         /* The number of parameters to the
                                          function                          */
  char szFunction[80];                 /* The base-name of the Gre function */
  char *pszDriverFunction;             /* Ptr to the driver's function name */
} SYM;

char szInput[512];                     /* The input line buffer             */
int nGreMax = 0;                       /* The maximum Gre index for
                                          hookable functions                */
FILE *stmIn;                           /* Input file stream pointer         */
FILE *stmOut;                          /* Output file stream pointer        */

/* The symbol table.*/
SYM asym[256];

/* The following array of strings contain typedefs that will
 * be inserted into the output "include" file.  This structure
 * is the typedef for the dispatch/parameter count vector table */
char *aszType[] =
{
  "typedef struct",               "    {",        "    PFNL pfnl;",
  "    int nParams;",       "    } VCTD,  *PVCTD;",      NULL
} ;

/* The following table of strings contain the names of the
 * driver functions that we wish to hook out.  The name must
 * match the corresponding Gre function name exaction starting
 * at the first character past the underscore. */
char *aszHookTable[] =
{
        "prdg_AccumulateBounds",
        "prdg_ResetBounds",
        "prdg_GetBoundsData",
        "prdg_NotifyTransformChange",
        "prdg_GetDCOrigin",
        "prdg_DeviceSetDCOrigin",
        "prdg_Death",
        "prdg_Resurrection",
        "prdg_LockDevice",
        "prdg_UnlockDevice",
        "prdg_ErasePS",

        "prdl_PolyLine",
        "prdl_GetCurrentPosition",
        "prdl_SetCurrentPosition",
        "prdl_PolySpline",
        "prdl_PolyFilletSharp",
        "prdl_PolyFillet",
        "prdl_BoxBoundary",
        "prdl_BoxInterior",
        "prdl_BoxBoth",
        "prdl_FullArcBoundary",
        "prdl_FullArcInterior",
        "prdl_FullArcBoth",
        "prdl_SetLineOrigin",
        "prdl_GetLineOrigin",

        "prdl_BeginPath",
        "prdl_EndPath",
        "prdl_BeginArea",
        "prdl_EndArea",
        "prdl_CloseFigure",
        "prdl_FillPath",
        "prdl_ModifyPath",
        "prdl_StrokePath",
        "prdl_SavePath",
        "prdl_RestorePath",
        "prdl_SelectClipPath",
        "prdl_NotifyClipChange",

        "prdl_SetStyleRatio",
        "prdl_DrawLinesInPath",
        "prdl_OutlinePath",

        "prdb_DeviceCreateBitmap",
        "prdb_DeviceDeleteBitmap",
        "prdb_DeviceSelectBitmap",
        "prdb_GetPel",
        "prdb_SetPel",
        "prdb_ImageData",
        "prdb_Bitblt",

     /* "prdb_GetBitmapParameters",  This function no longer exists*/
        "prdb_GetBitmapBits",
        "prdb_SetBitmapBits",
        "prdb_SaveScreenBits",
        "prdb_RestoreScreenBits",
        "prdb_ScrollRect",
        "prdb_PolyMarker",
        "prdt_CharStringPos",
        "prdt_QueryTextBox",
        "prdt_CharString",
        "prdt_QueryCharPositions",

     /* "prda_QueryKerning",           This function no longer exists
      * "prda_EnableKerning",          This function no longer exists */
        "prda_DeviceGetAttributes",
        "prda_GetPairKerningTable",
        "prda_QueryWidthTable",
        "prda_DeviceSetAttributes",
        "prda_DeviceSetGlobalAttribute",
        "prda_RealizeFont",
        "prda_DeviceQueryFontAttributes",
        "prda_DeviceQueryFonts",
        "prda_GetCodePage",
        "prda_SetCodePage",
        "prdc_QueryColorData",
        "prdc_QueryLogColorTable",
        "prdc_CreateLogColorTable",
        "prdc_RealizeColorTable",
        "prdc_UnrealizeColorTable",
        "prdc_QueryRealColors",
        "prdc_QueryNearestColor",
        "prdc_QueryColorIndex",
        "prdc_QueryRGBColor",
        "prdq_QueryDeviceBitmaps",
        "prdq_QueryDeviceCaps",
        "prdq_Escape",
        "prdq_QueryHardcopyCaps",

        /*         * PTR OSDD B734791  start of new hooks */
        "prdd_CharRect",
        "prdd_CharStr",
        "prdd_DeviceInvalidateVisRegion",
        "prdd_DeviceSetAVIOFont",
        "prdd_DeviceSetCursor",
        "prdd_GetPickWindow",
        "prdd_GetStyleRatio",
        "prdd_SetColorCursor",
        "prdd_SetPickWindow",
        "prdd_UpdateCursor",

        /*         * PTR OSDD B734791  end of hooks */

        NULL
};

/* Forward declarations for functions */
char *SkipWhite (char *);
BOOL szIsPrefix (char *, char *);
void szCopy (char *, char *, int);
BOOL szIsEqual (char *, char *);
SYM *FindFunction (char *);
void LoadParamCounts ();
void exit (int);
void LoadSyms ();
void PrintDefFile ();

/***************************************************************************
 *
 * FUNCTION NAME =  SkipWhite
 *
 * DESCRIPTION   =  This function skips white space, returning
 *                  a pointer to the first non-white character.
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = Pointer to first non-white character.
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

char *SkipWhite(char *psz)
{
  while (*psz == ' ' || *psz == '\t')
  {
    ++psz;
  }
  return (psz);
}


/***************************************************************************
 *
 * FUNCTION NAME =  szIsPrefix
 *
 * DESCRIPTION   =  This function returns TRUE or FALSE depending
 *                  on whether or not the first string is a prefix
 *                  of the second string.
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE if first string is a prefix else FALSE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL szIsPrefix (char *pszPrefix, char *pszSrc)
{
  while (*pszPrefix)
  {
    if (*pszPrefix++ != *pszSrc++)
    {
      return (FALSE);
    }
  }
  return (TRUE);
}


/***************************************************************************
 *
 * FUNCTION NAME =  szCopy
 *
 * DESCRIPTION   =  This function copies a string to a destination
 *                  buffer while checking the size of the buffer
 *                  to make sure that overflow doesn't occur.
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE if first string is a prefix else FALSE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

void szCopy (char *pbDst, char *pbSrc, int nb)
{
  --nb;

  while (--nb >= 0)
  {
    if (!(*pbDst++ = *pbSrc++))
    {
      return;
    }
  }
  *pbDst = 0;
}


/***************************************************************************
 *
 * FUNCTION NAME =  szIsEqual
 *
 * DESCRIPTION   =  This function compares two strings and returns
 *                  TRUE if identical, FALSE otherwise.
 *
 * INPUT         = psz1
 *                 psz2
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE if identical - FALSE otherwise
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL szIsEqual (char *psz1, char *psz2)
{
  while (*psz1)
  {
    if (*psz1++ != *psz2++)
    {
      return (FALSE);
    }
  }
  return (*psz1 == *psz2);
}


/***************************************************************************
 *
 * FUNCTION NAME =  FindFunction
 *
 * DESCRIPTION   =  Search for a function name in symbol table and
 *                  return a pointer to symbol information if it's
 *                  found, otherwise return NULL.
 *
 * INPUT         = psz
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = Pointer to symbol if found - NULL if not found
 *
 * RETURN-ERROR  = NONE
 **************************************************************************/

SYM *FindFunction (char *psz)
{
  static int iPrevSym = 0;
  int        i;

  /*
  ** Assume that the input file is sorted in order of ascending
  ** function numbers.  This speeds up the seach time since we
  ** can start searching for the current symbol at one slot
  ** past the previous one in the symbol table.
  */
  for (i = iPrevSym + 1 ; i <= nGreMax ; ++i)
  {
    if (szIsEqual (psz, asym[i].szFunction))
    {
      iPrevSym = i;
      return (&asym[i]);
    }
  }

  /* If the symbol wasn't fond, go back to the beginning of the
  ** symbol table and search the remainder of the table.
  */
  for (i = 0 ; i <= iPrevSym ; ++i)
  {
    if (szIsEqual(psz, asym[i].szFunction))
    {
      iPrevSym = i;
      return (&asym[i]);
    }
  }

  return (NULL);
}


/***************************************************************************
 *
 * FUNCTION NAME =  LoadParamCounts
 *
 * DESCRIPTION   = This function scans the input file and determines the
 *                 number of parameters that each of the hookable functions
 *                 takes.  This information is loaded into the symbol table.
 *
 * INPUT         = szInfile
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 **************************************************************************/

void LoadParamCounts (char *szInFile)
{
  char *psz;
  char *pszDst;
  char  szFunction[80];
  int   nb;
  int   nParams;
  SYM  *pSym;

  /* Open the input file containing the Gre definitions.*/
  stmIn = fopen(szInFile, "r");
  if (!stmIn)
  {
    printf ("can't open %s\n", szInFile);
    exit (1);
  }

  /* Read in each line of the input file and scan it looking
  ** for function declarations in the form "#define GreFoo()"
  ** If such a declaration is found, then the number of commas
  ** in the parameter list are counted and the parameter count
  ** is entered into the corresponding symbol table entry.
  */
  while (fgets (szInput, sizeof (szInput), stmIn))
  {
    psz = szInput;
    psz = SkipWhite (psz);
    if (!szIsPrefix ("#define", psz))
    {
      continue;
    }
    psz += 7;                          /* Skip "#define"                    */
    psz = SkipWhite (psz);              /* Skip trailing white space         */
    if (!szIsPrefix ("Gre", psz))
    {
      continue;
    }

    /*
    ** Skip the "Gre" prefix.
    */
    psz += 3;

    /*
    ** Copy the function name into a seperate buffer so that
    ** it can be used in a symbol table look-up.
    */
    nb = sizeof(szFunction) - 1;
    pszDst = szFunction;

    while (--nb >= 0)
    {
      if (*psz == 0 || *psz == '(')
      {
        break;
      }
      *pszDst++ = *psz++;
    }
    *pszDst = 0;

    /*
    ** Lookup the function name in the symbol table so that the
    ** parameter count can be stored.
    */
    pSym = FindFunction (szFunction);

    /*
    ** If the function isn't found then it isn't a hookable
    ** function, so we go on to the next symbol.
    */
    if (!pSym)
    {
      continue;
    }

    /*
    ** Skip any white space between the function name and the
    ** opening parenthesis.
    */
    psz = SkipWhite (psz);

    /*
    ** If there is an opening parenthesis, then count the
    ** number of commas enclosed in them to get the parementer
    ** count.
    */
    nParams = 0;
    if (*psz == '(')
    {
      nParams = 1;
      ++psz;
      while (*psz != '\0' && *psz != ')')
      {
        if (*psz == ',')
        {
          ++nParams;
        }
        ++psz;
      }

      /*
      ** Adjust parameter count for pddc, ifn
      */
      nParams += 2;
    }
    pSym->nParams = nParams;
  }
  fclose (stmIn);
}


/***************************************************************************
 *
 * FUNCTION NAME =  LoadSyms
 *
 * DESCRIPTION   = Seach through the input file looking for Gre function
 *                 numbers that are in the proper range for hookable
 *                 functions and enter those function names into the
 *                 symbol table.
 *
 * INPUT         = szInfile
 *
 * OUTPUT        = symbol Table
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 **************************************************************************/

void LoadSyms (char *szInFile)
{
  char  szFunction[80];
  int   nGre;
  char *psz;
  int   nb;
  SYM  *psym;

  nGreMax = 0;

  /*
  ** Open the input file containing the Gre definitions.
  */
  stmIn = fopen (szInFile, "r");
  if (!stmIn)
  {
    printf ("can't open %s\n", szInFile);
    exit (1);
  }

  /*
  ** Loop to read in each line of input.
  */
  while (fgets (szInput, sizeof (szInput), stmIn))
  {
    psz = szInput;
    psz = SkipWhite (psz);
    if (!szIsPrefix ("#define", psz))
    {
      continue;
    }
    psz += 7;
    psz = SkipWhite (psz);

    if (!szIsPrefix ("NGre", psz))
    {
      continue;
    }
    psz += 4;

    /*
    ** Scan in the function name.
    */
    sscanf (psz, "%s%n", szFunction, &nb);
    psz += nb;

    /*
    ** Scan in the Gre function number.
    */
    sscanf (psz, "%i%n", &nGre, &nb);
    psz += nb;

    /*
    ** Check to make sure that the Gre function number is in
    ** the correct range for a hookable function.
    */
    if (nGre & 0x200)
    {
      continue;
    }

    if (nGre < 0x4000)
    {
      continue;
    }

    /*
    ** Keep only the least signifigant 8 bits of the function
    ** number as an index into the symbol table.
    */
    nGre &= 0x0ff;

    if (nGre > nGreMax)
    {
      nGreMax = nGre;
    }

    /*
    ** Store the function name in the symbol table.
    */
    psym = &asym[nGre];
    if (psym->szFunction[0] != '\0')
    {
      printf ("Function index conflict:\n");
      printf ("    %s\n", psym->szFunction);
      printf ("    %s\n", szFunction);
      exit (1);
    }
    szCopy (psym->szFunction, szFunction, sizeof (psym->szFunction));
  }
  fclose (stmIn);
}


/***************************************************************************
 *
 * FUNCTION NAME =  PrintDefFile
 *
 * DESCRIPTION   = Print the output "include" file that will contain the
 *                 vector table and related definitions.
 *
 * INPUT         = NONE
 *
 * OUTPUT        = File containing Gre definitions
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 **************************************************************************/

void PrintDefFile ()
{
  char **ppsz;
  char  *pszDriver;
  char  *pszEngine;
  SYM   *psym;
  int    i;

  /*
  ** Open the output file containing the Gre definitions.
  */
  stmOut = fopen (szOutFile, "w+");
  if (!stmOut)
  {
    printf ("can't open %s\n", szOutFile);
    exit (1);
  }
  fprintf (stmOut, "/********************************************/\n");
  fprintf (stmOut, "/* This file is automatically generated by  */\n");
  fprintf (stmOut, "/* the utility \"makevect.c\"                 */\n");
  fprintf (stmOut, "/********************************************/\n");
  fprintf (stmOut, "\n");

  /*
  ** Install the driver function name into the symbol table.
  */
  ppsz = aszHookTable;
  while (*ppsz)
  {
    pszDriver = *ppsz++;
    pszEngine = pszDriver;
    while (*pszEngine)
    {
      if (*pszEngine == '_')
      {
        ++pszEngine;
        break;
      }
      ++pszEngine;
    }
    psym = FindFunction (pszEngine);

    if (!psym)
    {
      printf ("%s not found or not hookable.\n", pszDriver);
      exit (1);
    }
    psym->pszDriverFunction = pszDriver;
  }

  /*
  ** Issue forward declarations for the driver functions that
  ** will be dispatched to.
  */
  ppsz = aszHookTable;
  while (*ppsz)
  {
    fprintf (stmOut, "ULONG   %s();\n", *ppsz++);
  }
  fprintf (stmOut, "\n");

  /*
  ** Issue the typedef for the dispatch table structure.
  */
  ppsz = aszType;
  while (*ppsz)
  {
    fprintf (stmOut, "%s\n", *ppsz++);
  }
  fprintf (stmOut, "\n");

  /*
  ** Define the size of the dispatch table.
  ** This is the maximum NGRE value for hookable functions.
  */
  fprintf (stmOut, "#define NGREMAX %d\n", nGreMax);
  fprintf (stmOut, "\n");

  /*
  ** Issue the dispatch table.
  */
  fprintf (stmOut, "VCTD avctd[NGREMAX+1] =\n");
  fprintf (stmOut, "    {\n");

  for (i = 0 ; i <= nGreMax ; ++i)
  {
    if (asym[i].pszDriverFunction)
    {
      fprintf(stmOut, "        {%s, %d}", asym[i].pszDriverFunction, asym[i].nParams);
    }
    else
    {
      fprintf(stmOut, "        {NULL, %d}", asym[i].nParams);
    }

    if (i < nGreMax)
    {
      fprintf (stmOut, ",\n");
    }
    else
    {
      fprintf(stmOut, "\n");
    }
  }
  fprintf (stmOut, "    };");
  fclose (stmOut);
}


void main (int argc, char **argv)
{
  argc--;
  argv++;

  if (argc)
  {
    LoadSyms (argv[0]);
    LoadParamCounts (argv[0]);
    PrintDefFile ();
  }
  else
    printf ("no input file specified\n");
}
