Beispiel #1
0
/**
 * Reads a colon separated list from the given environment variable and tries
 * to match to the given program name. If one program matches (from the list)
 * to the given program name, then it will return a non zero value.
 *
 * On any error or mismatch the function returns 0.
 *
 * @param envVar_ the name of environment variable.
 * @param progName_ program name to match.
 * @return non zero on match, 0 otherwise
 */
static int matchToProgramList(
  const char* envVar_,
  const char* progName_)
{
  char* progList;
  char* token;
  const char* progListVar = getenv(envVar_);
  if (!progListVar)
  {
    return 0;
  }

  progList = loggerStrDup(progListVar);
  if (!progList)
  {
    return 0;
  }

  token = strtok(progList, PROG_LIST_SEPARATOR);
  while (token)
  {
    if (strstr(progName_, token))
    {
      /* Match! */
      free(progList);
      return 1;
    }

    token = strtok(NULL, PROG_LIST_SEPARATOR);
  }

  free(progList);
  return 0;
}
/**
 * Reads the arguments from a file (for ant support).
 *
 * @param file_ a file that contains the sources.
 * @param args_ a vector for arguments.
 */
static void readArgumentsFromFile(const char* file_, LoggerVector* args_)
{
  char* line = NULL;
  size_t lineSize = 0;
  ssize_t readSize;
  
  FILE* file = fopen(file_, "r");
  if (!file)
  {
    return;
  }

  while ((readSize = getline(&line, &lineSize, file)) > 0)
  {
    char* cont;
    char* normLine;

    /* The file may contain '"' character at the begining and the end of the
     * line, so we have to cut them off. */
    for (cont = line; cont[0] && (isspace(cont[0]) || cont[0] == '"');++cont){}
    normLine = loggerStrDup(cont);
    for (cont = normLine; cont[0] && cont[0] != '"'; ++cont) {}
    *cont = 0;

    loggerVectorAdd(args_, normLine);
  }

  fclose(file);
}
/**
 * This function inserts the paths from the given environment variable to the
 * vector.
 *
 * Implementation details: This function is used to fetch the value in any of
 * CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH variables.
 * These contain paths separated by colon. An empty path means the current
 * working directory
 * (see https://gcc.gnu.org/onlinedocs/cpp/Environment-Variables.html).
 *
 * &param paths_ A vector in which the items from envVar_ are added.
 * @param envVar_ An environment variable which contains paths separated by
 * color (:) character. If no such environment variable is set then the vector
 * remains untouched.
 * @param flag_ A flag which is also inserted before each element in the vector
 * as another element (e.g. -I or -isystem). If this is a NULL pointer then
 * this flag will not be inserted in the vector.
 */
void getPathsFromEnvVar(
  LoggerVector* paths_,
  const char* envVar_,
  const char* flag_)
{
  char* env;

  env = getenv(envVar_);

  if (!env)
    return;

  const char* from = env;
  const char* to = strchr(env, ':');

  while (to)
  {
    char token[PATH_MAX];
    size_t length = to - from;
    strncpy(token, from, length);
    token[length] = 0;
    from = to + 1;
    to = strchr(from, ':');

    if (flag_)
      loggerVectorAdd(paths_, loggerStrDup(flag_));

    if (strcmp(token, "") == 0)
      loggerVectorAdd(paths_, loggerStrDup("."));
    else
      loggerVectorAdd(paths_, loggerStrDup(token));
  }

  loggerVectorAdd(paths_, loggerStrDup(flag_));
  if (*from == 0)
    loggerVectorAdd(paths_, loggerStrDup("."));
  else
    loggerVectorAdd(paths_, loggerStrDup(from));
}
Beispiel #4
0
/**
 * Processes an command line argument for a GCC like command.
 *
 * @param state_ the current state of the parser.
 * @param arg_ the current command line argument.
 * @param action the current action.
 * @return the new state.
 */
static GccArgsState processArgument(
  GccArgsState state_,
  const char* arg_,
  LoggerAction* action_)
{
  char argToAdd[PATH_MAX];
  strcpy(argToAdd, arg_);

  if (state_ == InOutputArg)
  {
    if (!loggerMakePathAbs(arg_, argToAdd, 0))
    {
      strcpy(argToAdd, arg_);
    }

    loggerFileInitFromPath(&action_->output, argToAdd);
    state_ = Normal;
  }
  else if (strcmp(arg_, "-o") == 0)
  {
    state_ = InOutputArg;
  }
  else if (arg_[0] == '-' && (arg_[1] == 'I' || arg_[1] == 'L') && arg_[2])
  {
    /* This is a -I or -L option with a path */
    char fullPath[PATH_MAX];
    if (loggerMakePathAbs(arg_ + 2, fullPath, 0))
    {
      argToAdd[2] = 0;
      strcat(argToAdd, fullPath);
    }
  }
  else
  {
    char fullPath[PATH_MAX];
    if (loggerMakePathAbs(argToAdd, fullPath, 1))
    {
      char* ext = loggerGetFileExt(fullPath, 1);
      if (ext)
      {
        int i;
        for (i = 0; srcExts[i]; ++i)
        {
          if (strcmp(srcExts[i], ext) == 0)
          {
            strcpy(argToAdd, fullPath);
            loggerVectorAddUnique(&action_->sources,  loggerStrDup(fullPath),
              (LoggerCmpFuc) &strcmp);
            break;
          }
        }
      }

      free(ext);
    }
  }

  if (argToAdd[0])
  {
    loggerVectorAdd(&action_->arguments, loggerStrDup(argToAdd));
  }

  return state_;
}
Beispiel #5
0
int loggerGccParserCollectActions(
  const char* prog_,
  const char* toolName_,
  const char* const argv_[],
  LoggerVector* actions_)
{
  size_t i;
  /* Position of the last include path + 1 */
  size_t lastIncPos = 1;
  GccArgsState state = Normal;
  LoggerAction* action = loggerActionNew(toolName_);

  loggerVectorAdd(&action->arguments, loggerStrDup(toolName_));

  for (i = 1; argv_[i]; ++i)
  {
    state = processArgument(state, argv_[i], action);
    if (argv_[i][0] == '-' && argv_[i][1] == 'I')
    {
      if (argv_[i][2])
      {
        /* -I with path argument */
        lastIncPos = action->arguments.size;
      }
      else
      {
        /* The path should be the next argument */
        lastIncPos = action->arguments.size + 1;
      }
    }
  }

  if (!getenv("CC_LOGGER_NO_DEF_DIRS"))
  {
    LoggerVector defIncludes;
    loggerVectorInit(&defIncludes);

    getDefaultArguments(prog_, &defIncludes);
    if (defIncludes.size)
    {
      loggerVectorAddFrom(&action->arguments, &defIncludes,
        &lastIncPos, (LoggerDupFuc) &loggerStrDup);
    }

    loggerVectorClear(&defIncludes);
  }

  /*
   * Workaround for -MT and friends: if the source set contains the output,
   * then we have to remove it from the set.
   */
  i = loggerVectorFind(&action->sources, action->output.path,
    (LoggerCmpFuc) &strcmp);
  if (i != SIZE_MAX)
  {
    loggerVectorErase(&action->sources, i);
  }

  loggerVectorAdd(actions_, action);
  return 1;
}
Beispiel #6
0
/**
 * Tries to get the default header includes from a gcc(like) command and stores
 * the result into the given vector.
 *
 * @param prog_ the gcc like program / command.
 * @param args_ a vector for the arguments.
 */
static void getDefaultArguments(const char* prog_, LoggerVector* args_)
{
  char command[PATH_MAX];
  FILE* cmdOut;
  char* line = NULL;
  size_t lineSize = 0;
  ssize_t readSize;
  int incStarted = 0;

  strcpy(command, prog_);
  strcat(command, " -xc++ -E -v - < /dev/null 2>&1");

  cmdOut = popen(command, "r");
  if (!cmdOut)
  {
    return;
  }

  while ((readSize = getline(&line, &lineSize, cmdOut)) >= 0)
  {
    char fullPath[PATH_MAX] = "-I";
    char* pathEnd;
    char* pathStart;

    if (!incStarted)
    {
      if (strstr(line, "#include <...> search starts here"))
      {
        incStarted = 1;
      }
      continue;
    }
    else if (strstr(line, "End of search list"))
    {
      break;
    }

    /* Drop the new line character from the end of the line and the leading
       whitespaces. */
    for (pathStart = line; *pathStart && isspace(*pathStart); ++pathStart) {}
    for (pathEnd = pathStart; *pathEnd && !isspace(*pathEnd); ++pathEnd) {}
    *pathEnd = 0;
    if (pathStart[0] == 0)
    {
      /* WTF??? */
      continue;
    }

    if (!loggerMakePathAbs(pathStart, fullPath + 2, 0))
    {
      /* Invalid path, skip */
      continue;
    }

    if (isGccLibPath(fullPath))
    {
      /* We have to skip builtin gcc headers, we only need the paths to the
         stdlib */
      continue;
    }


    loggerVectorAdd(args_, loggerStrDup(fullPath));
  }

  free(line);
  pclose(cmdOut);
}
/**
 * Processes an command line argument for a GCC like command.
 *
 * @param state_ the current state of the parser.
 * @param arg_ the current command line argument.
 * @param action the current action.
 * @return the new state.
 */
static GccArgsState processArgument(
  GccArgsState state_,
  const char* arg_,
  LoggerAction* action_)
{
  char argToAdd[PATH_MAX];
  strcpy(argToAdd, arg_);

  if (state_ == InOutputArg)
  {
    if (!loggerMakePathAbs(arg_, argToAdd, 0))
    {
      strcpy(argToAdd, arg_);
    }

    loggerFileInitFromPath(&action_->output, argToAdd);
    state_ = Normal;
  }
  else if (strcmp(arg_, "-o") == 0)
  {
    state_ = InOutputArg;
  }
  else if (arg_[0] == '-' && ((arg_[1] == 'W' && (arg_[2] == 'l' || arg_[2] == 'p')) || arg_[1] == 'M'))
  {
    /* This is a -Wl linker option
     *  -Wl,-Map,output.map
     *  or a -Wp prepocessor option
     *  -Wp,option
     *  also matches for options like -Wpedantic
     *  handled here to skip for matching source files in
     *  these arguments
     */
    strcpy(argToAdd, arg_);
  }
  else if (arg_[0] == '-' && arg_[1] == 'D')
  {
    /*  Match for macro definition -D
     *  handled here to skip for matching source files in
     *  these arguments
     */
    strcpy(argToAdd, arg_);
  }
  else if (arg_[0] == '-' && (arg_[1] == 'I' || arg_[1] == 'L') && arg_[2])
  {
    /* This is a -I or -L option with a path */
    char fullPath[PATH_MAX];
    if (loggerMakePathAbs(arg_ + 2, fullPath, 0))
    {
      argToAdd[2] = 0;
      strcat(argToAdd, fullPath);
    }
  }
  else
  {
    char fullPath[PATH_MAX];
    if (loggerMakePathAbs(argToAdd, fullPath, 1))
    {
      char* ext = loggerGetFileExt(fullPath, 1);
      if (ext)
      {
        int i;
        for (i = 0; srcExts[i]; ++i)
        {
          if (strcmp(srcExts[i], ext) == 0)
          {
            strcpy(argToAdd, fullPath);
            loggerVectorAddUnique(&action_->sources,  loggerStrDup(fullPath),
              (LoggerCmpFuc) &strcmp);
            break;
          }
        }
      }

      free(ext);
    }
  }

  if (argToAdd[0])
  {
    loggerVectorAdd(&action_->arguments, loggerStrDup(argToAdd));
  }

  return state_;
}
int loggerGccParserCollectActions(
  const char* prog_,
  const char* toolName_,
  const char* const argv_[],
  LoggerVector* actions_)
{
  enum Language { C, CPP, OBJC } lang = CPP;

  size_t i;
  /* Position of the last include path + 1 */
  char full_prog_path[PATH_MAX+1];
  char *path_ptr;

  size_t lastIncPos = 1;
  size_t lastSysIncPos = 1;
  GccArgsState state = Normal;
  LoggerAction* action = loggerActionNew(toolName_);

  char* keepLinkVar = getenv("CC_LOGGER_KEEP_LINK");
  int keepLink = keepLinkVar && strcmp(keepLinkVar, "true") == 0;

  /* If prog_ is a relative path we try to
   * convert it to absolute path.
   */
  path_ptr = realpath(prog_, full_prog_path);

  /* If we cannot convert it, we try to find the
   * executable in the PATH.
   */
  if (!path_ptr)
	  path_ptr = findFullPath(toolName_, full_prog_path);
  if (path_ptr) /* Log compiler with full path. */
	  loggerVectorAdd(&action->arguments, loggerStrDup(full_prog_path));
  else  /* Compiler was not found in path, log the binary name only. */
  	  loggerVectorAdd(&action->arguments, loggerStrDup(toolName_));

  /* Determine programming language based on compiler name. */
  for (i = 0; cCompiler[i]; ++i)
    if (strstr(toolName_, cCompiler[i]))
      lang = C;

  for (i = 0; cppCompiler[i]; ++i)
    if (strstr(toolName_, cppCompiler[i]))
      lang = CPP;

  for (i = 1; argv_[i]; ++i)
  {
    const char* current = argv_[i];
    state = processArgument(state, current, action);

    if (current[0] == '-')
    {
      /* Determine the position of the last -I and -isystem flags.
       * Depending on whether the parameter of -I or -isystem is separated
       * from the flag by a space character.
       * 2 == strlen("-I") && 8 == strlen("-isystem")
       */
      if (current[1] == 'I')
        lastIncPos = action->arguments.size + (current[2] ? 0 : 1);
      else if (strstr(current, "-isystem") == current)
        lastSysIncPos = action->arguments.size + (current[8] ? 0 : 1);

      /* Determine the programming language based on -x flag.
       */
      else if (strcmp(current, "-x") == 0)
      {
        /* TODO: The language value after -x can be others too. See the man
         * page of GCC.
         * TODO: According to a GCC warning the -x flag has no effect when it
         * is placed after the last input file to be compiled.
         */
        const char* l = argv_[i + 1];
        if (strcmp(l, "c") == 0 || strcmp(l, "c-header") == 0)
          lang = C;
        else if (strcmp(l, "c++") == 0 || strcmp(l, "c++-header") == 0)
          lang = CPP;
      }
    }
  }

  if (getenv("CC_LOGGER_DEF_DIRS"))
  {
    LoggerVector defIncludes;
    loggerVectorInit(&defIncludes);

    getDefaultArguments(prog_, &defIncludes);
    if (defIncludes.size)
    {
      loggerVectorAddFrom(&action->arguments, &defIncludes,
        &lastIncPos, (LoggerDupFuc) &loggerStrDup);

      if (lastSysIncPos > lastIncPos)
        lastSysIncPos += defIncludes.size;

      lastIncPos += defIncludes.size;
    }

    loggerVectorClear(&defIncludes);
  }

  if (getenv("CPATH"))
  {
    LoggerVector includes;
    loggerVectorInit(&includes);

    getPathsFromEnvVar(&includes, "CPATH", "-I");
    if (includes.size)
    {
      loggerVectorAddFrom(&action->arguments, &includes,
        &lastIncPos, (LoggerDupFuc) &loggerStrDup);

      if (lastSysIncPos > lastIncPos)
        lastSysIncPos += includes.size;

      lastIncPos += includes.size;
    }

    loggerVectorClear(&includes);
  }

  if (lang == CPP && getenv("CPLUS_INCLUDE_PATH"))
  {
    LoggerVector includes;
    loggerVectorInit(&includes);

    getPathsFromEnvVar(&includes, "CPLUS_INCLUDE_PATH", "-isystem");
    if (includes.size)
    {
      loggerVectorAddFrom(&action->arguments, &includes,
        &lastSysIncPos, (LoggerDupFuc) &loggerStrDup);
    }

    loggerVectorClear(&includes);
  }
  else if (lang == C && getenv("C_INCLUDE_PATH"))
  {
    LoggerVector includes;
    loggerVectorInit(&includes);

    getPathsFromEnvVar(&includes, "C_INCLUDE_PATH", "-isystem");
    if (includes.size)
    {
      loggerVectorAddFrom(&action->arguments, &includes,
        &lastSysIncPos, (LoggerDupFuc) &loggerStrDup);
    }

    loggerVectorClear(&includes);
  }

  /*
   * Workaround for -MT and friends: if the source set contains the output,
   * then we have to remove it from the set.
   */
  i = loggerVectorFind(&action->sources, action->output.path,
    (LoggerCmpFuc) &strcmp);
  if (i != SIZE_MAX)
  {
    loggerVectorErase(&action->sources, i);
  }

  if (!keepLink)
    do {
      i = loggerVectorFindIf(&action->sources, (LoggerPredFuc) &isObjectFile);
      loggerVectorErase(&action->sources, i);
    } while (i != SIZE_MAX);

  if (action->sources.size != 0)
    loggerVectorAdd(actions_, action);

  return 1;
}
int loggerJavacParserCollectActions(
  const char* prog_,
  const char* toolName_,
  const char* const argv_[],
  LoggerVector* actions_)
{
  ParserData data;
  size_t i;

  assert(prog_ == prog_); /* suppress unused variable */

  data.hasSourcePath = 0;
  data.state = Normal;
  loggerVectorInit(&data.commonArgs);
  loggerVectorInit(&data.sources);
  memset(data.classdir, 0, sizeof(data.classdir));

  loggerVectorAdd(&data.commonArgs, loggerStrDup(toolName_));

  for (i = 1; argv_[i]; ++i)
  {
    if (argv_[i][0] == '@')
    {
      size_t j;
      LoggerVector fargs;

      loggerVectorInit(&fargs);
      
      readArgumentsFromFile(argv_[i] + 1, &fargs);
      for (j = 0; j < fargs.size; ++j)
      {
        processArg((const char*) fargs.data[j], &data);
      }

      loggerVectorClear(&fargs);
    }
    else
    {
      processArg(argv_[i], &data);
    }
  }

  if (!data.hasSourcePath)
  {
    char workdir[PATH_MAX];
    if (loggerMakePathAbs(".", workdir, 0))
    {
      loggerVectorAdd(&data.commonArgs, loggerStrDup("-sourcepath"));
      loggerVectorAdd(&data.commonArgs, loggerStrDup(workdir));
    }
  }

  for (i = 0; i < data.sources.size; ++i)
  {
    char outputFile[PATH_MAX];
    const char* src = (char*) data.sources.data[i];
    LoggerAction* action = loggerActionNew(toolName_);
    if (!action)
    {
      continue;
    }

    loggerVectorAddFrom(&action->arguments, &data.commonArgs,
      NULL, (LoggerDupFuc) &loggerStrDup);
    loggerVectorAdd(&action->arguments, loggerStrDup(src));
    loggerVectorAdd(&action->sources, loggerStrDup(src));

    if (data.classdir[0] != 0)
    {
      char* fname = loggerGetFileName(src, 1);
      strcpy(outputFile, data.classdir);
      strcat(outputFile, "/");
      strcat(outputFile, fname);
      strcat(outputFile, ".class");
      free(fname);
    }
    else
    {
      char* path = loggerGetFilePathWithoutExt(src);
      strcpy(outputFile, path);
      strcat(outputFile, ".class");
      free(path);
    }

    loggerFileInitFromPath(&action->output, outputFile);
    loggerVectorAdd(actions_, action);
  }

  loggerVectorClear(&data.commonArgs);
  loggerVectorClear(&data.sources);

  return 1;
}
/**
 * Processes a single argument.
 *
 * @param arg_ the current argument.
 * @param data_ the state data of the parser function.
 */
static void processArg(const char* arg_, ParserData* data_)
{
  size_t argToAddSize = PATH_MAX;
  char* argToAdd ;
  char* ext;

  argToAdd = (char*) malloc(sizeof(char) * argToAddSize);
  if (!argToAdd)
  {
    /* NO MEM! */
    return;
  }

  strcpy(argToAdd, arg_);

  if (data_->state == InClassDir)
  {
    if (!loggerMakePathAbs(arg_, data_->classdir, 0))
    {
      strcpy(data_->classdir, arg_);
    }

    strcpy(argToAdd, data_->classdir);
    data_->state = Normal;
  }
  else if (data_->state == InClassPath)
  {
    handleClassPath(&argToAdd, &argToAddSize, arg_);
    data_->state = Normal;
  }
  else if (strcmp(arg_, "-sourcepath") == 0)
  {
    data_->hasSourcePath = 1;
  }
  else if (strcmp(arg_, "-d") == 0)
  {
    data_->state = InClassDir;
  }
  else if (strcmp(arg_, "-cp") == 0 || strcmp(arg_, "-classpath") == 0)
  {
    data_->state = InClassPath;
  }
  else if ((ext = loggerGetFileExt(arg_, 1)))
  {
    int isSource = 0;
    if (strcmp(ext, "java") == 0)
    {
      char path[PATH_MAX];
      if (loggerMakePathAbs(arg_, path, 0))
      {
        loggerVectorAddUnique(&data_->sources,
          loggerStrDup(path), (LoggerCmpFuc) &strcmp);
        isSource = 1;
      }
    }

    if (isSource)
    {
      argToAdd[0] = 0;
    }

    free(ext);
  }

  if (argToAdd[0])
  {
    loggerVectorAdd(&data_->commonArgs, loggerStrDup(argToAdd));
  }

  free(argToAdd);
}