Solved

Another Stupid Question!

Posted on 2004-04-05
27
386 Views
Last Modified: 2012-06-27
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????
0
Comment
Question by:ankuratvb
  • 11
  • 5
  • 4
  • +4
27 Comments
 
LVL 45

Expert Comment

by:Kdo
ID: 10757316
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
 
LVL 12

Expert Comment

by:stefan73
ID: 10757318
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
 
LVL 9

Author Comment

by:ankuratvb
ID: 10757368
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
 
LVL 4

Expert Comment

by:oumer
ID: 10757471
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
 
LVL 9

Author Comment

by:ankuratvb
ID: 10757664
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
 
LVL 45

Expert Comment

by:Kdo
ID: 10757708

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
 
LVL 9

Author Comment

by:ankuratvb
ID: 10757782
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
 
LVL 45

Expert Comment

by:Kdo
ID: 10758047
Hmm..

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


Kent
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 10758635
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
 
LVL 9

Author Comment

by:ankuratvb
ID: 10758845
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
 
LVL 8

Assisted Solution

by:ssnkumar
ssnkumar earned 35 total points
ID: 10763254
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
 
LVL 11

Expert Comment

by:avizit
ID: 10763707


>>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
 
LVL 12

Expert Comment

by:stefan73
ID: 10764088
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
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 45

Expert Comment

by:Kdo
ID: 10765214

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
 
LVL 9

Author Comment

by:ankuratvb
ID: 10765357
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
 
LVL 9

Author Comment

by:ankuratvb
ID: 10765427
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
 
LVL 9

Author Comment

by:ankuratvb
ID: 10765443
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
 
LVL 45

Expert Comment

by:Kdo
ID: 10765444
Hmm....

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

Kent
0
 
LVL 12

Expert Comment

by:stefan73
ID: 10765465
Kdo,
> Of course, this is less like cheating that some of the other methods.
...but not less messy :-)

Stefan
0
 
LVL 9

Author Comment

by:ankuratvb
ID: 10765476
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
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 10765536
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
 
LVL 9

Author Comment

by:ankuratvb
ID: 10765580
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
 
LVL 8

Expert Comment

by:ssnkumar
ID: 10772145
But there is no c0*.obj on Linux!
So, is it possible to do these changes on Linux too?

-ssnkumar
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 10772807
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
 
LVL 9

Author Comment

by:ankuratvb
ID: 10773192
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
 
LVL 16

Accepted Solution

by:
PaulCaswell earned 30 total points
ID: 10773288
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
 
LVL 9

Author Comment

by:ankuratvb
ID: 10907884
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

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
The goal of this video is to provide viewers with basic examples to understand opening and writing to files in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now