• C

Another Stupid Question!

Ok,here is another one of my useless questions.

How will u execute a function before main() is called in ANSI C?

This is what i know:

There are non-portable and compiler specific solutions to this.
Some are:

TurboC++:
#pragma startup func()
where func() should be declared before the pragma and should be of the type
void func(void)
(i'd like to know whether this works on other compilers)

gcc:
void before(void) __attribute__((constructor));

void before(void)
{
printf("before main\n");
}

int main(void)
{
printf("in main now\n");
return 0;
}


Also i know this is easily done in C++:


int before(void)
{
printf("before main\n");
return 0;
}

int i=before();//initialising global var with fn. call
int main(void)
{
printf("in main now\n");
return 0;
}

Is there a portable way to do this in ANSI C????
LVL 9
ankuratvbAsked:
Who is Participating?
 
PaulCaswellConnect With a Mentor Commented:
Here it is in all its Gory. It picks up its own name from argv[0] and looks for environment variables of the form Prexxx where xxx is the program name.

E.G. This makes VC6 launch the old CL.EXE that came with the old MSVC.

set PreCl=C:\msvc\bin\cl.exe /1 /X@ /R"/MLd""" /R"/ML""" /R"/FAs""/Fc" /R"/FAcs /Fa""/Fc" /R"/I ""/I" /R"/D ""/D"

Please remember that this is an evolved program rather than a designed-to-death one so forgive its misfortunes:

/*
      Pre.cpp : Launches a different program depending on environment variables.
*/

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <process.h>
#include <direct.h>

#include "CDefs.h"
DEBUG

// **** Globals ****

// Set to true if we should expand @stuff.
bool ExpandAts = false;
// Set to true if we should strip quote chars from parameters.
bool StripQuotes = false;
// Set to true if target app can only handle one file at a time.
bool OneFile = false;
// The current file parameter.
char * FileParam = NULL;
char FileDrive[_MAX_DRIVE];  
char FileDir[_MAX_DIR];
char FileName[_MAX_FNAME];  
char FileExt[_MAX_EXT];      
// Use the helper.
bool UseHelper = false;
char HelperName[_MAX_FNAME];
// Current working directory.
char Cwd[_MAX_PATH];

// The arguments we will pass to the program we launch.
#define MAXARGSETS 50
#define MAXARGS 100

// A single arg set.
typedef struct ArgSet
{
      short argCount;
      char fName[_MAX_FNAME];
      char * args [MAXARGS];
} ArgSet;

// One we are currently adding to or how many there are.
short ArgSetCount = 0;      

// One for each launch.
ArgSet ArgSets [MAXARGSETS] = {0,{0}};
// The main set.
ArgSet MainArgs = {0,{0}};
// The current set.
ArgSet * Args = &MainArgs;

// The search/replace table.
#define MAXSEARCHES 10
#define MAXSEARCHLEN 32

// What a search looks like.
typedef struct Search
{
      char search [MAXSEARCHLEN];
      char replace [MAXSEARCHLEN];
} Search;

// How many Searches we've got.
short SearchCount = 0;

// The Searches.
Search Searches [MAXSEARCHES];

// Preamble.
char Preamble[256];
// Postamble
char Postamble[256];

// **** Prototypes ****
// Run the specified app.
int RunIt ( int argSet );
// Build the command stuff.
void BuildCommands ( char * command, int argc, char* argv[] );
// Build the argument list.
void BuildArgs ( int argc, char * argv [] );
// Take one parameter.
void TakeParam ( char * param );
// Parses the parameters.
void ProcessEnvParams ( char * params );
// Parses one parameter.
void ProcessEnvParam ( char ** param );
// Free the allocated argument strings.
void FreeArgs ();
// Add a new search to the search list.
void NewSearch ( char ** param );
// Search and replace the command line.
void SearchAndReplace ( char * params );
// Break it up into separate params.
void SplitParams ( char * params );
// Found a param in the string. Take it.
void FoundParam ( char * params, short where, short length );
// Make multi file names into multi spawns.
void SpawnParams ();
// Spawn argset 0 selecting all options
// but only the file param given.
void SpawnParamSet ( short whichFile );
// Make file name parameters relative.
void RelativeFilenames ( void );
// Is this parameter a file?
bool IsFileParam ( char * param );
// Breaks the string into tokens.
int Tokens ( char * str, char * sep, char * tokens [], int max, char * buffer );
// Test function.
void Tst(void);
// Trim crap off the end of a string.
void TrimRight ( char * string, char * trim );
// Trim crap off the start of a string.
void TrimLeft ( char * string, char * trim );
// Replace in-situ any occurrences of a string with another string.
char * SnR ( char * str, char * s, char * r );
// Find a string in a string.
char * strfind ( char * str, char * find );
// Find a char in a string.
char * strichr ( char * str, char ch );

// **** Code ****

int main(int argc, char* argv[])
{
      int result = 0;
      char command [256];            // The command I use to run it.
      FILE * helper = NULL;
      char str[256];      // Work string.

      TESTING(fprintf(stderr, "Pre 1.0.0.\n"););
//      TESTING(Tst(););
      // Build the command to use from my env and params.
      BuildCommands ( command, argc, argv );

      if ( UseHelper )
      {
            // Create the helper batch file.
            sprintf ( str, "\\Helper\\%s.BAT", HelperName );
            helper = fopen ( str, "wt" );
            // Copy through the stage 0 batch file.
            sprintf ( str, "\\Helper\\%s0.BAT", HelperName );
            FILE * helper0 = fopen ( str, "rt" );
            if ( helper0 != NULL )
            {
                  while ( fgets ( str, sizeof(str), helper0 ) != NULL ) fputs ( str, helper );
                  fclose ( helper0 );
            }
            // Add a CD to the current path.
            sprintf ( str, "CD %s\n", Cwd );
            fputs ( str, helper );
      }

      for ( short i = 0; i < ArgSetCount && result == 0; i++ )
      {      // Launch once for each argset built.
            // Launch it.
#ifdef _DEBUG
            fprintf(stderr, "Launching:");
            for ( short j = 0; j < ArgSets[i].argCount; j++ )
                  fprintf ( stderr, "%s{%s}", (j<=1?" ":","),ArgSets[i].args[j] );
            fprintf(stderr, "\n");
            _flushall (); // Flush all streams before spawn.
#endif

            unless ( UseHelper )
            {
                  result = _spawnv( _P_WAIT, command, ArgSets[i].args );
            }
            else
            {
                  // Use helper.
                  unless ( helper == NULL )
                  {
                        // Write the arguments.
                        for ( short j = 0; j < ArgSets[i].argCount; j++ )
                        {
                              fprintf ( helper, "%s ", ArgSets[i].args[j] );
                        }
                        fprintf ( helper, "\n" );
                        // Copy through the stage 1 batch file.
                        sprintf ( str, "\\Helper\\%s1.BAT", HelperName );
                        FILE * helper1 = fopen ( str, "rt" );
                        if ( helper1 != NULL )
                        {
                              while ( fgets ( str, sizeof(str), helper1 ) != NULL )
                              {
                                    fputs ( SnR(str, "¬F", ArgSets[i].fName ), helper );
                              }
                              fclose ( helper1 );
                        }
                  }
            }


            TESTING(fprintf(stderr, "Completed with %d. errno = %d\n", result, errno););

      }

      if ( UseHelper )
      {
            unless ( helper == NULL )
            {
                  // CD back to the helper path.
                  fputs ( "CD \\Helper\n", helper );
                  // Copy through the stage 2 batch file.
                  sprintf ( str, "\\Helper\\%s2.BAT", HelperName );
                  FILE * helper2 = fopen ( str, "rt" );
                  if ( helper2 != NULL )
                  {
                        while ( fgets ( str, sizeof(str), helper2 ) != NULL ) fputs ( str, helper );
                        fclose ( helper2 );
                  }
                  // Close the helper file.
                  fclose ( helper );
                  // Delete any .DUN files.
                  sprintf ( str, "\\Helper\\%s.DUN", HelperName );
                  remove ( str );
                  // Create the GO file.
                  sprintf ( str, "\\Helper\\%s.GO", HelperName );
                  helper = fopen ( str, "wt" );
                  unless ( helper == NULL )
                  {
                        fprintf ( helper, "GO!\n" );
                        fclose ( helper );
                  }
                  // Wait for the .DUN file.
                  sprintf ( str, "\\Helper\\%s.DUN", HelperName );
                  until ( access ( str, 0 ) == 0 )
                  {
                        // Wait a bit.
                        Sleep ( 5000 );
                  }
            }
      }
      // Free up the memory I allocated.
      FreeArgs ();

      return result;
}

// Build the command stuff.
void BuildCommands ( char * command, int argc, char* argv[] )
{
      char drive[_MAX_DRIVE];  
      char dir[_MAX_DIR];
      char me[_MAX_FNAME];  
      char ext[_MAX_EXT];      

      // Dont bother with argv[0], its not always there.
      _splitpath( _pgmptr, drive, dir, me, ext );

      // Work out what I really need to run.
      char myEnvName [256];
      strcpy ( myEnvName, "Pre" );
      strcat ( myEnvName, me );
      char * programToRun = getenv( myEnvName );

      // If there's none, try a PreXXXd/r for a debug/release version.
      if ( programToRun == NULL )
      {
            bool debug = false;
            bool release = false;

            // Look for either "Debug" or "Release" in any arg.
            for ( int i = 1; i < argc; i++ )
            {
                  if ( argv[i][0] == '@' )
                  {
                        char str[256];
                        // Look through the file.
                        FILE * file = fopen ( &argv[i][1], "rt" );
                        if ( file != NULL )
                        {
                              while ( fgets ( str, sizeof(str), file ) != NULL )
                              {
                                    TrimRight ( str, "\n\r " );
                                    if ( strfind ( str, "debug" ) != NULL ) debug = true;
                                    if ( strfind ( str, "release" ) != NULL ) release = true;
                              }
                              fclose ( file );
                        }
                  }
                  else
                  {
                        if ( strfind ( argv[i], "debug" ) != NULL ) debug = true;
                        if ( strfind ( argv[i], "release" ) != NULL ) release = true;
                  }
            }
            TESTING(fprintf(stderr, "Debug:%d Release:%d\n", debug, release ); );
            unless ( debug && release )
            {
                  if ( debug ) strcat ( myEnvName, "d" );
                  if ( release ) strcat ( myEnvName, "r" );
                  if ( debug || release ) programToRun = getenv( myEnvName );
            }
            
      }

//      TESTING(programToRun = "\\Casio\\SHC\\BIN\\SHC.EXE @\\Casio\\Pre.inp";);
//      TESTING(ExpandAts = true;);
      TESTING(fprintf(stderr, "Env Name: '%s'\n", myEnvName ); );
      TESTING(fprintf(stderr, "Program to run: '%s'\n", programToRun ); );

      if ( programToRun != NULL )
      {      // Run the other one.
            strcpy ( command, programToRun );

            // Strip out any parameters I want.
            char * params = strchr ( command, ' ' );
            if ( params != NULL )
            {
                  // Terminate the command.
                  *params = '\0';
                  params += 1;
                  // Analyse my environment params.
                  ProcessEnvParams ( params );
            }
            // MainArgs is the command.
            TakeParam ( command );
            // Then the preamble.
            unless ( Preamble[0] == '\0' ) TakeParam ( Preamble );
            // Build the args list.
            BuildArgs ( argc, argv );
            // Then the Postamble.
            unless ( Postamble[0] == '\0' ) TakeParam ( Postamble );
            // Make multi file names into multi spawns if requested.
            SpawnParams ();
      }
      else
      {      // Just launch the real one.
            strcpy ( command, drive );
            strcat ( command, dir );
            strcat ( command, "REAL" );
            strcat ( command, me );
            // Dont put the extension on.
            // They might be replacing a .BAT or .COM.

            /*
                  Note that I give him MY name as argv[0], not his.
                  This way I am causing the least damage to its
                  environment
            */

            // Just copy their args to mine.
            // Bring them directly into set 0.
            Args = &ArgSets[0];
            for ( short i = 0; i < argc; i++ )
            {
                  TakeParam ( argv[i] );
            }
            // Theres one there.
            ArgSetCount += 1;
      }
}

// Build the argument list.
void BuildArgs ( int argc, char * argv [] )
{
      short i;
      char params [512];      // Roll them out into here.
      params[0] = '\0';

      // Grab each passed param and roll it out into my param line.
      for ( i = 1; i < argc; i++ )
      {
            TESTING(fprintf(stderr, "Param: '%s'\n", argv[i] ); );
            if ( ExpandAts && argv[i][0] == '@' )
            {      // Expand out @filename stuff.
                  FILE * argFile = fopen (&argv[i][1], "r" );

                  until ( argFile == NULL || feof ( argFile ) )
                  {
                        char line [256];
                        
                        if ( fgets (line, sizeof(line), argFile ) != NULL )
                        {
                              // Turn returns into spaces.
                              if ( line[strlen(line)-1] == '\n' )
                                    line[strlen(line)-1] = ' ';
                              TESTING(fprintf(stderr, "     : '%s'\n", line ); );
                              // Add it to my params.
                              strcat (params, line);
                        }
                  }
                  // Close it if necessary.
                  unless ( argFile == NULL )
                        fclose ( argFile );
            }
            else
            {
                  // Normal one. Just take it.
                  strcat (params, argv[i]);
                  strcat ( params, " " );
            }
      }

      // Now post-process the params.

      // Do the search and replace.
      SearchAndReplace ( params );
      // Then break it up into separate params again.
      SplitParams ( params );
      // Make filenames relative.
      RelativeFilenames ();
}

// Make multi file names into multi spawns.
void SpawnParams ()
{
      // Bring them into the sets.
      if ( OneFile )      // Only if user says so.
      {      
            for ( short fileArg = 1; fileArg < MainArgs.argCount; fileArg++ )
            {
                  if ( IsFileParam(MainArgs.args[fileArg]) )
                  {
                        // Remember the file param.
                        FileParam = MainArgs.args[fileArg];
                        _splitpath( FileParam, FileDrive, FileDir, FileName, FileExt );
                        // Make a new set from this one but with only this file param.
                        SpawnParamSet ( fileArg );
                        // Not relevant any longer.
                        FileParam = NULL;
                  }
            }
      }
      else
      {
            // Just copy the main set to the zero set.
            SpawnParamSet ( 0 );
      }

}

// Spawn argset 0 selecting only the file param given.
void SpawnParamSet ( short whichFile )
{      // Check that there's room.
      if ( ArgSetCount < MAXARGSETS )
      {
            // New one.
            Args = &ArgSets[ArgSetCount++];
            // Then each parameter.
            for ( short i = 0; i < MainArgs.argCount; i++ )
            {
                  if ( IsFileParam ( MainArgs.args[i] ) )
                  {      // Its a file.
                        // Copy it if its the command or the one we want or we want all of them.
                        if ( i == 0 || whichFile == 0 || i == whichFile )
                        {
                              TakeParam ( MainArgs.args[i] );
                              // Record the file name.
                              if ( i == whichFile && FileParam != NULL )
                              {
                                    strcpy ( Args->fName, FileName );
                              }
                        }
                  }
                  else
                  {      // Its an option.
                        // Just copy it.
                        TakeParam ( MainArgs.args[i] );
                  }
            }
      }
      else
      {
            fprintf ( stderr, "Too many file params to spawn.\n" );
            exit ( EXIT_FAILURE );
      }

}

// Is this parameter a file?
bool IsFileParam ( char * param )
{
      bool is = true;

      if ( param[0] == '/' || param[0] == '-' )
      {
            is = false;
      }

      return ( is );
}

// Search and replace the command line.
void SearchAndReplace ( char * params )
{
      short i;
      bool inQuotes = false;

      //TESTING(fprintf(stderr, "Replacing: '%s'\n", params ); );
      // Do any search/replace stuff.
      for ( i = 0; params[i] != '\0'; i++ )
      {      // For each character in the line.
            if ( params[i] == '\"' )
                  inQuotes = !inQuotes;

            // Dont search/replace inside quotes.
            unless ( inQuotes )
            {      
                  for ( short s = 0; s < SearchCount; s++ )
                  {      // For each search.
                        bool match = true;
                        
                        // Do we have a match ?
                        for ( short j = 0; match && Searches[s].search[j] != '\0'; j++ )
                        {      // For each character in the search.
                              if ( Searches[s].search[j] != params[i+j] )
                                    match = false;
                        }

                        if ( match )      // YES! Replace it.
                        {
//                              TESTING(fprintf(stderr, "Replacing '%s' with '%s'\n", Searches[s].search, Searches[s].replace ); );
                              // Make room for the replace string.
                              memcpy (&params[i+strlen(Searches[s].replace)],
                                          &params[i+strlen(Searches[s].search)],
                                          strlen(&params[i+strlen(Searches[s].search)])+1);
                              // Copy it in.
                              memcpy (&params[i],
                                          Searches[s].replace,
                                          strlen(Searches[s].replace));
                        }
                  }
            }
      }

      //TESTING(fprintf(stderr, "Replaced:  '%s'\n", params ); );
}

// Break it up into separate params.
void SplitParams ( char * params )
{
      short i;
      bool inQuotes = false;
      short start = 0;

      // Break each one at a space.
      for ( i = 0; params[i] != '\0'; i++ )
      {      // For each character in the line.
            if ( params[i] == '\"' )
                  inQuotes = !inQuotes;

            unless ( inQuotes )      // Dont break between quotes.
            {
                  if ( params [i] == ' ' || params[i] == '\0' )
                  {
                        if ( start < i )
                        {      // We've got a non-zero length one.
                              FoundParam ( params, start, i - start );
                        }
                        start = i+1;
                  }
            }
      }
}

// Make file name parameters relative.
void RelativeFilenames ( void )
{
      
      /* Get the current working directory: */
      if( _getcwd( Cwd, _MAX_PATH ) != NULL )
      {
            char cwdDrive[_MAX_DRIVE];  
            char cwdDir[_MAX_DIR];
            char cwdName[_MAX_FNAME];  
            char cwdExt[_MAX_EXT];      

            // Add a '\' at the end.
            strcat ( Cwd, "\\" );
            _splitpath( Cwd, cwdDrive, cwdDir, cwdName, cwdExt );
            TESTING(fprintf(stderr, "CWD: '%s'\n", Cwd););

            char * cwdTokens [50];
            char cwdBuffer [256];
            int cwdFields = Tokens ( cwdDir, "\\", cwdTokens, 50, cwdBuffer );

            for ( short j = 0; j < MainArgs.argCount; j++ )
            {
                  unless ( MainArgs.args[j] == NULL )
                  {
                        // Is this a file param (not an option).
                        if ( IsFileParam ( MainArgs.args[j] ) )
                        {      // Not an option.
                              char arg [_MAX_PATH];
                              bool quoted = false;

                              // Is it a valid file name.
                              char drive[_MAX_DRIVE];  
                              char dir[_MAX_DIR];
                              char name[_MAX_FNAME];  
                              char ext[_MAX_EXT];      
                              
                              // Strip quotes.
                              strcpy ( arg, MainArgs.args [j] );
                              if ( arg[0] == '\"' )
                              {
                                    quoted = true;
                                    memcpy ( arg, arg+1, strlen(arg+1)+1 );
                                    if (arg[strlen(arg)-1] == '\"')
                                    {
                                          arg[strlen(arg)-1] = '\0';
                                    }

                              }

                              // Break it up.
                              _splitpath( arg, drive, dir, name, ext );
//                                    TESTING(fprintf(stderr, "File name: '%s'\n", arg););

                              // Same drive?
                              if ( stricmp ( drive, cwdDrive ) == 0 )
                              {      // Yup!
                                    char * tokens [50];
                                    char buffer [256];
                                    int fields = Tokens ( dir, "\\", tokens, 50, buffer );
                                    bool match = true;
                                    int diffToken = 0;
                                    // Where do they mismatch.
                                    for ( int f = 0; (f < fields) && match; f++ )
                                    {
//                                                TESTING(fprintf(stderr, "Compare: '%s' '%s'\n", tokens[f], cwdTokens[f]););
                                          if ( f >= cwdFields || stricmp(cwdTokens[f], tokens[f]) != 0 )
                                          {
                                                // Mismatch!
                                                match = false;
                                                diffToken = f;
//                                                      TESTING(fprintf(stderr, "Different at %d\n", f););
                                          }

                                    }
                                    if ( diffToken > 0 )
                                    {
                                          int t;
                                          // Empty the arg ready for the new one.
                                          arg[0] = '\0';
                                          // Start with a quote if necessary.
                                          if ( quoted ) strcat ( arg, "\"" );
                                          // Some match!
                                          // Put in the '..\' s
                                          for ( t = cwdFields - 1; t > diffToken; t-- )
                                          {
                                                // Not Tested!
                                                strcat ( arg, "..\\" );
                                          }
                                          // Then the path to the desired place.
                                          for ( t = diffToken; t < fields; t++ )
                                          {
                                                if ( strlen ( tokens[t] ) > 0 )
                                                {
                                                      strcat ( arg, tokens[t] );
                                                      strcat ( arg, "\\" );
                                                }
                                          }
                                          // Then name and ext.
                                          strcat ( arg, name );
                                          strcat ( arg, ext );
                                          // And the trailing quote.
                                          if ( quoted ) strcat ( arg, "\"" );
//                                                TESTING(fprintf(stderr, "Result: '%s'\n", arg););
                                          if ( strlen ( arg ) < strlen ( MainArgs.args [j] ) )
                                          {
                                                TESTING(fprintf(stderr, "Changing: '%s' to '%s'\n", MainArgs.args [j], arg););

                                                // Shorter! Replace it.
                                                strcpy ( MainArgs.args [j], arg );
                                          }

                                    }
                              }
                        }

                        
                  }
            }
      }
}

// Found a param in the string. Take it.
void FoundParam ( char * params, short where, short length )
{      // I need to process it.
      char param [256];

      // Copy it.
      memcpy ( param, &params[where], length );
      param[length] = '\0';
      
      // Remove all quotes if requested.
      if ( StripQuotes )
      {
            char * quote = NULL;      // Where the quote char was found.

            while ( (quote = (char*)strchr(param, '\"')) != NULL )
            {      // Found one! Kill it.
                  memcpy ( quote, quote+1, strlen(quote+1)+1 );
            }
      }
      // Add it to my param list.
      TakeParam ( param );
}

// Take one parameter.
void TakeParam ( char * param )
{
      if ( Args->argCount < MAXARGS )
      {      // Havent broken the limit yet.
            char newParam [256];
            short src, dst = 0;

            for ( src = 0; param[src] != '\0'; src++ )
            {
                  // Look for specials.
                  switch ( param[src] )
                  {
                        default:
                              newParam[dst++] = param[src];
                              break;

                        case      '¬':
                              switch ( param[++src] )
                              {
                                    case      'F':      // They want the file name from the file.
                                                unless ( FileParam == NULL )
                                                {
                                                      newParam[dst] = '\0';
                                                      strcat(newParam,FileName);
                                                      dst += strlen(FileName);
                                                }
                                                else
                                                {
                                                      newParam[dst++] = '¬';
                                                      newParam[dst++] = param[src];
                                                }
                                                break;

                                    default:            // Just give them it.
                                                newParam[dst++] = '¬';
                                                newParam[dst++] = param[src];
                                                break;
                                                
                              }
                              break;
                  }
            }
            // Terminate it.
            newParam[dst] = '\0';
            // Add it in.
            Args->args[Args->argCount] = (char *)malloc(strlen(newParam) + 1);
            strcpy ( Args->args[Args->argCount], newParam );
            Args->argCount += 1;
      }
      else
      {      // OOPs.
            fprintf ( stderr, "Too many arguments.\n" );
            exit ( EXIT_FAILURE );
      }
}

// Free the allocated argument strings.
void FreeArgs ()
{
      // The spawned sets.
      for ( short i = 0; i < ArgSetCount; i++ )
      {
            for ( short j = 0; j < ArgSets[i].argCount; j++ )
            {
                  unless ( ArgSets[i].args [j] == NULL )
                  {
                        free ( ArgSets[i].args [j] );
                  }
            }
      }
      // And the main set.
      for ( short j = 0; j < MainArgs.argCount; j++ )
      {
            unless ( MainArgs.args [j] == NULL )
            {
                  free ( MainArgs.args [j] );
            }
      }
}

// Parses the parameters to my SET string.
void ProcessEnvParams ( char * params )
{
      TESTING(fprintf(stderr, "Env params: '%s'\n", params ); );
      unless ( *params == '@' )
      {
            // Process each param.
            until ( *params == '\0' )
            {
                  switch ( *params )
                  {
                        case      '/':
                                    params += 1;      // Skip the '/'.
                                    ProcessEnvParam ( &params );
                                    while ( *params == ' ' )
                                    {
                                          params += 1;      // Skip extra spaces.
                                    }
                                    break;

                        default:
                                    fprintf ( stderr, "Bad parameter format \"%s\".\n", params );
                                    exit ( EXIT_FAILURE );
                                    break;
                  }
            }
      }
      else
      {
            // Get each from a file.
            FILE * from = fopen ( &params[1], "rt" );

            TESTING(fprintf(stderr, "Getting from file: '%s'\n", &params[1] ); );
            if ( from != NULL )
            {
                  char param [256];
                  while ( fgets ( param, sizeof(param), from ) != NULL )
                  {
                        // Trim cr/lf off end.
                        TrimRight ( param, "\n\r " );
//                        TESTING(fprintf(stderr, "Line '%s'\n", param););
                        // Ignore blanks and comments.
                        unless ( strlen ( param ) == 0 || param[0] == ':' )
                        {
                              if ( param [0] == '/' )
                              {
                                    char * paramPtr = &param[1];      // Fake a pointer to it.
                                    // Process it.
                                    ProcessEnvParam ( &paramPtr );
                              }
                              else
                              {
                                    fprintf ( stderr, "Bad parameter format \"%s\".\n", param );
                                    fclose ( from );
                                    exit ( EXIT_FAILURE );
                              }
                        }
                  }
                  fclose ( from );
            }
            else
            {
                  // Cant find the file.
                  fprintf ( stderr, "Cant open file \"%s\".\n", &params[1] );
                  exit ( EXIT_FAILURE );
            }
      }
}

// Parses one parameter.
void ProcessEnvParam ( char ** param )
{
      switch ( **param )
      {
            case      'X':      // Expand something.
            case      'x':
                        *param += 1;
                        switch ( **param )
                        {
                              case      '@':
                                          ExpandAts = true;
//                                          TESTING(fprintf ( stderr, "Expanding @ parameters.\n" ););
                                          break;
                              default:
                                          fprintf ( stderr, "Bad expand parameter \"%s\".\n", *param );
                                          exit ( EXIT_FAILURE );
                                          break;
                        }
                        break;

            case      'R':      // Replace.
            case      'r':
                        *param += 1;
                        NewSearch ( param );
                        break;

            case      '1':      // One file at a time.
                        OneFile = true;
                        break;

            case      'H':      // Use the helper.
                        UseHelper = true;
                        *param += 1;
                        strcpy ( HelperName, *param );
                        *param += strlen(*param);
                        break;

                        
            case      '<':      // Preamble.
                        *param += 1;
                        strcpy ( Preamble, *param );
                        TESTING(fprintf ( stderr, "Preamble \"%s\".\n", Preamble ););
                        *param += strlen(*param);
                        break;

            case      '>':      // Postamble.
                        *param += 1;
                        strcpy ( Postamble, *param );
                        TESTING(fprintf ( stderr, "Postamble \"%s\".\n", Postamble ););
                        *param += strlen(*param);
                        break;

            case      '"':      // Remove quote characters.
                        StripQuotes = true;
//                        TESTING(fprintf ( stderr, "Stripping quotes.\n" ););
                        break;

            default:
                        fprintf ( stderr, "Bad parameter \"%s\".\n", *param );
                        exit ( EXIT_FAILURE );
                        break;
      }
      *param += 1;      // Step on.

}

// Add a new search to the search list.
void NewSearch ( char ** param )
{
      short length = 0;
      char * p = *param;
      char sep = p[0];      // Use this separator.
      /*
            A search spec is of the form /R"/I ""/I"
            to remove a space after a /I command.
      */
      short startSearch = 0;      // The start of the search string.
      short endSearch = 0;
      short startReplace = 0;
      short endReplace = 0;
      short i;

      // Convert '`' to '"'
      for ( i = 0; p[i] != '\0'; i++ ) if ( p[i] == '`' ) p[i] = '\"';
      // Skip the first sep.
      for ( i = 1; p[i] != '\0' && endReplace == 0; i++ )
      {
            if ( p[i] == sep )
            {
                  if ( endSearch == 0 )
                        endSearch = i;
                  else if ( startReplace == 0 )
                        startReplace = i;
                  else if ( endReplace == 0 )
                        endReplace = i;
            }
            length += 1;
      }

      unless ( endSearch == startSearch )
      {
            p [endSearch] = '\0';
            p [endReplace] = '\0';
            strcpy ( Searches[SearchCount].search, &p[startSearch+1] );
            strcpy ( Searches[SearchCount].replace, &p[startReplace+1] );
            p [endSearch] = sep;
            p [endReplace] = sep;

            if ( SearchCount < MAXSEARCHES )
            {
                  SearchCount += 1;
            }
            else
            {
                  fprintf ( stderr, "Too many Searches.\n" );
                  exit ( EXIT_FAILURE );
            }
      }
      else
      {
            fprintf ( stderr, "Cant handle an empty search string.\n" );
            exit ( EXIT_FAILURE );
      }

      *param += length;
}

/*
      Breaks the string into tokens.

      Any character in sep signifies a token separator.

      Resultant tokens are filled in to 'tokens' up to max.

      Returns token count.
*/
int Tokens ( char * str, char * sep, char * tokens [], int max, char * buffer )
{
//      static char string [256];
      int len = strlen ( str );
      int count = 0;
      int i;

      // Grab the string.
      strcpy ( buffer, str );
//      TESTING(fprintf(stderr, "Tokens of: '%s'\n", str););
      // Empty the tokens.
      for ( i = 0; i < max; i++ ) tokens[i] = NULL;
      // Mark the first token.
      if ( count < max ) tokens[count++] = buffer;

      // Break it up.
      for ( i = 0; i < len; i++ )
      {
            if ( strchr ( sep, buffer[i] ) != NULL )
            {      // This character appears in the separators!
                  // Break the string here.
                  buffer[i] = '\0';
//                  TESTING(fprintf(stderr, "Token: '%s'\n", tokens[count-1]););
//                  TPRINT(("Token: '%s'", tokens[count-1]));
                  // Store the token.
                  if ( count < max )
                  {
                        tokens[count++] = &buffer[i+1];
                  }
            }

      }

      return count;
}

// Trim crap off the end of a string.
void TrimRight ( char * string, char * trim )
{
      int i;

      for ( i = strlen (string) - 1; i >= 0 && strchr ( trim, string[i] ) != NULL; i-- )
            string[i] = '\0';
}


// Trim crap off the start of a string.
void TrimLeft ( char * string, char * trim )
{
      while ( string[0] != '\0' && strchr ( trim, string[0] ) != NULL )
      {
            // Includes the terminator.
            memmove ( &string[0], &string[1], strlen(string) );
      }
}


// Replace in-situ any occurrences of a string with another string.
char * SnR ( char * str, char * s, char * r )
{
      unless ( str == NULL || s == NULL || r == NULL )
      {
            char * where = strchr ( str, s[0] );

            while ( where != NULL )
            {
                  if ( strncmp ( where, s, strlen(s) ) == 0 )
                  {
                        // Make room for the replace string.
                        memmove (&where[strlen(r)], &where[strlen(s)], strlen(where) - strlen(s) + 1);
                        // Copy it in.
                        memcpy (where, r, strlen(r));
                        // Look for next one AFTER the replace
                        where = strchr ( where+strlen(r), s[0] );
                  }
                  else
                  {
                        // Not matched! Look for next one.
                        where = strchr ( where+1, s[0] );
                  }
            }
      }

      return ( str );
}

// Find a string in a string.
char * strfind ( char * str, char * find )
{
      char * where = NULL;
      bool found = false;

      unless ( str == NULL || find == NULL )
      {
            where = strichr ( str, find[0] );
            while ( (where != NULL) && !found  )
            {
                  if ( strnicmp ( where, find, strlen(find) ) == 0 )
                  {
                        found = true;
                  }
                  else
                  {
                        // Not matched! Look for next one.
                        where = strichr ( where+1, find[0] );
                  }
            }
      }

//      TESTING(fprintf(stderr, "find '%s' in '%s' returning '%s'\n", find, str, found ? where: NULL ); );
      return found ? where: NULL;
}

// Find a char in a string.
char * strichr ( char * str, char ch )
{
      char * where = strchr ( str, ch );
      if ( where == NULL ) where = strchr ( str, toupper(ch) );
      return where;
}



0
 
Kent OlsenData Warehouse Architect / DBACommented:
Hi ankuratvb,

Some loaders/linkers let you substitute module names.  If so, you could always use the linker to equate main() to your function and the existing main() function to a name called by your function.


A workable "cheat" is to have two mains.  :)



main ()
{

  printf ("This is the real main.\n");

#define main NextMain

  main ();

}

main ()
{

  printf ("This is the next main.\n");

}



Kent
0
 
stefan73Commented:
Hi ankuratvb,
There are no stupid questions, just stupid answers :-)

A stupid answer of mine is: Why do you want to do this? You can always push your semantic main function further down the call tree, like:

int main(int argc,char** argv){
    int retval;

    before_real_main();
    retval = real_main(argc,argv);
    after_real_main();
    return retval;
}

Cheers,
Stefan
0
Protect Your Employees from Wi-Fi Threats

As Wi-Fi growth and popularity continues to climb, not everyone understands the risks that come with connecting to public Wi-Fi or even offering Wi-Fi to employees, visitors and guests. Download the resource kit to make sure your safe wherever business takes you!

 
ankuratvbAuthor Commented:
I dont really have a purpose to do this.
That is why i say that this is another of my useless questions.
Just trying to explore the subtleties of the language.

Everyone says that main() starts,at the user level atleast,the execution of the program,
I am just trying to see if another function can be called before main is invoked in the asm listing as well.

Some compilers,i guess even VC++ allows u to define the entry point function for ur program.But i wanted to do this thru portable ANSI C code if possible.

Nice one Kent. :~))
But that really ain't the answer i am trying to find.


0
 
oumerCommented:
what about using LD_PRELOAD? Never used it but I have read that using this environment variable you could be able to set some library codes to execute before main. So may be that will do it for you.

links:

for linux:
http://uberhip.com/godber/interception/index.html

for windows:
http://www.deez.info/sengelha/projects/ldpreload/
0
 
ankuratvbAuthor Commented:
Hi oumer,

The windows link says that the code will work only on Win NT/2000.
Any way,i already have such a solution if i have to use dif. code for dif. OS
For linux/unix,i can use the following in gcc:
void before(void) __attribute__((constructor));
For windows,in VC++ i can set my entry point to some other fn.
while for borland compilers,i can use #pragma startup.

0
 
Kent OlsenData Warehouse Architect / DBACommented:

Hi ankuratvb,

Because main() isn't really THE main function your options are limited.  The initialization code that links will all C programs sets up the stack and heap, builds argv, sets argc, and performs several other startup functions.  When it gets done, it explicitly calls main() -- a function that the program is responsible for providing.

If you want to put something between the startup code and main(), you need to modify the startup code to call something else, or you need to link the modules in such a way that the loader substitutes another name for main().


Kent
0
 
ankuratvbAuthor Commented:
Hi kent,

I tried that but didnt work.

See:
http://oldlook.experts-exchange.com:8080/Programming/Programming_Languages/C/Q_20725515.html

This was another of my stupid useless questions that didnt quite work as i expected it to.
0
 
Kent OlsenData Warehouse Architect / DBACommented:
Hmm..

I was going to refer you to the same thread.  :)


Kent
0
 
PaulCaswellCommented:
I've done this years ago in Mac CodeWarrior but it was C++ and I declared a static object with a creator method. The creator was successfully called before main.

0
 
ankuratvbAuthor Commented:
Hi paul,

This is easily done in c++.

Just declare a global variable and initialize with a fn.call(which is not allowed in ANSI C)
This calls the fn. which does the initialization before main() is called.
0
 
ssnkumarConnect With a Mentor Commented:
I don't think there can be a general solution for this!
This has to be done keeping in mind the compiler we are using.
So, you will have to understand the compiler first and see who calls the main() function.
Usually a startup routine calls the main function. This routine is a compiled code and gets linked to your code. So, you don't have the freedom to change it in the way you want:-(

-ssnkumar
0
 
avizitCommented:


>>This is easily done in c++.

>>Just declare a global variable and initialize with a fn.call(which is not allowed in ANSI C)
>>This calls the fn. which does the initialization before main() is called.

Even easier way in C++ is to just decalare a global  object and put your stuff in the constructor.

This actually ctreated a hell of a problem for my when my friend fopr testing purpose called abort() from the constructor

and I spent two days wondering how my program could abort without even reaching main().

--Abhijit




0
 
stefan73Commented:
avizit,
> I spent two days wondering how my program could abort without even
> reaching main().

Good point. pre-main initializations should not fail. You'll have a big mess otherwise.

Stefan
0
 
Kent OlsenData Warehouse Architect / DBACommented:

An overlooked possibility is to hack the c0*.obj file.  Use a binary editor to change "main" to "anku".  I don't remember the header well enough to know what will happen if the length of the name changes.

And of course, one can always disassemble the c0*.obj file, change "main" to anything that one wishes, and reassemble.  Of course, this is less like cheating that some of the other methods.


Kent
0
 
ankuratvbAuthor Commented:
Hi kent,

I tried that and it compiled as well.

From my previous thread:
>The changes that i made in the c0*.obj & the tc.exe file did solve my problem to an extent
>It did then search for niam instead of main but on executing crashed my compiler saying
>an exception occured.
0
 
ankuratvbAuthor Commented:
Also from my prev. thread,

>The c0*.obj files come in after the asm file has been created so the definition for main lies >in the tc.exe file itself.
>The c0*.obj files just call the fn main() ,as Kdo said

>What I believe is that the compiler creates a C0.asm file with a procedure _main.This is >defined in the tc.exe file(i think) where in the debugger if you display contents, it says ><template>main _main <template>.

>I changed that to define _niam instead of _main,so that i have a _niam procedure in >c0.asm,& i made the c0*.obj files call a niam() fn instead of main().
>but it didnt work(crashes saying exception occured)

After the changes,what was happening was that instead of looking for main,it did look for niam and it compiled fine even if i didnt give a main() and gave me a linker error if i didnt give niam() but when i did define niam(),it crashed the compiler saying that an exception occured.

0
 
ankuratvbAuthor Commented:
But this too would be limited only to TC but i can do this very easily in TC using the

void func(void);
#pragma startup func()

void func(void)
{
}

Is there really no portable way?
0
 
Kent OlsenData Warehouse Architect / DBACommented:
Hmm....

I know you said compiler, but just in case -- crashed the compiler, linker, or execution?

Kent
0
 
stefan73Commented:
Kdo,
> Of course, this is less like cheating that some of the other methods.
...but not less messy :-)

Stefan
0
 
ankuratvbAuthor Commented:
crashed the compiler.It compiled and linked fine but then it seg faulted and i got a core dump on the dos window.If i remember correctly,it gave me an 'Invalid Segment Error/Exception'
0
 
PaulCaswellCommented:
How about writing your own program that spawns the other one.

I've done this with CL.EXE to allow me to use VC6 IDE with older compilers. It just tinkers with the parameters and spawns the original compiler.

Paul
0
 
ankuratvbAuthor Commented:
Hi paul,

Can u elaborate?

But then again,i'd be limited to a particular compiler.

I guess i already have pragmatic solutions for this for all(most of them atleast) compilers
but the problem all of them are different for each compiler.

I was looking for a common solution.U know,something like the global var. initialization with fn.call in C++. which is common for all compilers for C++.


0
 
ssnkumarCommented:
But there is no c0*.obj on Linux!
So, is it possible to do these changes on Linux too?

-ssnkumar
0
 
PaulCaswellCommented:
What do you want to do before main? If you can do it by modifying the command-line parameters then you can rename the program and write a new one that uses 'spawn' to launch the renamed one. This should be relatively portable but doesnt give you much more control over the spawned program other than command-line parameters and, perhaps, environment variables.

For example. I have VC6 installed on my Windows PC. Somewhere in the system, therefore, there is a CL.EXE which is the 'C' compiler it uses. I want to use VC6 to compile code that was written for a different C compiler so, in rather simplistic terms, I rename CL.EXE to REALCL.EXE and write a program that, depending on settings of various environment variables, will launch any C compiler on my PC, including the REALCL.EXE.

I can now use all the facilities of of VC6, code browsing, syntax colouring, single click building, automatic dependency checking, SourceSafe integration while still compiling programs using a compiler that was was released 14 years ago. Sure there are complications, like command line parameters have changed, but thats just a SMOP (small matter of programming).

If this is close to what you want, let me know and I'll post some source code.
0
 
ankuratvbAuthor Commented:
Hi ssn,

the co*.obj files exist in TurboC++ and not for gcc.
For gcc,there are startup stubs similar to co*.obj but i dont know what are their filenames.

Hi Paul,

Though this is not exactly what i wanted,but i'd definitely like to see what u have done with CL.EXE
0
 
ankuratvbAuthor Commented:
Oh!!!

I've grown so tired of my useless,stupid questions that i've decided to close them once and for all.

I guess this is one of those questions where you have to say:"It can't be done!"

Paul,thanks for your code.
I guess ssnkumar said the correct answer here "It can't be done"

Thanx to Kent,Stefan,oumer,avizit for their responses and wasting their time for my useless question.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.