Logo Search packages:      
Sourcecode: u++ version File versions

cpp0.cc

//                              -*- Mode: C++ -*- 
// 
// uC++ Version 5.0.1, Copyright (C) Peter A. Buhr and Nikita Borisov 1995
// 
// cpp0.c -- 
// 
// Author           : Nikita Borisov
// Created On       : Sat Dec  9 13:32:00 1995
// Last Modified By : Peter A. Buhr
// Last Modified On : Sun Aug  8 09:26:34 2004
// Update Count     : 406
//
// This  library is free  software; you  can redistribute  it and/or  modify it
// under the terms of the GNU Lesser General Public License as published by the
// Free Software  Foundation; either  version 2.1 of  the License, or  (at your
// option) any later version.
// 
// This library is distributed in the  hope that it will be useful, but WITHOUT
// ANY  WARRANTY;  without even  the  implied  warranty  of MERCHANTABILITY  or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
// for more details.
// 
// You should  have received a  copy of the  GNU Lesser General  Public License
// along  with this library.
// 


#include <string>
using std::string;
#include <cstdio>
#include <unistd.h>                             // execvp, fork, unlink
#include <sys/wait.h>                           // wait


//#define __U_DEBUG_H__

#ifdef __U_DEBUG_H__
#include <iostream>
using std::cerr;
using std::endl;
#endif


string compiler_name( CCAPP );                        // path/name of C compiler


int main( int argc, char *argv[] ) {
    int code;
    int i;

    string arg;
    string bprefix;

    const char *cpp_in = NULL;
    const char *cpp_out = NULL;

    bool upp_flag = false;
    bool cpp_flag = false;
    bool cxx_flag = false;
    const char *o_name = NULL;
    bool start = false;

    const char *args[argc + 100];               // leave space for 100 additional cpp command line values
    int nargs = 1;                              // number of arguments in args list; 0 => command name
    const char *uargs[20];                      // leave space for 20 additional u++-cpp command line values
    int nuargs = 1;                             // 0 => command name

    // process all the arguments
#ifdef __U_DEBUG_H__
    cerr << "cpp:" << endl;
#endif // __U_DEBUG_H__

    for ( i = 1; i < argc; i += 1 ) {
#ifdef __U_DEBUG_H__
      cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
#endif // __U_DEBUG_H__
      arg = argv[i];
#ifdef __U_DEBUG_H__
      cerr << "arg:\"" << arg << "\"" << endl;
#endif // __U_DEBUG_H__
      if ( arg.substr(0,1) == "-" ) {
          // strip g++ flags that are inappropriate or cause duplicates in subsequent passes

          if ( arg == "-quiet" ) {
          } else if ( arg.substr(0,5) == "-lang" ) {
            if ( arg == "-lang-c++" ) {
                cxx_flag = true;
            } // if
          } else if ( arg.substr(0,2) == "-A" ) {
          // ignore -D flags before this as they are duplicated on the next step
          } else if ( arg == "-D__U_CPP_FLAGS__" ) {  // start of user -D flags
            start = true;
          } else if ( ( arg.substr(0,2) == "-D" || arg.substr(0,2) == "-U" ) && ! start ) {

          // strip u++ flags controlling cpp step

          } else if ( arg == "-D__U_CPP__" ) {
            cpp_flag = true;
          } else if ( arg == "-D__U_UPP__" ) {
            upp_flag = true;
          } else if ( arg.substr(0,16) == "-D__U_COMPILER__" ) {
            compiler_name = arg.substr( 16+1 );
          } else if ( arg.substr(0,19) == "-D__U_GCC_BPREFIX__" ) {
            bprefix = arg.substr( 19+1 );
          } else if ( arg.substr(0,19) == "-D__U_GCC_MACHINE__" ) {
            args[nargs] = ( *new string( arg.substr( 19+1 ) ) ).c_str(); // pass the argument along
            nargs += 1;
          } else if ( arg.substr(0,19) == "-D__U_GCC_VERSION__" ) {
            args[nargs] = ( *new string( arg.substr( 19+1 ) ) ).c_str(); // pass the argument along
            nargs += 1;

          // u++ flags controlling the u++-cpp step

          } else if ( arg == "-D__U_YIELD__" || arg == "-D__U_VERIFY__" || arg == "-D__U_PROFILE__" ) {
            args[nargs] = argv[i];              // pass the flag along to cpp
            nargs += 1;
            uargs[nuargs] = argv[i];            // pass the flag along to upp
            nuargs += 1;

          // all other flags

          } else if ( arg == "-o" ) {
              i += 1;
              o_name = argv[i];
          } else {
            args[nargs] = argv[i];              // pass the flag along
            nargs += 1;
            // CPP flags with an argument
            if ( arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" ||
                 arg == "-include" || arg == "-imacros" || arg == "-idirafter" || arg == "-iprefix" ||
                 arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" ) {
                i += 1;
                args[nargs] = argv[i];          // pass the argument along
                nargs += 1;
#ifdef __U_DEBUG_H__
                cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
#endif // __U_DEBUG_H__
            } else if ( arg == "-MD" || arg == "-MMD" ) {
                args[nargs] = "-MF";            // insert before file
                nargs += 1;
                i += 1;
                args[nargs] = argv[i];          // pass the argument along
                nargs += 1;
#ifdef __U_DEBUG_H__
                cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
#endif // __U_DEBUG_H__
            } // if
          } // if
      } else {                            // obtain input and possibly output files
          if ( cpp_in == NULL ) {
            cpp_in = argv[i];
#ifdef __U_DEBUG_H__
            cerr << "cpp_in:\"" << cpp_in << "\"" << endl;
#endif // __U_DEBUG_H__
          } else if ( cpp_out == NULL ) {
            cpp_out = argv[i];
#ifdef __U_DEBUG_H__
            cerr << "cpp_out:\"" << cpp_out << "\""<< endl;
#endif // __U_DEBUG_H__
          } else {
            fprintf( stderr, "Usage: %s input-file [output-file] [options]\n", argv[0] );
            exit( 1 );
          } // if
      } // if
    } // for

#ifdef __U_DEBUG_H__
    cerr << "args:";
    for ( i = 1; i < nargs; i += 1 ) {
      cerr << " " << args[i];
    } // for
    if ( cpp_in != NULL ) cerr << " " << cpp_in;
    if ( cpp_out != NULL ) cerr << " " << cpp_out;
    cerr << endl;
#endif // __U_DEBUG_H__

    if ( cpp_in == NULL ) {
      fprintf( stderr, "Usage: %s input-file [output-file] [options]\n", argv[0] );
      exit( 1 );
    } // if

    if ( cpp_flag || ! cxx_flag ) {
      // The -E flag is specified on the u++ command so only run the
      // preprocessor and output is written to standard output or -o. The g++
      // command does not pass the -E flag from the command line.

      args[0] = compiler_name.c_str();
      args[nargs] = cpp_in;
      nargs += 1;
      args[nargs] = "-E";
      nargs += 1;
      if ( o_name != NULL ) {                   // location for output
          args[nargs] = "-o";
          nargs += 1;
          args[nargs] = o_name;
          nargs += 1;
      } else if ( cpp_out != NULL ) {                 // location for output
          args[nargs] = "-o";
          nargs += 1;
          args[nargs] = cpp_out;
          nargs += 1;
      } // if
      args[nargs] = NULL;                       // terminate argument list

#ifdef __U_DEBUG_H__
      cerr << "nargs: " << nargs << endl;
      for ( i = 0; args[i] != NULL; i += 1 ) {
          cerr << args[i] << " ";
      } // for
      cerr << endl;
#endif // __U_DEBUG_H__

      execvp( args[0], (char *const *)args );         // should not return
      perror( "uC++ Translator error: cpp level, execvp" );
      exit( -1 );
    } // if

    // Create a temporary file to store output of the C preprocessor.

    char tmpname[] = P_tmpdir "/uC++XXXXXX";
    int tmpfile = mkstemp( tmpname );
    if ( tmpfile == -1 ) {
      perror( "uC++ Translator error: cpp level, mkstemp" );
      exit( -1 );
    } // if

#ifdef __U_DEBUG_H__
    cerr << "tmpname:" << tmpname << " tmpfile:" << tmpfile << endl;
#endif // __U_DEBUG_H__

    // Run the C preprocessor and save the output in tmpfile.

    if ( fork() == 0 ) {                        // child process ?
      // -o xxx.ii cannot be used to write the output file from cpp because
      // no output file is created if cpp detects an error (e.g., cannot find
      // include file). Whereas, output is always generated, even when there
      // is an error, when cpp writes to stdout. Hence, stdout is redirected
      // into the temporary file.
      if ( freopen( tmpname, "w", stdout ) == NULL ) { // redirect stdout to tmpname
          perror( "uC++ Translator error: cpp level, freopen" );
          exit( -1 );
      } // if
      args[0] = compiler_name.c_str();
      args[nargs] = "-E";
      nargs += 1;
      args[nargs] = cpp_in;                     // input to cpp
      nargs += 1;
      args[nargs] = NULL;                       // terminate argument list

#ifdef __U_DEBUG_H__
      cerr << "cpp nargs: " << nargs << endl;
      for ( i = 0; args[i] != NULL; i += 1 ) {
          cerr << args[i] << " ";
      } // for
      cerr << endl;
#endif // __U_DEBUG_H__

      execvp( args[0], (char *const *)args );         // should not return
      perror( "uC++ Translator error: cpp level, execvp" );
      exit( -1 );
    } // if

    wait( &code );                              // wait for child to finish

#ifdef __U_DEBUG_H__
    cerr << "return code from cpp:" << WEXITSTATUS(code) << endl;
#endif // __U_DEBUG_H__

    if ( WIFSIGNALED(code) ) {                        // child failed ?
      unlink( tmpname );                        // remove tmpname
      fprintf( stderr, "uC++ Translator error: cpp failed with signal %d\n", WTERMSIG(code) );
      exit( -1 );
    } // if

    if ( WEXITSTATUS(code) != 0 ) {             // child error ?
      unlink( tmpname );                        // remove tmpname
      exit( WEXITSTATUS(code) );                // do not continue
    } // if

    // If -U++ flag specified, run the u++-cpp preprocessor on the temporary
    // file, and output is written to standard output.  Otherwise, run the
    // u++-cpp preprocessor on the temporary file and save the result into the
    // output file.

    if ( upp_flag || fork() == 0 ) {                  // conditional fork ?
      uargs[0] = ( *new string( bprefix + "/u++-cpp" ) ).c_str();

      uargs[nuargs] = tmpname;
      nuargs += 1;
      if ( o_name != NULL ) {
          uargs[nuargs] = o_name;
          nuargs += 1;
      } else if ( ! upp_flag ) {                // run u++-cpp ?
          uargs[nuargs] = cpp_out;
          nuargs += 1;
      } // if
      uargs[nuargs] = NULL;                     // terminate argument list

#ifdef __U_DEBUG_H__
      cerr << "u++-cpp nuargs: " << nuargs << endl;
      for ( i = 0; uargs[i] != NULL; i += 1 ) {
          cerr << uargs[i] << " ";
      } // for
      cerr << endl;
#endif // __U_DEBUG_H__

      execvp( uargs[0], (char * const *)uargs );      // should not return
      perror( "uC++ Translator error: cpp level, execvp" );
      exit( -1 );
    } // if

    wait( &code );                              // wait for child to finish

#ifdef __U_DEBUG_H__
    cerr << "return code from u++-cpp:" << WEXITSTATUS(code) << endl;
#endif // __U_DEBUG_H__

    // Must unlink here because file must exist across execvp.
    if ( unlink( tmpname ) == -1 ) {
      perror( "uC++ Translator error: cpp level, unlink" );
      exit( -1 );
    } // if

    if ( WIFSIGNALED(code) ) {                        // child failed ?
      fprintf( stderr, "uC++ Translator error: u++-cpp failed with signal %d\n", WTERMSIG(code) );
      exit( -1 );
    } // if

    exit( WEXITSTATUS(code) );
} // main


// Local Variables: //
// compile-command: "gmake install" //
// End: //

Generated by  Doxygen 1.6.0   Back to index