Newer
Older
ubixos / src / tools / build_isa_pnp_files.c
/*
   "build_isa_pnp_files.c"

   created by: grayspace aka J. Leveille
   for: UbixOS Project
   date: July 7, 2002

   purpose: - tool to create the necessary source files
            for ISAPNP devices based on certain configuration files
            - built and run by the makefile for the kernel (eventually)

   NOTES: kinda hacky for now, but hey! it's only an intermediary tool!

   $Id$
*/

// dependancy
#include "../grayspace-misc/gsdefines.h"
#include "../sys/include/deviceman/bus_resources.h"
#include "../sys/include/deviceman/device.h"
#include "make_kernel_string_pool.h"
#include "build_isa_pnp_files.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define CLASS_NAME_CHARS   (31)
#define DEVDESC_MAX_CHARS  (255)
#define DEVID_CHARS        (7)

typedef struct tagISAPNP_TEMP_INFO
{
   // device ID in string form
   char a_IDstr[DEVID_CHARS + 1];

   // device description in string form
   char a_desc[DEVDESC_MAX_CHARS + 1];

   // device class in string form
   char a_class[CLASS_NAME_CHARS + 1];
}
ISAPNP_TEMP_INFO;

// current temporary info
ISAPNP_TEMP_INFO * g_p_infos = NULL;
int g_numinfos = 0;

static void FreeInfos()
{
   if( g_p_infos )
   {
      free( g_p_infos );
      g_p_infos = NULL;
   }
   g_numinfos = 0;
}

static void FreeAll()
{
   FreeInfos();
   MakeKSP_ResetAll();
}

static void AllocateInfos( int numinfos )
{
   FreeInfos();
   g_p_infos = malloc( sizeof(ISAPNP_TEMP_INFO) * numinfos );
}

#define LINEBUFFCHARS   (  (  CLASS_NAME_CHARS\
                              + DEVDESC_MAX_CHARS\
                              + CLASS_NAME_CHARS\
                              + 3                  ) * 2 )

/* HACK */
const static char * g_ap_validclassnames[] =
{
   DEVICE_CLASS_GENERIC_IDSTR,
   DEVICE_CLASS_SOUND_DAC_IDSTR,
   DEVICE_CLASS_VIDEO_IDSTR,
   DEVICE_CLASS_NIC_IDSTR,
   DEVICE_CLASS_DISK_CTLR_IDSTR,
   DEVICE_CLASS_DISK_IDSTR
};

#define NUMCLASSNAMES   (sizeof(g_ap_validclassnames)/sizeof(char *))

static int ClassNameValid( const char * p_name )
{
   int i;
   for( i = 0; i < NUMCLASSNAMES; i++ )
   {
      if( strcmp( p_name, g_ap_validclassnames[i] ) )
      {
         return 1;
      }
   }

   return 0;
}

const static char g_whitespace[] = " \t\n";
const static char g_classdelimit[] = ";\n";

// returns number of non-white space chars remaining
static int RemoveWhiteSpace( char * p_str )
{
   char buff[LINEBUFFCHARS + 1];
   char * p_curchar;
   int numnonwhitechars;

   p_curchar = p_str;
   numnonwhitechars = 0;

   // skip past leading white space
   while(   *p_curchar != 0
            && (  *p_curchar == '\t'
                  || *p_curchar == ' ' )  )
   {
      p_curchar++;
   }

   // copy string with no white space to 'buff'
   strcpy( buff, p_curchar );

   // go to last char
   p_curchar = buff + (strlen(buff) - 1);

   // if string non empty, NULL terminate buff after last non-whitespace char
   if( p_curchar >= buff )
   {
      // non empty
      while( *p_curchar == '\t'
             || *p_curchar == ' '   )
      {
         p_curchar--;
      }
      p_curchar++;

      if( p_curchar > buff )
      {
         // non empty will remain
         *p_curchar = 0;

         // copy back to original string
         strcpy( p_str, buff );

         // return characters remaining
         return strlen( p_str );
      }
   }

   // empty string remains
   return 0;
}

static int FillInfo( ISAPNP_TEMP_INFO * p_infos,
                     int idx,
                     char * p_line,
                     int linenum                )
{
   char * p_curbuff;
   ISAPNP_TEMP_INFO * p_i;

   // get current info
   p_i = p_infos + idx;

   // extract pnp ID
   p_curbuff = p_line;
   p_curbuff = strtok( p_curbuff, g_whitespace );
   if( !p_curbuff )
   {
      // empty line
      return 0;
   }

   if( *p_curbuff == ';' || *p_curbuff == '#' )
   {
      // comment
      return 0;
   }

   if( strlen( p_curbuff ) == DEVID_CHARS )
   {
      // device ID string ok
      // TODO: parse more thoroughly
      strcpy( p_i->a_IDstr, p_curbuff );

      // fetch everything up until the class name delimiter
      p_curbuff = strtok( NULL, g_classdelimit );

      if( p_curbuff )
      {
         // copy description
         if( strlen( p_curbuff ) <= DEVDESC_MAX_CHARS )
         {
            strcpy( p_i->a_desc, p_curbuff );
         }
         else
         {
            printf( "[FillInfo], Warning, device description too long in line: %d, Ignoring.\n", linenum );
            return 0;
         }

         // trim it's whitespace
         RemoveWhiteSpace( p_i->a_desc );

         // fetch the class id:
         p_curbuff = strtok( NULL, g_whitespace );

         if( p_curbuff )
         {
            if( ClassNameValid( p_curbuff ) )
            {
               // copy it
               strcpy( p_i->a_class, p_curbuff );
            }
            else
            {
               printf( "[FillInfo], Warning, invalid device class in line: %d, Ignoring.\n", linenum );
               return 0;
            }
         }
         else
         {
            printf( "[FillInfo], Warning, missing device class in line: %d, Assuming Generic.\n", linenum );
           
               // fill class as generic
            strcpy( p_i->a_class, DEVICE_CLASS_GENERIC_IDSTR );
         }
      }

      // success
      return 1;
   }

   printf( "[FillInfo], Warning, invalid PNP-ID in line: %d, Ignoring.\n", linenum );
   return 0;
}

static int ReadInConfigFile( const char * p_path )
{
   FILE * p_file;
   int numlines;
   int linenum;
   char buff[LINEBUFFCHARS + 1];

   // open the file
   if( !(p_file = fopen( p_path, "rt" )) )
   {
      printf( "[ReadInConfigFile] Error, cannot open file: %s.\n", p_path );
      return 0;
   }

   // count our maximum number of descriptions

   // go to beginning of file
   if( fseek( p_file, 0L, SEEK_SET ) )
   {
      goto failbail;
   }

   // count our lines:
   numlines = 0;
   while( fgets( buff, LINEBUFFCHARS, p_file ) != NULL )
   {
      numlines++;
   }

   // (re)allocate our infos
   AllocateInfos( numlines );

   // fill our infos

   // go to beginning of file
   if( fseek( p_file, 0L, SEEK_SET ) )
   {
      goto failbail;
   }

   // read each line as info if possible
   g_numinfos = 0;
   linenum = 0;
   while( fgets( buff, LINEBUFFCHARS, p_file ) != NULL )
   {
      if( FillInfo( g_p_infos, g_numinfos, buff, linenum ) )
      {
         g_numinfos++;
      }
      linenum++;
   }

   // close file
   fclose( p_file );

   if( g_numinfos )
   {
      // success
      return 1;
   }

failbail:
   // close file
   fclose( p_file );
   // free infos
   FreeInfos();
   printf( "[ReadInConfigFile] Error parsing file: %s.\n", p_path );
   return 0;
}

static int WriteDescriptionStringsFile( const char * p_path )
{
   FILE * p_file;
   int i;

   // open the file
   if( !(p_file = fopen( p_path, "wt" )) )
   {
      printf( "[ReadInConfigFile] Error, cannot open file: %s.\n", p_path );
      return 0;
   }

   // write out every description line
   for( i = 0; i < g_numinfos; i++ )
   {
      if( fputs( g_p_infos[i].a_desc, p_file ) != EOF )
      {
         if( fputs( "\n", p_file ) != EOF )
         {
            continue;
         }
      }

      goto failbail;
   }

   // success:
   return 1;

failbail:
   // close file
   fclose( p_file );
   printf( "[WriteDescriptionStringsFile] Error, cannot write to file\n" );
   return 0;
}

static int RegisterSubStrings(   const char * p_dstpath,
                                 const char * p_srcpath  )
{
   // HACK: create for now as well
   if( Create_SubStringFile( p_dstpath ) )
   {
      if( Add_SubStringsFromFile( p_srcpath ) )
      {
         if( WriteAndClose_SubStringFile() )
         {
            return 1;
         }
      }
   }

   printf( "[WriteDescriptionSubStringsFile] Error, cannot create sub strings file\n" );
   return 0;
}

static int pnp_str_idx = 0;
static int pnp_num_strs = 0;

static int RegisterGlobalKStrings(  const char * p_dstpath_str,
                                    const char * p_dstpath_substr,
                                    const char * p_srcpath        )
{
   // register the sub strings
   if( RegisterSubStrings( p_dstpath_substr,
                           p_srcpath         )  )
   {
      // HACK: create for now as well
      if( Create_StringFile( p_dstpath_str ) )
      {
         if( AppendStringsFromFile( &pnp_str_idx,
                                    &pnp_num_strs,
                                    p_srcpath      )  )
         {
            if( WriteAndClose_StringFile() )
            {
               return 1;
            }
         }
      }

      printf( "[WriteToGlobalKStrings] Error, cannot create strings file\n" );
   }

   return 0;
}

static int GenerateGlobalKStringsSource(  const char * p_strs_path,
                                          const char * p_substrs_path,
                                          const char * p_hdr_path,
                                          const char * p_hdr_name,
                                          const char * p_srccode_path,
                                          const char * p_srccode_name,
                                          const char ** pp_includes,
                                          int numincludes,
                                          const char * p_poolname       )
{
   int ok;

   ok = 0;

   // open the string file
   if( Open_StringFile( p_strs_path ) )
   {
      // open the sub string file
      if( Open_SubStringFile( p_substrs_path ) )
      {
         // generate the source code
         ok = Create_KStringSourceCode(   p_hdr_path,
                                          p_hdr_name,
                                          p_srccode_path,
                                          p_srccode_name,
                                          pp_includes,
                                          numincludes,
                                          p_poolname        );

         // close the sub string file
         ok &= Close_SubStringFile();
      }

      // close the string file
      ok &= Close_StringFile();
   }

   // return success result
   return ok;
}


// HACK:
char * ap_includes[] =
{
   "\"../../grayspace-misc/gsdefines.h\"",
   "\"../../sys/include/misc/kernel_string_pool.h\""
};

int main( void )
{
   char buff[1024];

   // first, read in and extract all ISA-PNP devices from configuration file
   if( !ReadInConfigFile( DEVLIST_FILEPATH_IN ) )
   {
      FreeAll();
      return 0;
   }

   // now, generate text file of strings used for device descriptions
   if( !WriteDescriptionStringsFile( DEVSTRINGS_FILEPATH_TMP ) )
   {
      FreeAll();
      return 0;
   }

   // add strings to global string files
   if( !RegisterGlobalKStrings(  KSTRINGS_FILEPATH_TMP,
                                 KSUBSTRINGS_FILEPATH_TMP,
                                 DEVSTRINGS_FILEPATH_TMP    )  )
   {
      FreeAll();
      return 0;
   }

   // generate source files
   if( !GenerateGlobalKStringsSource(  KSTRINGS_FILEPATH_TMP,
                                       KSUBSTRINGS_FILEPATH_TMP,
                                       DEVLIST_KSTR_HDR_OUT_PATH,
                                       DEVLIST_KSTR_HDR_OUT,
                                       DEVLIST_KSTR_SRC_OUT_PATH,
                                       DEVLIST_KSTR_SRC_OUT,
                                       ap_includes,
                                       sizeof(ap_includes)/sizeof(char *),
                                       DEVLIST_KSTR_POOLNAME               )  )
   {
      FreeAll();
      return 0;
   }

   gets( buff );
   
   return 1;
}