int main()

in compiler/cpp/src/thrift/main.cc [1077:1312]


int main(int argc, char** argv) {
  int i;
  std::string out_path;
  bool out_path_is_absolute = false;

  // Setup time string
  time_t now = time(nullptr);
  g_time_str = ctime(&now);

  // Check for necessary arguments, you gotta have at least a filename and
  // an output language flag
  if (argc < 2) {
    usage();
  }

  vector<string> generator_strings;
  string old_thrift_include_path;
  string new_thrift_include_path;
  string old_input_file;

  // Set the current path to a dummy value to make warning messages clearer.
  g_curpath = "arguments";

  // Hacky parameter handling... I didn't feel like using a library sorry!
  for (i = 1; i < argc - 1; i++) {
    char* arg;

    arg = strtok(argv[i], " ");
    while (arg != nullptr) {
      // Treat double dashes as single dashes
      if (arg[0] == '-' && arg[1] == '-') {
        ++arg;
      }

      if (strcmp(arg, "-help") == 0) {
        help();
      } else if (strcmp(arg, "-version") == 0) {
        version();
        exit(0);
      } else if (strcmp(arg, "-debug") == 0) {
        g_debug = 1;
      } else if (strcmp(arg, "-nowarn") == 0) {
        g_warn = 0;
      } else if (strcmp(arg, "-strict") == 0) {
        g_strict = 255;
        g_warn = 2;
      } else if (strcmp(arg, "-v") == 0 || strcmp(arg, "-verbose") == 0) {
        g_verbose = 1;
      } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-recurse") == 0) {
        gen_recurse = true;
      } else if (strcmp(arg, "-allow-neg-keys") == 0) {
        g_allow_neg_field_keys = true;
      } else if (strcmp(arg, "-allow-64bit-consts") == 0) {
        g_allow_64bit_consts = true;
      } else if (strcmp(arg, "-gen") == 0) {
        arg = argv[++i];
        if (arg == nullptr) {
          fprintf(stderr, "Missing generator specification\n");
          usage();
        }
        generator_strings.emplace_back(arg);
      } else if (strcmp(arg, "-I") == 0) {
        // An argument of "-I\ asdf" is invalid and has unknown results
        arg = argv[++i];

        if (arg == nullptr) {
          fprintf(stderr, "Missing Include directory\n");
          usage();
        }
        g_incl_searchpath.emplace_back(arg);
      } else if ((strcmp(arg, "-o") == 0) || (strcmp(arg, "-out") == 0)) {
        out_path_is_absolute = (strcmp(arg, "-out") == 0) ? true : false;
        arg = argv[++i];
        if (arg == nullptr) {
          fprintf(stderr, "-o: missing output directory\n");
          usage();
        }
        out_path = arg;

#ifdef _WIN32
        // strip out trailing \ on Windows
        std::string::size_type last = out_path.length() - 1;
        if (out_path[last] == '\\') {
          out_path.erase(last);
        }
#endif
        if (!check_is_directory(out_path.c_str()))
          return -1;
      } else if (strcmp(arg, "-audit") == 0) {
        g_audit = true;
        arg = argv[++i];
        if (arg == nullptr) {
          fprintf(stderr, "Missing old thrift file name for audit operation\n");
          usage();
        }
        char old_thrift_file_rp[THRIFT_PATH_MAX];

        // cppcheck-suppress uninitvar
        if (saferealpath(arg, old_thrift_file_rp) == nullptr) {
          failure("Could not open input file with realpath: %s", arg);
        }
        old_input_file = string(old_thrift_file_rp);
      } else if (strcmp(arg, "-audit-nofatal") == 0) {
        g_audit_fatal = false;
      } else if (strcmp(arg, "-Iold") == 0) {
        arg = argv[++i];
        if (arg == nullptr) {
          fprintf(stderr, "Missing Include directory for old thrift file\n");
          usage();
        }
        old_thrift_include_path = string(arg);
      } else if (strcmp(arg, "-Inew") == 0) {
        arg = argv[++i];
        if (arg == nullptr) {
          fprintf(stderr, "Missing Include directory for new thrift file\n");
          usage();
        }
        new_thrift_include_path = string(arg);
      } else {
        fprintf(stderr, "Unrecognized option: %s\n", arg);
        usage();
      }

      // Tokenize more
      arg = strtok(nullptr, " ");
    }
  }

  // display help
  if ((strcmp(argv[argc - 1], "-help") == 0) || (strcmp(argv[argc - 1], "--help") == 0)) {
    help();
  }

  // if you're asking for version, you have a right not to pass a file
  if ((strcmp(argv[argc - 1], "-version") == 0) || (strcmp(argv[argc - 1], "--version") == 0)) {
    version();
    exit(0);
  }

  // Initialize global types
  initGlobals();

  if (g_audit) {
    // Audit operation

    if (old_input_file.empty()) {
      fprintf(stderr, "Missing file name of old thrift file for audit\n");
      usage();
    }

    char new_thrift_file_rp[THRIFT_PATH_MAX];
    if (argv[i] == nullptr) {
      fprintf(stderr, "Missing file name of new thrift file for audit\n");
      usage();
    }
    // cppcheck-suppress uninitvar
    if (saferealpath(argv[i], new_thrift_file_rp) == nullptr) {
      failure("Could not open input file with realpath: %s", argv[i]);
    }
    string new_input_file(new_thrift_file_rp);

    t_program new_program(new_input_file);
    t_program old_program(old_input_file);

    audit(&new_program, &old_program, new_thrift_include_path, old_thrift_include_path);

  } else {
    // Generate options

    // You gotta generate something!
    if (generator_strings.empty()) {
      fprintf(stderr, "No output language(s) specified\n");
      usage();
    }

    // Real-pathify it
    char rp[THRIFT_PATH_MAX];
    if (argv[i] == nullptr) {
      fprintf(stderr, "Missing file name\n");
      usage();
    }
    // cppcheck-suppress uninitvar
    if (saferealpath(argv[i], rp) == nullptr) {
      failure("Could not open input file with realpath: %s", argv[i]);
    }
    string input_file(rp);

    // Instance of the global parse tree
    t_program* program = new t_program(input_file);
    if (out_path.size()) {
      program->set_out_path(out_path, out_path_is_absolute);
    }

    // Compute the cpp include prefix.
    // infer this from the filename passed in
    string input_filename = argv[i];
    string include_prefix;

    string::size_type last_slash = string::npos;
    if ((last_slash = input_filename.rfind("/")) != string::npos) {
      include_prefix = input_filename.substr(0, last_slash);
    }

    program->set_include_prefix(include_prefix);

    // Parse it!
    std::set<std::string> known_includes;
    parse(program, nullptr, known_includes);

    // The current path is not really relevant when we are doing generation.
    // Reset the variable to make warning messages clearer.
    g_curpath = "generation";
    // Reset yylineno for the heck of it.  Use 1 instead of 0 because
    // That is what shows up during argument parsing.
    yylineno = 1;

    // Generate it!
    generate(program, generator_strings);
    delete program;
  }

  // Clean up. Who am I kidding... this program probably orphans heap memory
  // all over the place, but who cares because it is about to exit and it is
  // all referenced and used by this wacky parse tree up until now anyways.
  clearGlobals();

  // Finished
  if (g_return_failure && g_audit_fatal) {
    exit(2);
  }
  if (g_generator_failure) {
    exit(3);
  }
  // Finished
  return 0;
}