zdsar.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  1. /****************************************************************************
  2. * tools/zds/zdsar.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <sys/stat.h>
  24. #include <stdbool.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <unistd.h>
  28. #include <string.h>
  29. #include <limits.h>
  30. #include <ctype.h>
  31. #include <libgen.h>
  32. #include <errno.h>
  33. #ifdef HOST_CYGWIN
  34. # include <sys/cygwin.h>
  35. #endif
  36. /****************************************************************************
  37. * Pre-processor Definitions
  38. ****************************************************************************/
  39. #define MAX_BUFFER (4096)
  40. #define MAX_EXPAND (2048)
  41. /* MAX_PATH might be defined in stdlib.h */
  42. #if !defined(MAX_PATH)
  43. # define MAX_PATH (512)
  44. #endif
  45. /* NAME_MAX is typically defined in limits.h */
  46. #if !defined(NAME_MAX)
  47. /* FILENAME_MAX might be defined in stdio.h */
  48. # if defined(FILENAME_MAX)
  49. # define NAME_MAX FILENAME_MAX
  50. # else
  51. /* MAXNAMELEN might be defined in dirent.h */
  52. # include <dirent.h>
  53. # if defined(MAXNAMLEN)
  54. # define NAME_MAX MAXNAMLEN
  55. # else
  56. /* Lets not let a silly think like this stop us... just make something up */
  57. # define NAME_MAX 256
  58. # endif
  59. # endif
  60. #endif
  61. /* Maximum objects per librarian call.
  62. *
  63. * REVISIT: The librarian is supposed to handle multiple object insertions
  64. * per call, but my experience was that it was unreliable in that case. That
  65. * may have improved, however, and perhaps we can increase MAX_OPBJEXT.. TRY
  66. * IT!
  67. */
  68. #define MAX_OBJECTS 1 /* 64 */
  69. /* Name of the host. The ZDS-II toolchain runs only on Windows. Therefore,
  70. * the only options are (1) Windows native, or (2) Cygwin or environments
  71. * that derive for Cygwin (like MSYS2).
  72. */
  73. #define WINSEPARATOR '\\'
  74. #if defined(HOST_NATIVE)
  75. # define SEPARATOR '\\'
  76. # define HOSTNAME "Native" /* Windows native */
  77. #elif defined(HOST_CYGWIN)
  78. # define SEPARATOR '/'
  79. # define HOSTNAME "Cygwin" /* Cygwin or MSYS under Windows */
  80. #endif
  81. /****************************************************************************
  82. * Private Data
  83. ****************************************************************************/
  84. static char *g_current_wd = NULL; /* Current working directory */
  85. static char *g_ar = NULL; /* Full path to the librarian program */
  86. static char *g_arflags = NULL; /* Flags to use with the librarian program */
  87. static char *g_libpath = NULL; /* Path to the library */
  88. static char *g_libname = NULL; /* Library file name*/
  89. static char *g_objects = NULL; /* List of object files */
  90. static int g_debug = 0; /* Debug output enabled if >0 */
  91. static char g_command[MAX_BUFFER]; /* Full librarian command */
  92. static char g_initial_wd[MAX_PATH]; /* Initial working directory */
  93. static char g_path[MAX_PATH]; /* Temporary for path generation */
  94. static char g_objpath[MAX_PATH]; /* Holds the relative path to the objects */
  95. #ifdef HOST_CYGWIN
  96. static char g_expand[MAX_EXPAND]; /* Temporary for quoted path */
  97. static char g_dequoted[MAX_PATH]; /* Temporary for de-quoted path */
  98. static char g_hostpath[MAX_PATH]; /* Temporary for host path conversions */
  99. #endif
  100. /****************************************************************************
  101. * Private Functions
  102. ****************************************************************************/
  103. /* MinGW does not seem to provide strtok_r */
  104. #ifndef HAVE_STRTOK_R
  105. static char *my_strtok_r(char *str, const char *delim, char **saveptr)
  106. {
  107. char *pbegin;
  108. char *pend = NULL;
  109. /* Decide if we are starting a new string or continuing from
  110. * the point we left off.
  111. */
  112. if (str)
  113. {
  114. pbegin = str;
  115. }
  116. else if (saveptr && *saveptr)
  117. {
  118. pbegin = *saveptr;
  119. }
  120. else
  121. {
  122. return NULL;
  123. }
  124. /* Find the beginning of the next token */
  125. for (;
  126. *pbegin && strchr(delim, *pbegin) != NULL;
  127. pbegin++);
  128. /* If we are at the end of the string with nothing
  129. * but delimiters found, then return NULL.
  130. */
  131. if (!*pbegin)
  132. {
  133. return NULL;
  134. }
  135. /* Find the end of the token */
  136. for (pend = pbegin + 1;
  137. *pend && strchr(delim, *pend) == NULL;
  138. pend++);
  139. /* pend either points to the end of the string or to
  140. * the first delimiter after the string.
  141. */
  142. if (*pend)
  143. {
  144. /* Turn the delimiter into a null terminator */
  145. *pend++ = '\0';
  146. }
  147. /* Save the pointer where we left off and return the
  148. * beginning of the token.
  149. */
  150. if (saveptr)
  151. {
  152. *saveptr = pend;
  153. }
  154. return pbegin;
  155. }
  156. #undef strtok_r
  157. # define strtok_r my_strtok_r
  158. #endif
  159. static void append(char **base, char *str)
  160. {
  161. char *oldbase;
  162. char *newbase;
  163. int alloclen;
  164. oldbase = *base;
  165. if (oldbase == NULL)
  166. {
  167. newbase = strdup(str);
  168. if (!newbase)
  169. {
  170. fprintf(stderr, "ERROR: Failed to strdup %s\n", str);
  171. exit(EXIT_FAILURE);
  172. }
  173. }
  174. else
  175. {
  176. alloclen = strlen(oldbase) + strlen(str) + sizeof((char) ' ') +
  177. sizeof((char) '\0');
  178. newbase = (char *)malloc(alloclen);
  179. if (!newbase)
  180. {
  181. fprintf(stderr, "ERROR: Failed to allocate %d bytes\n", alloclen);
  182. exit(EXIT_FAILURE);
  183. }
  184. snprintf(newbase, alloclen, "%s %s", oldbase, str);
  185. free(oldbase);
  186. }
  187. *base = newbase;
  188. }
  189. static const char *quote_backslash(const char *argument)
  190. {
  191. #ifdef HOST_CYGWIN
  192. const char *src;
  193. char *dest;
  194. int len;
  195. src = argument;
  196. dest = g_expand;
  197. len = 0;
  198. while (*src && len < MAX_EXPAND)
  199. {
  200. if (*src == '\\')
  201. {
  202. /* Copy backslash */
  203. *dest++ = *src++;
  204. if (++len >= MAX_EXPAND)
  205. {
  206. break;
  207. }
  208. /* Already quoted? */
  209. if (*src == '\\')
  210. {
  211. /* Yes... just copy all consecutive backslashes */
  212. do
  213. {
  214. *dest++ = *src++;
  215. if (++len >= MAX_EXPAND)
  216. {
  217. break;
  218. }
  219. }
  220. while (*src == '\\');
  221. }
  222. else
  223. {
  224. /* No.. expend */
  225. *dest++ = '\\';
  226. if (++len >= MAX_EXPAND)
  227. {
  228. break;
  229. }
  230. }
  231. }
  232. else
  233. {
  234. *dest++ = *src++;
  235. len++;
  236. }
  237. }
  238. if (*src)
  239. {
  240. fprintf(stderr, "ERROR: Truncated during expansion string "
  241. "is too long [%lu/%u]\n",
  242. (unsigned long)strlen(argument), MAX_EXPAND);
  243. exit(EXIT_FAILURE);
  244. }
  245. *dest = '\0';
  246. return g_expand;
  247. #else
  248. return argument;
  249. #endif
  250. }
  251. /* Remove backslash quoting from a path */
  252. #ifdef HOST_CYGWIN
  253. static bool dequote_path(const char *winpath)
  254. {
  255. char *dest = g_dequoted;
  256. const char *src = winpath;
  257. int len = 0;
  258. bool quoted = false;
  259. while (*src && len < MAX_PATH)
  260. {
  261. if (src[0] != '\\' ||
  262. (src[1] != ' ' && src[1] != '(' && src[1] != ')'))
  263. {
  264. *dest++ = *src;
  265. len++;
  266. }
  267. else
  268. {
  269. quoted = true;
  270. }
  271. src++;
  272. }
  273. if (*src || len >= MAX_PATH)
  274. {
  275. fprintf(stderr, "# ERROR: Path truncated\n");
  276. exit(EXIT_FAILURE);
  277. }
  278. *dest = '\0';
  279. return quoted;
  280. }
  281. #endif
  282. /* If using Cygwin with a Window's Toolchain, then we have to convert the
  283. * POSIX path to a Windows or POSIX path.
  284. */
  285. #ifdef HOST_CYGWIN
  286. static const char *convert_path(const char *path, cygwin_conv_path_t what)
  287. {
  288. const char *retptr;
  289. ssize_t size;
  290. ssize_t ret;
  291. bool quoted;
  292. quoted = dequote_path(path);
  293. if (quoted)
  294. {
  295. retptr = g_hostpath;
  296. }
  297. else
  298. {
  299. retptr = &g_hostpath[1];
  300. }
  301. size = cygwin_conv_path(what | CCP_RELATIVE, g_dequoted, NULL, 0);
  302. if (size > (MAX_PATH - 3))
  303. {
  304. fprintf(stderr, "# ERROR: POSIX path too long: %lu\n",
  305. (unsigned long)size);
  306. exit(EXIT_FAILURE);
  307. }
  308. ret = cygwin_conv_path(what | CCP_RELATIVE, g_dequoted,
  309. &g_hostpath[1], MAX_PATH - 3);
  310. if (ret < 0)
  311. {
  312. fprintf(stderr, "# ERROR: cygwin_conv_path '%s' failed: %s\n",
  313. g_dequoted, strerror(errno));
  314. exit(EXIT_FAILURE);
  315. }
  316. if (quoted)
  317. {
  318. size++;
  319. g_hostpath[0] = '"';
  320. g_hostpath[size] = '"';
  321. }
  322. g_hostpath[size + 1] = '\0';
  323. return retptr;
  324. }
  325. #endif
  326. static const char *convert_path_windows(const char *path)
  327. {
  328. #ifdef HOST_CYGWIN
  329. return convert_path(path, CCP_POSIX_TO_WIN_A);
  330. #else
  331. strcpy(g_path, path);
  332. return g_path;
  333. #endif
  334. }
  335. static const char *convert_path_posix(const char *path)
  336. {
  337. #ifdef HOST_CYGWIN
  338. return convert_path(path, CCP_WIN_A_TO_POSIX);
  339. #else
  340. strcpy(g_path, path);
  341. return g_path;
  342. #endif
  343. }
  344. static void show_usage(const char *progname, const char *msg, int exitcode)
  345. {
  346. if (msg)
  347. {
  348. fprintf(stderr, "\n");
  349. fprintf(stderr, "%s:\n", msg);
  350. }
  351. fprintf(stderr, "\n");
  352. fprintf(stderr, "%s [OPTIONS] --ar \"<AR>\" --library \"<LIBRARY>\" "
  353. "obj [obj [obj...]]\n",
  354. progname);
  355. fprintf(stderr, "\n");
  356. fprintf(stderr, "Where:\n");
  357. fprintf(stderr, " --ar <AR>\n");
  358. fprintf(stderr, " A command line string that defines how to execute the "
  359. "ZDS-II librarian\n");
  360. fprintf(stderr, " --library \"<LIBRARY>\"\n");
  361. fprintf(stderr, " The library into which the object files will be "
  362. "inserted\n");
  363. fprintf(stderr, " obj\n");
  364. fprintf(stderr, " One or more object files that will be inserted into "
  365. "the archive. Each expected\n");
  366. fprintf(stderr, " to reside in the current directory unless --obj-path "
  367. "is provided on the command line\n");
  368. fprintf(stderr, "\n");
  369. fprintf(stderr, "And [OPTIONS] include:\n");
  370. fprintf(stderr, " --ar_flags \"<ARFLAGS>\"\n");
  371. fprintf(stderr, " Optional librarian flags\n");
  372. fprintf(stderr, " --obj-path <path>\n");
  373. fprintf(stderr, " Do not look in the current directory for the object "
  374. "files. Instead, look in <path> for\n");
  375. fprintf(stderr, " the object files. --obj-path may be used only once "
  376. "on the command line\n");
  377. fprintf(stderr, " --debug\n");
  378. fprintf(stderr, " Enable %s debug output\n", progname);
  379. fprintf(stderr, " --help\n");
  380. fprintf(stderr, " Shows this message and exits\n");
  381. exit(exitcode);
  382. }
  383. static void parse_args(int argc, char **argv)
  384. {
  385. const char *tmp = NULL;
  386. char *library = NULL;
  387. char *objpath = NULL;
  388. int pathlen;
  389. int argidx;
  390. /* Parse arguments */
  391. for (argidx = 1; argidx < argc; argidx++)
  392. {
  393. if (strcmp(argv[argidx], "--ar") == 0)
  394. {
  395. argidx++;
  396. if (argidx >= argc)
  397. {
  398. show_usage(argv[0], "ERROR: Missing argument to --ar",
  399. EXIT_FAILURE);
  400. }
  401. else if (g_ar != NULL)
  402. {
  403. show_usage(argv[0], "ERROR: Multiple --ar arguments",
  404. EXIT_FAILURE);
  405. }
  406. g_ar = argv[argidx];
  407. }
  408. else if (strcmp(argv[argidx], "--ar_flags") == 0)
  409. {
  410. argidx++;
  411. if (argidx >= argc)
  412. {
  413. show_usage(argv[0], "ERROR: Missing argument to --ar_flags",
  414. EXIT_FAILURE);
  415. }
  416. else if (g_arflags != NULL)
  417. {
  418. show_usage(argv[0], "ERROR: Multiple --ar_flags arguments",
  419. EXIT_FAILURE);
  420. }
  421. g_arflags = argv[argidx];
  422. }
  423. else if (strcmp(argv[argidx], "--library") == 0)
  424. {
  425. const char *tmp_path;
  426. argidx++;
  427. if (argidx >= argc)
  428. {
  429. show_usage(argv[0], "ERROR: Missing argument to --library",
  430. EXIT_FAILURE);
  431. }
  432. else if (library != NULL)
  433. {
  434. show_usage(argv[0], "ERROR: Multiple --library arguments",
  435. EXIT_FAILURE);
  436. }
  437. /* Convert the library path a POSIX. NOTE this is a no-op in Windows
  438. * native mode.
  439. */
  440. tmp_path = convert_path_posix(argv[argidx]);
  441. library = strdup(tmp_path);
  442. if (library == NULL)
  443. {
  444. fprintf(stderr, "ERROR: strdup() failed\n");
  445. exit(EXIT_FAILURE);
  446. }
  447. }
  448. else if (strcmp(argv[argidx], "--obj-path") == 0)
  449. {
  450. argidx++;
  451. if (argidx >= argc)
  452. {
  453. show_usage(argv[0], "ERROR: Missing argument to --obj-path",
  454. EXIT_FAILURE);
  455. }
  456. else if (objpath != NULL)
  457. {
  458. show_usage(argv[0], "ERROR: Multiple --obj-path arguments",
  459. EXIT_FAILURE);
  460. }
  461. objpath = argv[argidx];
  462. }
  463. else if (strcmp(argv[argidx], "--debug") == 0)
  464. {
  465. g_debug++;
  466. }
  467. else if (strcmp(argv[argidx], "--help") == 0)
  468. {
  469. show_usage(argv[0], NULL, EXIT_SUCCESS);
  470. }
  471. else if (strncmp(argv[argidx], "--", 2) == 0)
  472. {
  473. show_usage(argv[0], "ERROR: Unrecognized option", EXIT_FAILURE);
  474. }
  475. else
  476. {
  477. break;
  478. }
  479. }
  480. /* Accumulate object files */
  481. for (; argidx < argc; argidx++)
  482. {
  483. append(&g_objects, argv[argidx]);
  484. }
  485. if (g_debug)
  486. {
  487. fprintf(stderr, "Selections:\n");
  488. fprintf(stderr, " CWD : [%s]\n",
  489. g_initial_wd);
  490. fprintf(stderr, " Host Environ : [%s]\n",
  491. HOSTNAME);
  492. fprintf(stderr, " AR : [%s]\n",
  493. g_ar ? g_ar : "(None)");
  494. fprintf(stderr, " AR Flags : [%s]\n",
  495. g_arflags ? g_arflags : "(None)");
  496. fprintf(stderr, " Library : [%s]\n",
  497. library ? library : "(None)");
  498. fprintf(stderr, " Object Path : [%s]\n",
  499. objpath ? objpath : "(None");
  500. fprintf(stderr, " Object Files : [%s]\n\n",
  501. g_objects ? g_objects : "(None)");
  502. }
  503. /* Check for required parameters */
  504. if (g_ar == NULL)
  505. {
  506. show_usage(argv[0], "ERROR: No librarian specified",
  507. EXIT_FAILURE);
  508. }
  509. if (library == NULL)
  510. {
  511. show_usage(argv[0], "ERROR: No library specified",
  512. EXIT_FAILURE);
  513. }
  514. else
  515. {
  516. /* Separate the library file name from the path. The ZDS-II librarian
  517. * expects the library to be in the current working directory.
  518. */
  519. g_libname = basename(library); /* Must come first */
  520. g_libpath = dirname(library);
  521. }
  522. if (g_objects == NULL)
  523. {
  524. /* Don't report an error -- this happens normally in some configurations */
  525. printf("No object files specified\n");
  526. exit(EXIT_SUCCESS);
  527. }
  528. g_objpath[0] = '\0';
  529. if (objpath != NULL)
  530. {
  531. /* If the object path relative to the current working directory? */
  532. /* It is a relative path if the path does not begin with the path
  533. * segment separator or if in the Windows native case, it begins
  534. * with a volume specified like C:.
  535. */
  536. pathlen = 0;
  537. #ifdef HOST_NATIVE
  538. if (objpath[0] != SEPARATOR ||
  539. (isalpha(objpath[0]) && objpath[1] != ':'))
  540. #else
  541. if (objpath[0] != SEPARATOR)
  542. #endif
  543. {
  544. /* Add the default working directory to the path */
  545. /* Copy the initial working directory */
  546. pathlen = strlen(g_initial_wd);
  547. if (pathlen >= MAX_PATH)
  548. {
  549. fprintf(stderr, "ERROR: Working directory path is "
  550. "too long [%d/%d]: %s\n",
  551. pathlen, MAX_PATH, g_initial_wd);
  552. exit(EXIT_FAILURE);
  553. }
  554. strcpy(g_path, g_initial_wd);
  555. /* Append a separator is one is not already present */
  556. if (g_path[pathlen - 1] != SEPARATOR)
  557. {
  558. int newlen = pathlen + 1;
  559. if (newlen >= MAX_PATH)
  560. {
  561. fprintf(stderr, "ERROR: Object path is too long "
  562. "with separator[%d/%d]: %s\n",
  563. newlen, MAX_PATH, g_initial_wd);
  564. exit(EXIT_FAILURE);
  565. }
  566. g_path[pathlen] = SEPARATOR;
  567. g_path[pathlen + 1] = '\0';
  568. pathlen = newlen;
  569. }
  570. }
  571. /* Add the object file path after the current working directory */
  572. pathlen += strlen(objpath);
  573. if (pathlen >= MAX_PATH)
  574. {
  575. fprintf(stderr, "ERROR: Path+objpath is too long [%d/%d]\n",
  576. pathlen, MAX_PATH);
  577. exit(EXIT_FAILURE);
  578. }
  579. strcat(g_path, objpath);
  580. }
  581. /* The object was in the current working directory. If a library path
  582. * is NOT the current working directory, then the library path will now
  583. * be the current working directory and the path to the objects will be
  584. * the working directory when the program was started.
  585. */
  586. else if (g_libpath != NULL && strcmp(g_libpath, ".") != 0)
  587. {
  588. strcpy(g_path, g_initial_wd);
  589. }
  590. /* Convert the absolute objection file path to the native host path form
  591. * NOTE that convert_path_posix() is a no-op in Windows native mode.
  592. */
  593. tmp = convert_path_posix(g_path);
  594. strcpy(g_path, tmp);
  595. /* Check for a relative path. We will CD to g_libpath because the
  596. * library must be in the current working directory.
  597. */
  598. pathlen = strlen(g_libpath);
  599. if (strncmp(g_path, g_libpath, pathlen) == 0)
  600. {
  601. const char *relpath = &g_path[pathlen];
  602. /* Skip over leading path segment delimiters.. that should be as
  603. * least one.
  604. */
  605. while (*relpath == SEPARATOR)
  606. {
  607. relpath++;
  608. }
  609. /* Convert the relative object file path to the Windows path form
  610. * for the ZDS-II tool tool. NOTE that convert_path_windows() is
  611. * a no-op in Windows native mode.
  612. */
  613. tmp = convert_path_windows(relpath);
  614. }
  615. else
  616. {
  617. /* Convert the absolute object file path to the Windows path form
  618. * for the ZDS-II tool tool. NOTE that convert_path_windows() is
  619. * a no-op in Windows native mode.
  620. */
  621. tmp = convert_path_windows(g_path);
  622. }
  623. /* And save the path in as a native Windows path */
  624. strcpy(g_objpath, tmp);
  625. /* Dump some intermediate results */
  626. if (g_debug)
  627. {
  628. fprintf(stderr, "Derived:\n");
  629. fprintf(stderr, " Object Path : [%s]\n",
  630. g_objpath[0] != '\0' ? g_objpath : "(None");
  631. fprintf(stderr, " Library Path : [%s]\n",
  632. g_libpath ? g_libpath : "(None)");
  633. fprintf(stderr, " Library Name : [%s]\n\n",
  634. g_libname ? g_libname : "(None)");
  635. }
  636. }
  637. static void do_archive(void)
  638. {
  639. struct stat buf;
  640. char *alloc;
  641. char *objects;
  642. char *object;
  643. char *lasts;
  644. int cmdlen;
  645. int pathlen;
  646. int objlen;
  647. int totallen;
  648. int nobjects;
  649. int ret;
  650. /* Make a copy of g_objects. We need to do this because at least the version
  651. * of strtok_r above does modify it.
  652. */
  653. alloc = strdup(g_objects);
  654. if (alloc == NULL)
  655. {
  656. fprintf(stderr, "ERROR: Failed to strdup object list\n");
  657. exit(EXIT_FAILURE);
  658. }
  659. objects = alloc;
  660. /* We may have to loop since we limit the number of objects in each call
  661. * to the librarian.
  662. */
  663. lasts = NULL;
  664. for (; ; )
  665. {
  666. /* Copy the librarian into the command buffer */
  667. cmdlen = strlen(g_ar);
  668. if (cmdlen >= MAX_BUFFER)
  669. {
  670. fprintf(stderr, "ERROR: Librarian string is too long [%d/%d]: %s\n",
  671. cmdlen, MAX_BUFFER, g_ar);
  672. exit(EXIT_FAILURE);
  673. }
  674. strcpy(g_command, g_ar);
  675. /* Add a space */
  676. g_command[cmdlen] = ' ';
  677. cmdlen++;
  678. g_command[cmdlen] = '\0';
  679. /* Copy the librarian flags into the command buffer */
  680. if (g_arflags != NULL)
  681. {
  682. const char *quoted;
  683. quoted = quote_backslash(g_arflags);
  684. cmdlen += strlen(quoted);
  685. if (cmdlen >= MAX_BUFFER)
  686. {
  687. fprintf(stderr, "ERROR: CFLAG string is too long [%d/%d]: %s\n",
  688. cmdlen, MAX_BUFFER, g_arflags);
  689. exit(EXIT_FAILURE);
  690. }
  691. strcat(g_command, quoted);
  692. }
  693. /* Add each object file. This loop will continue until each path has been
  694. * tried (failure) or until stat() finds the object file
  695. */
  696. nobjects = 0;
  697. while ((object = strtok_r(objects, " ", &lasts)) != NULL)
  698. {
  699. const char *quoted;
  700. const char *converted;
  701. /* Set objects to NULL. This will force strtok_r to move from the
  702. * the first object in the list.
  703. */
  704. objects = NULL;
  705. /* Add a space */
  706. g_command[cmdlen] = ' ';
  707. cmdlen++;
  708. g_command[cmdlen] = '\0';
  709. /* Create a full path to the object file */
  710. g_path[0] = '\0';
  711. pathlen = 0;
  712. /* Add the path to buffer path buffer first */
  713. if (g_objpath[0] != '\0')
  714. {
  715. /* Copy the obj_path */
  716. pathlen = strlen(g_objpath);
  717. if (pathlen >= MAX_PATH)
  718. {
  719. fprintf(stderr, "ERROR: Path is too long [%d/%d]: %s\n",
  720. pathlen, MAX_PATH, g_objpath);
  721. exit(EXIT_FAILURE);
  722. }
  723. strcpy(g_path, g_objpath);
  724. /* Append a separator is one is not already present */
  725. if (g_path[pathlen - 1] != WINSEPARATOR)
  726. {
  727. int newlen = pathlen + 1;
  728. if (newlen >= MAX_PATH)
  729. {
  730. fprintf(stderr, "ERROR: Path is too long with "
  731. "separator[%d/%d]: %s\n",
  732. newlen, MAX_PATH, g_path);
  733. exit(EXIT_FAILURE);
  734. }
  735. g_path[pathlen] = WINSEPARATOR;
  736. g_path[pathlen + 1] = '\0';
  737. pathlen = newlen;
  738. }
  739. }
  740. /* Add the object file name after the path */
  741. objlen = strlen(object);
  742. pathlen += objlen;
  743. if (pathlen >= MAX_PATH)
  744. {
  745. fprintf(stderr, "ERROR: Path+objfile is too long [%d/%d]\n",
  746. pathlen, MAX_PATH);
  747. exit(EXIT_FAILURE);
  748. }
  749. strcat(g_path, object);
  750. /* Check that a object file actually exists at this path. NOTE
  751. * that convert_path_posix() is a no-op in Windows native mode.
  752. */
  753. converted = convert_path_posix(g_path);
  754. ret = stat(converted, &buf);
  755. if (ret < 0)
  756. {
  757. fprintf(stderr, "WARNING: Stat of object %s failed: %s\n",
  758. g_path, strerror(errno));
  759. continue;
  760. }
  761. if (!S_ISREG(buf.st_mode))
  762. {
  763. fprintf(stderr, "ERROR: Object %s exists but is not a regular "
  764. "file\n",
  765. g_path);
  766. exit(EXIT_FAILURE);
  767. }
  768. /* Expand the path */
  769. /* Copy the librarian argument of form like:
  770. *
  771. * <libname>=-+<objpath>
  772. */
  773. pathlen = 4; /* For =-+ and terminator */
  774. quoted = quote_backslash(g_path);
  775. pathlen += strlen(quoted);
  776. /* Get the full length */
  777. pathlen += strlen(g_libname);
  778. totallen = cmdlen + pathlen;
  779. if (totallen >= MAX_BUFFER)
  780. {
  781. fprintf(stderr, "ERROR: object argument is too long [%d/%d]: "
  782. "%s=-+%s\n",
  783. totallen, MAX_BUFFER, g_libname, quoted);
  784. exit(EXIT_FAILURE);
  785. }
  786. /* Append the next librarian command */
  787. pathlen = snprintf(&g_command[cmdlen], MAX_BUFFER - cmdlen, "%s=-+%s",
  788. g_libname, quoted);
  789. cmdlen += pathlen;
  790. /* Terminate early if we have a LOT files in the command line */
  791. if (++nobjects >= MAX_OBJECTS)
  792. {
  793. break;
  794. }
  795. }
  796. /* Handling the final command which may have not objects to insert */
  797. if (nobjects > 0)
  798. {
  799. /* Okay.. we have everything. Add the object files to the library.
  800. * On a failure to start the compiler, system() will return -1;
  801. * Otherwise, the returned value from the compiler is in
  802. * WEXITSTATUS(ret).
  803. */
  804. if (g_debug)
  805. {
  806. fprintf(stderr, "Executing: %s\n", g_command);
  807. }
  808. ret = system(g_command);
  809. #ifdef WEXITSTATUS
  810. if (ret < 0 || WEXITSTATUS(ret) != 0)
  811. {
  812. if (ret < 0)
  813. {
  814. fprintf(stderr, "ERROR: system failed: %s\n",
  815. strerror(errno));
  816. }
  817. else
  818. {
  819. fprintf(stderr, "ERROR: %s failed: %d\n", g_ar,
  820. WEXITSTATUS(ret));
  821. }
  822. fprintf(stderr, " command: %s\n", g_command);
  823. exit(EXIT_FAILURE);
  824. }
  825. #else
  826. if (ret < 0)
  827. {
  828. fprintf(stderr, "ERROR: system failed: %s\n", strerror(errno));
  829. fprintf(stderr, " command: %s\n", g_command);
  830. exit(EXIT_FAILURE);
  831. }
  832. #endif
  833. /* We don't really know that the command succeeded... Let's
  834. * assume that it did
  835. */
  836. }
  837. /* Check if we have more objects to process */
  838. if (object == NULL)
  839. {
  840. /* No, we are finished */
  841. break;
  842. }
  843. }
  844. free(alloc);
  845. }
  846. /****************************************************************************
  847. * Public Functions
  848. ****************************************************************************/
  849. int main(int argc, char **argv, char **envp)
  850. {
  851. char *wd;
  852. int ret;
  853. /* Get the current working directory */
  854. wd = getcwd(g_initial_wd, MAX_PATH);
  855. if (wd == NULL)
  856. {
  857. fprintf(stderr, "ERROR: getcwd failed: %s\n", strerror(errno));
  858. return EXIT_FAILURE;
  859. }
  860. g_current_wd = g_initial_wd;
  861. /* Parse command line parameters */
  862. parse_args(argc, argv);
  863. /* Change to the directory containing the library */
  864. if (g_libpath != NULL && strcmp(g_libpath, ".") != 0)
  865. {
  866. ret = chdir(g_libpath);
  867. if (ret < 0)
  868. {
  869. fprintf(stderr, "ERROR: getcwd failed: %s\n", strerror(errno));
  870. return EXIT_FAILURE;
  871. }
  872. g_current_wd = g_libpath;
  873. }
  874. /* Then generate dependencies for each path on the command line. */
  875. do_archive();
  876. return EXIT_SUCCESS;
  877. }