1/* c-arcmt-test.c */
2
3#include "clang-c/Index.h"
4#include <stdlib.h>
5#include <stdio.h>
6#include <string.h>
7#if defined(_WIN32)
8#include <io.h>
9#include <fcntl.h>
10#endif
11
12static int print_remappings(const char *path) {
13  CXRemapping remap;
14  unsigned i, N;
15  CXString origFname;
16  CXString transFname;
17
18  remap = clang_getRemappings(path);
19  if (!remap)
20    return 1;
21
22  N = clang_remap_getNumFiles(remap);
23  for (i = 0; i != N; ++i) {
24    clang_remap_getFilenames(remap, i, &origFname, &transFname);
25
26    fprintf(stdout, "%s\n", clang_getCString(origFname));
27    fprintf(stdout, "%s\n", clang_getCString(transFname));
28
29    clang_disposeString(origFname);
30    clang_disposeString(transFname);
31  }
32
33  clang_remap_dispose(remap);
34  return 0;
35}
36
37static int print_remappings_filelist(const char **files, unsigned numFiles) {
38  CXRemapping remap;
39  unsigned i, N;
40  CXString origFname;
41  CXString transFname;
42
43  remap = clang_getRemappingsFromFileList(files, numFiles);
44  if (!remap)
45    return 1;
46
47  N = clang_remap_getNumFiles(remap);
48  for (i = 0; i != N; ++i) {
49    clang_remap_getFilenames(remap, i, &origFname, &transFname);
50
51    fprintf(stdout, "%s\n", clang_getCString(origFname));
52    fprintf(stdout, "%s\n", clang_getCString(transFname));
53
54    clang_disposeString(origFname);
55    clang_disposeString(transFname);
56  }
57
58  clang_remap_dispose(remap);
59  return 0;
60}
61
62/******************************************************************************/
63/* Command line processing.                                                   */
64/******************************************************************************/
65
66static void print_usage(void) {
67  fprintf(stderr,
68    "usage: c-arcmt-test -mt-migrate-directory <path>\n"
69    "       c-arcmt-test <remap-file-path1> <remap-file-path2> ...\n\n\n");
70}
71
72/***/
73
74int carcmttest_main(int argc, const char **argv) {
75  clang_enableStackTraces();
76  if (argc == 3 && strncmp(argv[1], "-mt-migrate-directory", 21) == 0)
77    return print_remappings(argv[2]);
78
79  if (argc > 1)
80    return print_remappings_filelist(argv+1, argc-1);
81
82  print_usage();
83  return 1;
84}
85
86/***/
87
88/* We intentionally run in a separate thread to ensure we at least minimal
89 * testing of a multithreaded environment (for example, having a reduced stack
90 * size). */
91
92typedef struct thread_info {
93  int argc;
94  const char **argv;
95  int result;
96} thread_info;
97void thread_runner(void *client_data_v) {
98  thread_info *client_data = client_data_v;
99  client_data->result = carcmttest_main(client_data->argc, client_data->argv);
100}
101
102static void flush_atexit(void) {
103  /* stdout, and surprisingly even stderr, are not always flushed on process
104   * and thread exit, particularly when the system is under heavy load. */
105  fflush(stdout);
106  fflush(stderr);
107}
108
109int main(int argc, const char **argv) {
110  thread_info client_data;
111
112  atexit(flush_atexit);
113
114#if defined(_WIN32)
115  if (getenv("LIBCLANG_LOGGING") == NULL)
116    putenv("LIBCLANG_LOGGING=1");
117  _setmode( _fileno(stdout), _O_BINARY );
118#else
119  setenv("LIBCLANG_LOGGING", "1", /*overwrite=*/0);
120#endif
121
122  if (getenv("CINDEXTEST_NOTHREADS"))
123    return carcmttest_main(argc, argv);
124
125  client_data.argc = argc;
126  client_data.argv = argv;
127  clang_executeOnThread(thread_runner, &client_data, 0);
128  return client_data.result;
129}
130