imake.c 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $TOG: imake.c /main/104 1998/03/24 12:45:15 kaleb $ */
  24. /***************************************************************************
  25. * *
  26. * Porting Note *
  27. * *
  28. * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will *
  29. * be passed to the template file. *
  30. * *
  31. ***************************************************************************/
  32. /*
  33. *
  34. Copyright (c) 1985, 1986, 1987, 1998 The Open Group
  35. All Rights Reserved.
  36. The above copyright notice and this permission notice shall be included in
  37. all copies or substantial portions of the Software.
  38. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  39. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  40. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  41. OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  42. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  43. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  44. Except as contained in this notice, the name of The Open Group shall not be
  45. used in advertising or otherwise to promote the sale, use or other dealings
  46. in this Software without prior written authorization from The Open Group.
  47. *
  48. * Original Author:
  49. * Todd Brunhoff
  50. * Tektronix, inc.
  51. * While a guest engineer at Project Athena, MIT
  52. *
  53. * imake: the include-make program.
  54. *
  55. * Usage: imake [-Idir] [-Ddefine] [-T template] [-f imakefile ] [-C Imakefile.c ] [-s] [-e] [-v] [make flags]
  56. *
  57. * Imake takes a template file (Imake.tmpl) and a prototype (Imakefile)
  58. * and runs cpp on them producing a Makefile. It then optionally runs make
  59. * on the Makefile.
  60. * Options:
  61. * -D define. Same as cpp -D argument.
  62. * -I Include directory. Same as cpp -I argument.
  63. * -T template. Designate a template other
  64. * than Imake.tmpl
  65. * -f specify the Imakefile file
  66. * -C specify the name to use instead of Imakefile.c
  67. * -s[F] show. Show the produced makefile on the standard
  68. * output. Make is not run is this case. If a file
  69. * argument is provided, the output is placed there.
  70. * -e[F] execute instead of show; optionally name Makefile F
  71. * -v verbose. Show the make command line executed.
  72. *
  73. * Environment variables:
  74. *
  75. * IMAKEINCLUDE Include directory to use in addition to "."
  76. * IMAKECPP Cpp to use instead of /lib/cpp
  77. * IMAKEMAKE make program to use other than what is
  78. * found by searching the $PATH variable.
  79. * Other features:
  80. * imake reads the entire cpp output into memory and then scans it
  81. * for occurences of "@@". If it encounters them, it replaces it with
  82. * a newline. It also trims any trailing white space on output lines
  83. * (because make gets upset at them). This helps when cpp expands
  84. * multi-line macros but you want them to appear on multiple lines.
  85. * It also changes occurences of "XCOMM" to "#", to avoid problems
  86. * with treating commands as invalid preprocessor commands.
  87. *
  88. * The macros MAKEFILE and MAKE are provided as macros
  89. * to make. MAKEFILE is set to imake's makefile (not the constructed,
  90. * preprocessed one) and MAKE is set to argv[0], i.e. the name of
  91. * the imake program.
  92. *
  93. * Theory of operation:
  94. * 1. Determine the name of the imakefile from the command line (-f)
  95. * or from the content of the current directory (Imakefile or imakefile).
  96. * Call this <imakefile>. This gets added to the arguments for
  97. * make as MAKEFILE=<imakefile>.
  98. * 2. Determine the name of the template from the command line (-T)
  99. * or the default, Imake.tmpl. Call this <template>
  100. * 3. Determine the name of the imakeCfile from the command line (-C)
  101. * or the default, Imakefile.c. Call this <imakeCfile>
  102. * 4. Store lines of input into <imakeCfile>:
  103. * - A c-style comment header (see ImakefileCHeader below), used
  104. * to recognize temporary files generated by imake.
  105. * - If DEFAULT_OS_NAME is defined, format the utsname struct and
  106. * call the result <defaultOsName>. Add:
  107. * #define DefaultOSName <defaultOsName>
  108. * - If DEFAULT_OS_MAJOR_REV is defined, format the utsname struct
  109. * and call the result <defaultOsMajorVersion>. Add:
  110. * #define DefaultOSMajorVersion <defaultOsMajorVersion>
  111. * - If DEFAULT_OS_MINOR_REV is defined, format the utsname struct
  112. * and call the result <defaultOsMinorVersion>. Add:
  113. * #define DefaultOSMinorVersion <defaultOsMinorVersion>
  114. * - If DEFAULT_OS_TEENY_REV is defined, format the utsname struct
  115. * and call the result <defaultOsTeenyVersion>. Add:
  116. * #define DefaultOSTeenyVersion <defaultOsTeenyVersion>
  117. * - If the file "localdefines" is readable in the current
  118. * directory, print a warning message to stderr and add:
  119. * #define IMAKE_LOCAL_DEFINES "localdefines"
  120. * #include IMAKE_LOCAL_DEFINES
  121. * - If the file "admindefines" is readable in the current
  122. * directory, print a warning message to stderr and add:
  123. * #define IMAKE_ADMIN_DEFINES "admindefines"
  124. * #include IMAKE_ADMIN_DEFINES
  125. * - The following lines:
  126. * #define INCLUDE_IMAKEFILE < <imakefile> >
  127. * #define IMAKE_TEMPLATE " <template> "
  128. * #include IMAKE_TEMPLATE
  129. * - If the file "adminmacros" is readable in the current
  130. * directory, print a warning message to stderr and add:
  131. * #define IMAKE_ADMIN_MACROS "adminmacros"
  132. * #include IMAKE_ADMIN_MACROS
  133. * - If the file "localmacros" is readable in the current
  134. * directory, print a warning message to stderr and add:
  135. * #define IMAKE_LOCAL_MACROS "localmacros"
  136. * #include IMAKE_LOCAL_MACROS
  137. * 5. Start up cpp and provide it with this file.
  138. * Note that the define for INCLUDE_IMAKEFILE is intended for
  139. * use in the template file. This implies that the imake is
  140. * useless unless the template file contains at least the line
  141. * #include INCLUDE_IMAKEFILE
  142. * 6. Gather the output from cpp, and clean it up, expanding @@ to
  143. * newlines, stripping trailing white space, cpp control lines,
  144. * and extra blank lines, and changing XCOMM to #. This cleaned
  145. * output is placed in a new file, default "Makefile", but can
  146. * be specified with -s or -e options.
  147. * 7. Optionally start up make on the resulting file.
  148. *
  149. * The design of the template makefile should therefore be:
  150. * <set global macros like CFLAGS, etc.>
  151. * <include machine dependent additions>
  152. * #include INCLUDE_IMAKEFILE
  153. * <add any global targets like 'clean' and long dependencies>
  154. */
  155. #include <stdio.h>
  156. #include <ctype.h>
  157. #include "Xosdefs.h"
  158. #ifndef X_NOT_POSIX
  159. # ifndef _POSIX_SOURCE
  160. # define _POSIX_SOURCE
  161. # endif
  162. #endif
  163. #include <sys/types.h>
  164. #include <fcntl.h>
  165. #ifdef X_NOT_POSIX
  166. # include <sys/file.h>
  167. #else
  168. # include <unistd.h>
  169. #endif
  170. #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
  171. # include <signal.h>
  172. #else
  173. # define _POSIX_SOURCE
  174. # include <signal.h>
  175. # undef _POSIX_SOURCE
  176. #endif
  177. #include <sys/stat.h>
  178. #ifndef X_NOT_POSIX
  179. # ifdef _POSIX_SOURCE
  180. # include <sys/wait.h>
  181. # else
  182. # define _POSIX_SOURCE
  183. # include <sys/wait.h>
  184. # undef _POSIX_SOURCE
  185. # endif
  186. # define waitCode(w) WEXITSTATUS(w)
  187. # define waitSig(w) WTERMSIG(w)
  188. typedef int waitType;
  189. #else /* X_NOT_POSIX */
  190. # ifdef SYSV
  191. # define waitCode(w) (((w) >> 8) & 0x7f)
  192. # define waitSig(w) ((w) & 0xff)
  193. typedef int waitType;
  194. # else /* SYSV */
  195. # include <sys/wait.h>
  196. # define waitCode(w) ((w).w_T.w_Retcode)
  197. # define waitSig(w) ((w).w_T.w_Termsig)
  198. typedef union wait waitType;
  199. # endif
  200. # ifndef WIFSIGNALED
  201. # define WIFSIGNALED(w) waitSig(w)
  202. # endif
  203. # ifndef WIFEXITED
  204. # define WIFEXITED(w) waitCode(w)
  205. # endif
  206. #endif /* X_NOT_POSIX */
  207. #ifndef X_NOT_STDC_ENV
  208. # include <stdlib.h>
  209. #else
  210. char *malloc(), *realloc();
  211. void exit();
  212. #endif
  213. #ifdef X_NOT_STDC_ENV
  214. extern char *getenv();
  215. #endif
  216. #include <errno.h>
  217. #ifdef X_NOT_STDC_ENV
  218. extern int errno;
  219. #endif
  220. #include <sys/utsname.h>
  221. #ifndef SYS_NMLN
  222. # ifdef _SYS_NMLN
  223. # define SYS_NMLN _SYS_NMLN
  224. # else
  225. # define SYS_NMLN 257
  226. # endif
  227. #endif
  228. #ifdef linux
  229. #include <limits.h>
  230. #endif
  231. /*
  232. * is strstr() in <strings.h> on X_NOT_STDC_ENV?
  233. * are there any X_NOT_STDC_ENV machines left in the world?
  234. */
  235. #include <string.h>
  236. #include <stdarg.h>
  237. #include "imakemdep.h"
  238. /*
  239. * This define of strerror is copied from (and should be identical to)
  240. * Xos.h, which we don't want to include here for bootstrapping reasons.
  241. */
  242. #if defined(X_NOT_STDC_ENV) || (defined(sun) && !defined(SVR4))
  243. # ifndef strerror
  244. extern char *sys_errlist[];
  245. extern int sys_nerr;
  246. # define strerror(n) \
  247. (((n) >= 0 && (n) < sys_nerr) ? sys_errlist[n] : "unknown error")
  248. # endif
  249. #endif
  250. #define TRUE 1
  251. #define FALSE 0
  252. #ifdef FIXUP_CPP_WHITESPACE
  253. static int InRule = FALSE;
  254. # ifdef INLINE_SYNTAX
  255. static int InInline = 0;
  256. # endif
  257. #endif
  258. #ifdef MAGIC_MAKE_VARS
  259. static int xvariable = 0;
  260. static int xvariables[10];
  261. #endif
  262. /*
  263. * Some versions of cpp reduce all tabs in macro expansion to a single
  264. * space. In addition, the escaped newline may be replaced with a
  265. * space instead of being deleted. Blech.
  266. */
  267. #ifdef FIXUP_CPP_WHITESPACE
  268. static void KludgeOutputLine(char **pline);
  269. static void KludgeResetRule(void);
  270. #else
  271. # define KludgeOutputLine(arg)
  272. # define KludgeResetRule()
  273. #endif
  274. typedef unsigned char boolean;
  275. #ifdef USE_CC_E
  276. # ifndef DEFAULT_CC
  277. # define DEFAULT_CC "cc"
  278. # endif
  279. #else
  280. # ifndef DEFAULT_CPP
  281. # ifdef CPP_PROGRAM
  282. # define DEFAULT_CPP CPP_PROGRAM
  283. # else
  284. # define DEFAULT_CPP "/lib/cpp"
  285. # endif
  286. # endif
  287. #endif
  288. static char *cpp = NULL;
  289. static char *tmpMakefile = "/tmp/Imf.XXXXXX";
  290. static char *tmpImakefile = "/tmp/IIf.XXXXXX";
  291. static char *make_argv[ ARGUMENTS ] = {"make"};
  292. static int make_argindex;
  293. static int cpp_argindex;
  294. static char *Imakefile = NULL;
  295. static char *Makefile = "Makefile";
  296. static char *Template = "Imake.tmpl";
  297. static char *ImakefileC = "Imakefile.c";
  298. static boolean haveImakefileC = FALSE;
  299. static char *cleanedImakefile = NULL;
  300. static char *program;
  301. static boolean verbose = FALSE;
  302. static boolean show = TRUE;
  303. static char *FindImakefile(char *);
  304. static char *ReadLine(FILE *, const char *);
  305. static char *CleanCppInput(char *);
  306. static char *Strdup(const char *);
  307. static char *Emalloc(int);
  308. static void LogFatal(const char *, ...);
  309. static void LogMsg(const char *, ...);
  310. static void Log(const char *, va_list);
  311. static void showit(FILE *);
  312. static void wrapup(void);
  313. static
  314. #ifdef SIGNALRETURNSINT
  315. int
  316. #else
  317. void
  318. #endif
  319. catch(int);
  320. static void init(void);
  321. static void AddMakeArg(char *);
  322. static void AddCppArg(char *);
  323. static void SetOpts(int, char **);
  324. static void showargs(char **);
  325. static void CheckImakefileC(const char *);
  326. static boolean optional_include(FILE *, const char *, const char *);
  327. static void doit(FILE *, const char *, char **);
  328. #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
  329. defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
  330. static void parse_utsname(struct utsname *, const char *, char *, const char *);
  331. #endif
  332. #if (defined(DEFAULT_OS_MAJOR_REV) || defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
  333. static const char *trim_version(const char *);
  334. #endif
  335. #ifdef linux
  336. static void get_distrib(FILE *);
  337. static void get_libc_version(FILE *);
  338. static void get_ld_version(FILE *);
  339. #endif
  340. #if defined(sun) && defined(__SVR4)
  341. static char *get_full_path(const char *program);
  342. static int get_sun_compiler_version(const char *fspec, const char *product,
  343. int *cmajor, int *cminor);
  344. static void get_sun_compiler_versions(FILE *);
  345. #endif
  346. static void get_gcc_incdir(FILE *);
  347. static boolean define_os_defaults(FILE *);
  348. static void cppit(const char *i, const char *, const char *, FILE *, const char *);
  349. static void makeit(void);
  350. static void CleanCppOutput(FILE *, const char *);
  351. static boolean isempty(char *);
  352. static void writetmpfile(FILE *, const char *, int, const char *);
  353. int
  354. main(int argc, char *argv[])
  355. {
  356. FILE *tmpfd;
  357. char makeMacro[ BUFSIZ ];
  358. char makefileMacro[ BUFSIZ ];
  359. program = argv[0];
  360. init();
  361. SetOpts(argc, argv);
  362. Imakefile = FindImakefile(Imakefile);
  363. CheckImakefileC(ImakefileC);
  364. if (Makefile)
  365. tmpMakefile = Makefile;
  366. else {
  367. tmpMakefile = Strdup(tmpMakefile);
  368. int ret = mkstemp(tmpMakefile);
  369. (void) ret;
  370. }
  371. AddMakeArg("-f");
  372. AddMakeArg( tmpMakefile );
  373. snprintf(makeMacro, BUFSIZ, "MAKE=%s", program);
  374. AddMakeArg( makeMacro );
  375. snprintf(makefileMacro, BUFSIZ, "MAKEFILE=%s", Imakefile);
  376. AddMakeArg( makefileMacro );
  377. if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
  378. LogFatal("Cannot create temporary file %s.", tmpMakefile);
  379. cleanedImakefile = CleanCppInput(Imakefile);
  380. cppit(cleanedImakefile, Template, ImakefileC, tmpfd, tmpMakefile);
  381. if (show) {
  382. if (Makefile == NULL)
  383. showit(tmpfd);
  384. } else
  385. makeit();
  386. wrapup();
  387. return 0;
  388. }
  389. static void
  390. showit(FILE *fd)
  391. {
  392. char buf[ BUFSIZ ];
  393. int red;
  394. fseek(fd, 0, 0);
  395. while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
  396. writetmpfile(stdout, buf, red, "stdout");
  397. if (red < 0)
  398. LogFatal("Cannot read %s.", tmpMakefile);
  399. }
  400. static void
  401. wrapup(void)
  402. {
  403. if (tmpMakefile != Makefile)
  404. unlink(tmpMakefile);
  405. if (cleanedImakefile && cleanedImakefile != Imakefile)
  406. unlink(cleanedImakefile);
  407. if (haveImakefileC)
  408. unlink(ImakefileC);
  409. }
  410. static
  411. #ifdef SIGNALRETURNSINT
  412. int
  413. #else
  414. void
  415. #endif
  416. catch(int sig)
  417. {
  418. errno = 0;
  419. LogFatal("Signal %d.", sig);
  420. }
  421. /*
  422. * Initialize some variables.
  423. */
  424. static void
  425. init(void)
  426. {
  427. char *p;
  428. make_argindex=0;
  429. while (make_argv[ make_argindex ] != NULL)
  430. make_argindex++;
  431. cpp_argindex = 0;
  432. while (cpp_argv[ cpp_argindex ] != NULL)
  433. cpp_argindex++;
  434. /*
  435. * See if the standard include directory is different than
  436. * the default. Or if cpp is not the default. Or if the make
  437. * found by the PATH variable is not the default.
  438. */
  439. if ((p = getenv("IMAKEINCLUDE"))) {
  440. if (*p != '-' || *(p+1) != 'I')
  441. LogFatal("Environment var IMAKEINCLUDE %s must begin with -I");
  442. AddCppArg(p);
  443. for (; *p; p++)
  444. if (*p == ' ') {
  445. *p++ = '\0';
  446. AddCppArg(p);
  447. }
  448. }
  449. if ((p = getenv("IMAKECPP")))
  450. cpp = p;
  451. if ((p = getenv("IMAKEMAKE")))
  452. make_argv[0] = p;
  453. if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  454. signal(SIGINT, catch);
  455. }
  456. static void
  457. AddMakeArg(char *arg)
  458. {
  459. errno = 0;
  460. if (make_argindex >= ARGUMENTS-1)
  461. LogFatal("Out of internal storage.");
  462. make_argv[ make_argindex++ ] = arg;
  463. make_argv[ make_argindex ] = NULL;
  464. }
  465. static void
  466. AddCppArg(char *arg)
  467. {
  468. errno = 0;
  469. if (cpp_argindex >= ARGUMENTS-1)
  470. LogFatal("Out of internal storage.");
  471. cpp_argv[ cpp_argindex++ ] = arg;
  472. cpp_argv[ cpp_argindex ] = NULL;
  473. }
  474. static void
  475. SetOpts(int argc, char **argv)
  476. {
  477. errno = 0;
  478. /*
  479. * Now gather the arguments for make
  480. */
  481. for(argc--, argv++; argc; argc--, argv++) {
  482. /*
  483. * We intercept these flags.
  484. */
  485. if (argv[0][0] == '-') {
  486. if (argv[0][1] == 'D') {
  487. AddCppArg(argv[0]);
  488. } else if (argv[0][1] == 'I') {
  489. AddCppArg(argv[0]);
  490. } else if (argv[0][1] == 'f') {
  491. if (argv[0][2])
  492. Imakefile = argv[0]+2;
  493. else {
  494. argc--, argv++;
  495. if (! argc)
  496. LogFatal("No description arg after -f flag");
  497. Imakefile = argv[0];
  498. }
  499. } else if (argv[0][1] == 's') {
  500. if (argv[0][2])
  501. Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
  502. NULL : argv[0]+2;
  503. else {
  504. argc--, argv++;
  505. if (!argc)
  506. LogFatal("No description arg after -s flag");
  507. Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
  508. NULL : argv[0];
  509. }
  510. show = TRUE;
  511. } else if (argv[0][1] == 'e') {
  512. Makefile = (argv[0][2] ? argv[0]+2 : NULL);
  513. show = FALSE;
  514. } else if (argv[0][1] == 'T') {
  515. if (argv[0][2])
  516. Template = argv[0]+2;
  517. else {
  518. argc--, argv++;
  519. if (! argc)
  520. LogFatal("No description arg after -T flag");
  521. Template = argv[0];
  522. }
  523. } else if (argv[0][1] == 'C') {
  524. if (argv[0][2])
  525. ImakefileC = argv[0]+2;
  526. else {
  527. argc--, argv++;
  528. if (! argc)
  529. LogFatal("No imakeCfile arg after -C flag");
  530. ImakefileC = argv[0];
  531. }
  532. } else if (argv[0][1] == 'v') {
  533. verbose = TRUE;
  534. } else
  535. AddMakeArg(argv[0]);
  536. } else
  537. AddMakeArg(argv[0]);
  538. }
  539. #ifdef USE_CC_E
  540. if (!cpp)
  541. {
  542. AddCppArg("-E");
  543. cpp = DEFAULT_CC;
  544. }
  545. #else
  546. if (!cpp)
  547. cpp = DEFAULT_CPP;
  548. #endif
  549. cpp_argv[0] = cpp;
  550. AddCppArg(ImakefileC);
  551. }
  552. static char *
  553. FindImakefile(char *Imakefile)
  554. {
  555. if (Imakefile) {
  556. if (access(Imakefile, R_OK) < 0)
  557. LogFatal("Cannot find %s.", Imakefile);
  558. } else {
  559. if (access("Imakefile", R_OK) < 0)
  560. if (access("imakefile", R_OK) < 0)
  561. LogFatal("No description file.");
  562. else
  563. Imakefile = "imakefile";
  564. else
  565. Imakefile = "Imakefile";
  566. }
  567. return(Imakefile);
  568. }
  569. static void
  570. LogFatal(const char *s, ...)
  571. {
  572. static boolean entered = FALSE;
  573. va_list args;
  574. if (entered)
  575. return;
  576. entered = TRUE;
  577. va_start(args, s);
  578. Log(s, args);
  579. va_end(args);
  580. fprintf(stderr, "Stop.\n");
  581. wrapup();
  582. exit(1);
  583. }
  584. static void
  585. LogMsg(const char *s, ...)
  586. {
  587. va_list args;
  588. va_start(args, s);
  589. Log(s, args);
  590. va_end(args);
  591. }
  592. static void
  593. Log(const char *s, va_list args)
  594. {
  595. int error_number = errno;
  596. if (error_number) {
  597. fprintf(stderr, "%s: ", program);
  598. fprintf(stderr, "%s\n", strerror(error_number));
  599. }
  600. fprintf(stderr, "%s: ", program);
  601. vfprintf(stderr, s, args);
  602. fprintf(stderr, "\n");
  603. }
  604. static void
  605. showargs(char **argv)
  606. {
  607. for (; *argv; argv++)
  608. fprintf(stderr, "%s ", *argv);
  609. fprintf(stderr, "\n");
  610. }
  611. #define ImakefileCHeader "/* imake - temporary file */"
  612. static void
  613. CheckImakefileC(const char *masterc)
  614. {
  615. char mkcbuf[1024];
  616. FILE *inFile;
  617. if (access(masterc, F_OK) == 0) {
  618. inFile = fopen(masterc, "r");
  619. if (inFile == NULL)
  620. LogFatal("Refuse to overwrite: %s", masterc);
  621. if ((fgets(mkcbuf, sizeof(mkcbuf), inFile) &&
  622. strncmp(mkcbuf, ImakefileCHeader,
  623. sizeof(ImakefileCHeader)-1)))
  624. {
  625. fclose(inFile);
  626. LogFatal("Refuse to overwrite: %s", masterc);
  627. }
  628. fclose(inFile);
  629. }
  630. }
  631. #define LocalDefineFmt "#define %s \"%s\"\n"
  632. #define IncludeFmt "#include %s\n"
  633. #define ImakeDefSym "INCLUDE_IMAKEFILE"
  634. #define ImakeTmplSym "IMAKE_TEMPLATE"
  635. #define OverrideWarning "Warning: local file \"%s\" overrides global macros."
  636. static boolean
  637. optional_include(FILE *inFile, const char *defsym, const char *fname)
  638. {
  639. errno = 0;
  640. if (access(fname, R_OK) == 0) {
  641. if(errno)
  642. LogMsg(OverrideWarning, fname);
  643. return (fprintf(inFile, LocalDefineFmt, defsym, fname) < 0 ||
  644. fprintf(inFile, IncludeFmt, defsym) < 0);
  645. }
  646. return FALSE;
  647. }
  648. static void
  649. doit(FILE *outfd, const char *cmd, char **argv)
  650. {
  651. int pid;
  652. waitType status;
  653. /*
  654. * Fork and exec the command.
  655. */
  656. pid = fork();
  657. if (pid < 0)
  658. LogFatal("Cannot fork.");
  659. if (pid) { /* parent... simply wait */
  660. while (wait(&status) > 0) {
  661. errno = 0;
  662. if (WIFSIGNALED(status))
  663. LogFatal("Signal %d.", waitSig(status));
  664. if (WIFEXITED(status) && waitCode(status))
  665. LogFatal("Exit code %d.", waitCode(status));
  666. }
  667. }
  668. else { /* child... dup and exec cmd */
  669. if (verbose)
  670. showargs(argv);
  671. if (outfd)
  672. dup2(fileno(outfd), 1);
  673. execvp(cmd, argv);
  674. LogFatal("Cannot exec %s.", cmd);
  675. }
  676. }
  677. #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
  678. defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
  679. static void
  680. parse_utsname(struct utsname *name, const char *fmt, char *result, const char *msg)
  681. {
  682. char buf[SYS_NMLN * 5 + 1];
  683. char *ptr = buf;
  684. int arg;
  685. /* Assemble all the pieces into a buffer. */
  686. for (arg = 0; fmt[arg] != ' '; arg++)
  687. {
  688. /* Our buffer is only guaranteed to hold 5 arguments. */
  689. if (arg >= 5)
  690. LogFatal(msg, fmt);
  691. switch (fmt[arg])
  692. {
  693. case 's':
  694. if (arg > 0)
  695. *ptr++ = ' ';
  696. strncpy(ptr, name->sysname, SYS_NMLN);
  697. ptr += strlen(ptr);
  698. break;
  699. case 'n':
  700. if (arg > 0)
  701. *ptr++ = ' ';
  702. strncpy(ptr, name->nodename, SYS_NMLN);
  703. ptr += strlen(ptr);
  704. break;
  705. case 'r':
  706. if (arg > 0)
  707. *ptr++ = ' ';
  708. strncpy(ptr, name->release, SYS_NMLN);
  709. ptr += strlen(ptr);
  710. break;
  711. case 'v':
  712. if (arg > 0)
  713. *ptr++ = ' ';
  714. strncpy(ptr, name->version, SYS_NMLN);
  715. ptr += strlen(ptr);
  716. break;
  717. case 'm':
  718. if (arg > 0)
  719. *ptr++ = ' ';
  720. strncpy(ptr, name->machine, SYS_NMLN);
  721. ptr += strlen(ptr);
  722. break;
  723. default:
  724. LogFatal(msg, fmt);
  725. }
  726. }
  727. /* Just in case... */
  728. if (strlen(buf) >= sizeof(buf))
  729. LogFatal("Buffer overflow parsing uname.");
  730. /* Parse the buffer. The sscanf() return value is rarely correct. */
  731. *result = '\0';
  732. int ret = sscanf(buf, fmt + arg + 1, result);
  733. (void) ret;
  734. }
  735. /* Trim leading 0's and periods from version names. The 0's cause
  736. the number to be interpreted as octal numbers. Some version strings
  737. have the potential for different numbers of .'s in them.
  738. */
  739. #if (defined(DEFAULT_OS_MAJOR_REV) || defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
  740. static const char *
  741. trim_version(const char *p)
  742. {
  743. if (p != 0 && *p != '\0')
  744. {
  745. while ((*p == '0' || *p == '.') && *(p + 1) != '\0')
  746. ++p;
  747. }
  748. return (p);
  749. }
  750. #endif
  751. #endif
  752. #ifdef linux
  753. static void
  754. get_distrib(FILE *inFile)
  755. {
  756. struct stat sb;
  757. static char* yast = "/sbin/yast";
  758. static char* redhat = "/etc/redhat-release";
  759. fprintf (inFile, "%s\n", "#define LinuxUnknown 0");
  760. fprintf (inFile, "%s\n", "#define LinuxSuSE 1");
  761. fprintf (inFile, "%s\n", "#define LinuxCaldera 2");
  762. fprintf (inFile, "%s\n", "#define LinuxCraftworks 3");
  763. fprintf (inFile, "%s\n", "#define LinuxDebian 4");
  764. fprintf (inFile, "%s\n", "#define LinuxInfoMagic 5");
  765. fprintf (inFile, "%s\n", "#define LinuxKheops 6");
  766. fprintf (inFile, "%s\n", "#define LinuxPro 7");
  767. fprintf (inFile, "%s\n", "#define LinuxRedHat 8");
  768. fprintf (inFile, "%s\n", "#define LinuxSlackware 9");
  769. fprintf (inFile, "%s\n", "#define LinuxTurbo 10");
  770. fprintf (inFile, "%s\n", "#define LinuxWare 11");
  771. fprintf (inFile, "%s\n", "#define LinuxYggdrasil 12");
  772. if (lstat (yast, &sb) == 0) {
  773. fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxSuSE");
  774. return;
  775. }
  776. if (lstat (redhat, &sb) == 0) {
  777. fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxRedHat");
  778. return;
  779. }
  780. /* what's the definitive way to tell what any particular distribution is? */
  781. fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxUnknown");
  782. /* would like to know what version of the distribution it is */
  783. }
  784. static const char libc_c[]=
  785. "#include <stdio.h>\n"
  786. "#include <ctype.h>\n"
  787. "\n"
  788. "#if 0\n"
  789. "#pragma weak gnu_get_libc_version\n"
  790. "#pragma weak __libc_version\n"
  791. "#pragma weak __linux_C_lib_version\n"
  792. "#else\n"
  793. "asm (\".weak gnu_get_libc_version\");\n"
  794. "asm (\".weak __libc_version\");\n"
  795. "asm (\".weak __linux_C_lib_version\");\n"
  796. "#endif\n"
  797. "\n"
  798. "extern const char * gnu_get_libc_version (void);\n"
  799. "extern const char * __linux_C_lib_version;\n"
  800. "extern const char __libc_version [];\n"
  801. "\n"
  802. "int\n"
  803. "main ()\n"
  804. "{\n"
  805. " int libcmajor = 0, libcminor = 0, libcteeny = 0;\n"
  806. "\n"
  807. " if (((&__linux_C_lib_version != 0)\n"
  808. " && ((&__libc_version != 0) || (gnu_get_libc_version != 0)))\n"
  809. " || (!(&__linux_C_lib_version != 0) && !(&__libc_version != 0)\n"
  810. " && !(gnu_get_libc_version != 0)))\n"
  811. " {\n"
  812. " libcmajor = 0;\n"
  813. " libcminor = 0;\n"
  814. " libcteeny = 0;\n"
  815. " }\n"
  816. " else\n"
  817. " {\n"
  818. " const char * ptr;\n"
  819. " int glibcmajor = 0;\n"
  820. "\n"
  821. " if (gnu_get_libc_version != 0)\n"
  822. " {\n"
  823. " ptr = gnu_get_libc_version ();\n"
  824. " glibcmajor = 4;\n"
  825. " }\n"
  826. " else if (&__libc_version != 0)\n"
  827. " {\n"
  828. " ptr = __libc_version;\n"
  829. " glibcmajor = 4;\n"
  830. " }\n"
  831. " else\n"
  832. " ptr = __linux_C_lib_version;\n"
  833. "\n"
  834. " while (!isdigit (*ptr))\n"
  835. " ptr++;\n"
  836. "\n"
  837. " sscanf (ptr, \"%d.%d.%d\", &libcmajor, &libcminor, &libcteeny);\n"
  838. " libcmajor += glibcmajor;\n"
  839. " }\n"
  840. "\n"
  841. " printf(\"#define DefaultLinuxCLibMajorVersion %d\\n\", libcmajor);\n"
  842. " printf(\"#define DefaultLinuxCLibMinorVersion %d\\n\", libcminor);\n"
  843. " printf(\"#define DefaultLinuxCLibTeenyVersion %d\\n\", libcteeny);\n"
  844. "\n"
  845. " return 0;\n"
  846. "}\n"
  847. ;
  848. #define libc32path "/usr/lib/libc.so"
  849. #define libc64path "/usr/lib64/libc.so"
  850. static void
  851. get_libc_version(FILE *inFile)
  852. {
  853. char* libcso = NULL;
  854. struct stat sb;
  855. char buf[PATH_MAX];
  856. char* ptr;
  857. int libcmajor, libcminor, libcteeny;
  858. struct utsname u;
  859. /*
  860. * If we are on a 64-bit Linux system and we see /usr/lib64/libc.so,
  861. * we should use it. Otherwise go with /usr/lib/libc.so. It is entirely
  862. * possible that someone will be running a 32-bit userland on a 64-bit
  863. * system.
  864. */
  865. if (uname(&u) == -1) {
  866. fprintf(stderr, "%s (%d): %s\n", __func__, __LINE__, strerror(errno));
  867. abort();
  868. }
  869. if (!strcmp(u.sysname, "Linux") &&
  870. (!strcmp(u.machine, "x86_64"))) {
  871. if (!lstat (libc64path, &sb) && S_ISREG(sb.st_mode)) {
  872. libcso = libc64path;
  873. }
  874. }
  875. if (libcso == NULL) {
  876. libcso = libc32path;
  877. }
  878. if (lstat (libcso, &sb) == 0) {
  879. if (S_ISLNK (sb.st_mode)) {
  880. /*
  881. * /usr/lib/libc.so is a symlink -- this is libc 5.x
  882. * we can do this the quick way
  883. */
  884. if (readlink (libcso, buf, PATH_MAX) >= 0) {
  885. for (ptr = buf; *ptr && !isdigit (*ptr); ptr++);
  886. int ret = sscanf (ptr, "%d.%d.%d", &libcmajor, &libcminor, &libcteeny);
  887. (void) ret;
  888. fprintf(inFile, "#define DefaultLinuxCLibMajorVersion %d\n", libcmajor);
  889. fprintf(inFile, "#define DefaultLinuxCLibMinorVersion %d\n", libcminor);
  890. fprintf(inFile, "#define DefaultLinuxCLibTeenyVersion %d\n", libcteeny);
  891. }
  892. } else {
  893. /*
  894. * /usr/lib/libc.so is NOT a symlink -- this is libc 6.x / glibc 2.x
  895. * now we have to figure this out the hard way.
  896. */
  897. char aout[PATH_MAX];
  898. int fd = -1;
  899. FILE *fp;
  900. const char *format = "%s -o %s -x c -";
  901. char *cc;
  902. int len;
  903. char *command;
  904. memset(aout, '\0', PATH_MAX);
  905. if (!lstat(getenv("TMPDIR"), &sb) && S_ISDIR(sb.st_mode))
  906. strncpy(aout, getenv("TMPDIR"), PATH_MAX - 1);
  907. #ifdef P_tmpdir /* defined by XPG and XOPEN, but don't assume we have it */
  908. else if (!lstat(P_tmpdir, &sb) && S_ISDIR(sb.st_mode))
  909. strncpy(aout, P_tmpdir, PATH_MAX - 1);
  910. #endif
  911. else if (!lstat("/tmp", &sb) && S_ISDIR(sb.st_mode))
  912. strncpy(aout, "/tmp", PATH_MAX - 1);
  913. else
  914. abort();
  915. strncat(aout, "/imaketmp.XXXXXX", PATH_MAX - 1);
  916. if ((fd = mkstemp(aout)) == -1)
  917. abort ();
  918. if (close(fd) == -1)
  919. abort ();
  920. cc = getenv ("CC");
  921. if (cc == NULL)
  922. cc = "gcc";
  923. len = strlen (aout) + strlen (format) + strlen (cc);
  924. if (len < 128) len = 128;
  925. command = alloca (len);
  926. if (snprintf (command , len, format, cc, aout) == len)
  927. abort ();
  928. fp = popen (command, "w");
  929. if (fp == NULL || fprintf (fp, "%s\n", libc_c) < 0 || pclose (fp) != 0)
  930. abort ();
  931. fp = popen (aout, "r");
  932. if (fp == NULL)
  933. abort ();
  934. while (fgets (command, len, fp))
  935. fprintf (inFile, "%s", command);
  936. len = pclose (fp);
  937. remove (aout);
  938. if (len)
  939. abort ();
  940. }
  941. }
  942. }
  943. static void
  944. get_ld_version(FILE *inFile)
  945. {
  946. FILE* ldprog = popen ("ld -v", "r");
  947. char c;
  948. int ldmajor, ldminor;
  949. if (ldprog) {
  950. do {
  951. c = fgetc (ldprog);
  952. } while (c != EOF && !isdigit (c));
  953. ungetc (c, ldprog);
  954. int ret = fscanf (ldprog, "%d.%d", &ldmajor, &ldminor);
  955. (void) ret;
  956. fprintf(inFile, "#define DefaultLinuxBinUtilsMajorVersion %d\n",
  957. ldmajor * 10 + ldminor);
  958. pclose (ldprog);
  959. }
  960. }
  961. #endif
  962. #ifndef PATH_MAX
  963. #define PATH_MAX 1024
  964. #endif
  965. #if defined(sun) && defined(__SVR4)
  966. static char *
  967. get_full_path(const char *program)
  968. {
  969. char *buf;
  970. char *cmd;
  971. FILE *proc;
  972. buf = calloc(1, PATH_MAX);
  973. asprintf(&cmd, "command -v %s", program);
  974. if ((proc = popen (cmd, "r")) != NULL)
  975. fgets (buf, PATH_MAX, proc);
  976. pclose (proc);
  977. return strtok (buf, "\n"); /* strip newline */
  978. }
  979. static int
  980. get_sun_compiler_version(const char *fspec, const char *product,
  981. int *cmajor, int *cminor)
  982. {
  983. char buf[PATH_MAX];
  984. char cmd[PATH_MAX];
  985. char *vptr;
  986. struct stat sb;
  987. FILE *ccproc;
  988. int ret;
  989. char vendor[4];
  990. if (lstat (fspec, &sb) != 0)
  991. return ENOENT;
  992. strncpy (cmd, fspec, PATH_MAX);
  993. strlcpy (vendor, product, 4);
  994. if (strcmp (vendor, "Sun") == 0)
  995. strncat (cmd, " -V 2>&1", 8);
  996. else if (strcmp (vendor, "Gnu") == 0)
  997. strncat (cmd, " --version 2>&1", 15);
  998. else
  999. return EINVAL;
  1000. if ((ccproc = popen (cmd, "r")) != NULL) {
  1001. if (fgets (buf, PATH_MAX, ccproc) != NULL) {
  1002. for (vptr = buf; !isdigit(*vptr) && *vptr != NULL; vptr++);
  1003. if (*vptr == NULL) {
  1004. pclose (ccproc);
  1005. return EINVAL;
  1006. } else {
  1007. ret = sscanf (vptr, "%d.%d", cmajor, cminor);
  1008. }
  1009. }
  1010. pclose (ccproc);
  1011. } else {
  1012. return EIO;
  1013. }
  1014. return 0;
  1015. }
  1016. static void
  1017. get_sun_compiler_versions(FILE *inFile)
  1018. {
  1019. static const char *compilers[][2] =
  1020. {{"SunProC", "/opt/solarisstudio/bin/cc"},
  1021. {"SunProCplusplus", "/opt/solarisstudio/bin/CC"},
  1022. {"GnuC", "gcc"},
  1023. {"GnuCplusplus", "g++"}};
  1024. int cmajor, cminor;
  1025. int i;
  1026. int ret;
  1027. for (i = 0; i < sizeof compilers / sizeof compilers[0]; i++) {
  1028. const char *product = compilers[i][0];
  1029. char *fspec = get_full_path (compilers[i][1]);
  1030. ret = get_sun_compiler_version (fspec, product, &cmajor, &cminor);
  1031. free (fspec);
  1032. if (ret == 0) {
  1033. fprintf (inFile,
  1034. "#define Default%sCompilerMajorVersion %d\n",
  1035. product,
  1036. cmajor);
  1037. fprintf (inFile,
  1038. "#define Default%sCompilerMinorVersion %d\n",
  1039. product,
  1040. cminor);
  1041. } else if (ret == EINVAL) {
  1042. printf ("Failed to detect version of compiler: %s\n", product);
  1043. exit (EINVAL);
  1044. }
  1045. }
  1046. (void) ret;
  1047. }
  1048. #endif
  1049. static void
  1050. get_gcc_incdir(FILE *inFile)
  1051. {
  1052. static char* gcc_path[] = {
  1053. #ifdef linux
  1054. "/usr/bin/cc", /* for Linux PostIncDir */
  1055. #endif
  1056. #ifdef sun
  1057. "gcc",
  1058. #endif
  1059. "/usr/local/bin/gcc",
  1060. "/opt/gnu/bin/gcc"
  1061. };
  1062. struct stat sb;
  1063. int i;
  1064. FILE* gccproc;
  1065. char buf[PATH_MAX];
  1066. char cmd[PATH_MAX];
  1067. char* ptr;
  1068. memset(buf, 0, PATH_MAX);
  1069. for (i = 0; i < sizeof gcc_path / sizeof gcc_path[0]; i++) {
  1070. #ifdef sun
  1071. gcc_path[i] = get_full_path (gcc_path[i]);
  1072. #endif
  1073. if (lstat (gcc_path[i], &sb) == 0) {
  1074. #ifdef sun
  1075. free (gcc_path[i]);
  1076. #endif
  1077. strncpy (cmd, gcc_path[i], PATH_MAX - 1 );
  1078. strncat (cmd, " --print-libgcc-file-name", PATH_MAX - 1);
  1079. if ((gccproc = popen (cmd, "r")) != NULL) {
  1080. if (fgets (buf, PATH_MAX - 1, gccproc) != NULL) {
  1081. ptr = strstr (buf, "libgcc.a");
  1082. if (ptr) strncpy (ptr, "include", 8);
  1083. }
  1084. (void) pclose (gccproc);
  1085. break;
  1086. }
  1087. }
  1088. }
  1089. if (buf[0])
  1090. fprintf (inFile, "#define DefaultGccIncludeDir %s\n", buf);
  1091. }
  1092. static boolean
  1093. define_os_defaults(FILE *inFile)
  1094. {
  1095. #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
  1096. defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
  1097. struct utsname name;
  1098. char buf[SYS_NMLN * 5 + 1];
  1099. /* Obtain the system information. */
  1100. if (uname(&name) < 0)
  1101. LogFatal("Cannot invoke uname");
  1102. # ifdef DEFAULT_OS_NAME
  1103. parse_utsname(&name, DEFAULT_OS_NAME, buf,
  1104. "Bad DEFAULT_OS_NAME syntax %s");
  1105. if (buf[0] != '\0')
  1106. fprintf(inFile, "#define DefaultOSName %s\n", buf);
  1107. # endif
  1108. # ifdef DEFAULT_OS_MAJOR_REV
  1109. parse_utsname(&name, DEFAULT_OS_MAJOR_REV, buf,
  1110. "Bad DEFAULT_OS_MAJOR_REV syntax %s");
  1111. fprintf(inFile, "#define DefaultOSMajorVersion %s\n",
  1112. *buf ? trim_version(buf) : "0");
  1113. # endif
  1114. # ifdef DEFAULT_OS_MINOR_REV
  1115. parse_utsname(&name, DEFAULT_OS_MINOR_REV, buf,
  1116. "Bad DEFAULT_OS_MINOR_REV syntax %s");
  1117. fprintf(inFile, "#define DefaultOSMinorVersion %s\n",
  1118. *buf ? trim_version(buf) : "0");
  1119. # endif
  1120. # ifdef DEFAULT_OS_TEENY_REV
  1121. parse_utsname(&name, DEFAULT_OS_TEENY_REV, buf,
  1122. "Bad DEFAULT_OS_TEENY_REV syntax %s");
  1123. fprintf(inFile, "#define DefaultOSTeenyVersion %s\n",
  1124. *buf ? trim_version(buf) : "0");
  1125. # endif
  1126. #endif
  1127. #ifdef linux
  1128. get_distrib (inFile);
  1129. get_libc_version (inFile);
  1130. get_ld_version(inFile);
  1131. #endif
  1132. get_gcc_incdir(inFile);
  1133. #if defined (sun) && defined(SVR4)
  1134. get_sun_compiler_versions (inFile);
  1135. #endif
  1136. return FALSE;
  1137. }
  1138. static void
  1139. cppit(const char *imakefile, const char *template, const char *masterc, FILE *outfd, const char *outfname)
  1140. {
  1141. FILE *inFile;
  1142. haveImakefileC = TRUE;
  1143. inFile = fopen(masterc, "w");
  1144. if (inFile == NULL)
  1145. LogFatal("Cannot open %s for output.", masterc);
  1146. if (fprintf(inFile, "%s\n", ImakefileCHeader) < 0 ||
  1147. define_os_defaults(inFile) ||
  1148. optional_include(inFile, "IMAKE_LOCAL_DEFINES", "localdefines") ||
  1149. optional_include(inFile, "IMAKE_ADMIN_DEFINES", "admindefines") ||
  1150. fprintf(inFile, "#define %s <%s>\n", ImakeDefSym, imakefile) < 0 ||
  1151. fprintf(inFile, LocalDefineFmt, ImakeTmplSym, template) < 0 ||
  1152. fprintf(inFile, IncludeFmt, ImakeTmplSym) < 0 ||
  1153. optional_include(inFile, "IMAKE_ADMIN_MACROS", "adminmacros") ||
  1154. optional_include(inFile, "IMAKE_LOCAL_MACROS", "localmacros") ||
  1155. fflush(inFile) ||
  1156. fclose(inFile))
  1157. LogFatal("Cannot write to %s.", masterc);
  1158. /*
  1159. * Fork and exec cpp
  1160. */
  1161. doit(outfd, cpp, cpp_argv);
  1162. CleanCppOutput(outfd, outfname);
  1163. }
  1164. static void
  1165. makeit(void)
  1166. {
  1167. doit(NULL, make_argv[0], make_argv);
  1168. }
  1169. static char *
  1170. CleanCppInput(char *imakefile)
  1171. {
  1172. FILE *outFile = NULL;
  1173. FILE *inFile;
  1174. char *buf, /* buffer for file content */
  1175. *pbuf, /* walking pointer to buf */
  1176. *punwritten, /* pointer to unwritten portion of buf */
  1177. *ptoken, /* pointer to # token */
  1178. *pend, /* pointer to end of # token */
  1179. savec; /* temporary character holder */
  1180. int count;
  1181. struct stat st;
  1182. /*
  1183. * grab the entire file.
  1184. */
  1185. if (!(inFile = fopen(imakefile, "r")))
  1186. LogFatal("Cannot open %s for input.", imakefile);
  1187. if (fstat(fileno(inFile), &st) < 0)
  1188. LogFatal("Cannot stat %s for size.", imakefile);
  1189. buf = Emalloc((int)st.st_size+3);
  1190. count = fread(buf + 2, 1, st.st_size, inFile);
  1191. if (count == 0 && st.st_size != 0)
  1192. LogFatal("Cannot read %s:", imakefile);
  1193. fclose(inFile);
  1194. buf[0] = '\n';
  1195. buf[1] = '\n';
  1196. buf[count + 2] = '\0';
  1197. punwritten = pbuf = buf + 2;
  1198. while (*pbuf) {
  1199. /* for compatibility, replace make comments for cpp */
  1200. if (*pbuf == '#' && pbuf[-1] == '\n' && pbuf[-2] != '\\') {
  1201. ptoken = pbuf+1;
  1202. while (*ptoken == ' ' || *ptoken == '\t')
  1203. ptoken++;
  1204. pend = ptoken;
  1205. while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
  1206. pend++;
  1207. savec = *pend;
  1208. *pend = '\0';
  1209. if (strcmp(ptoken, "define") &&
  1210. strcmp(ptoken, "if") &&
  1211. strcmp(ptoken, "ifdef") &&
  1212. strcmp(ptoken, "ifndef") &&
  1213. strcmp(ptoken, "include") &&
  1214. strcmp(ptoken, "line") &&
  1215. strcmp(ptoken, "else") &&
  1216. strcmp(ptoken, "elif") &&
  1217. strcmp(ptoken, "endif") &&
  1218. strcmp(ptoken, "error") &&
  1219. strcmp(ptoken, "pragma") &&
  1220. strcmp(ptoken, "undef")) {
  1221. if (outFile == NULL) {
  1222. tmpImakefile = Strdup(tmpImakefile);
  1223. int ret = mkstemp(tmpImakefile);
  1224. (void) ret;
  1225. outFile = fopen(tmpImakefile, "w");
  1226. if (outFile == NULL)
  1227. LogFatal("Cannot open %s for write.",
  1228. tmpImakefile);
  1229. }
  1230. writetmpfile(outFile, punwritten, pbuf-punwritten,
  1231. tmpImakefile);
  1232. if (ptoken > pbuf + 1)
  1233. writetmpfile(outFile, "XCOMM", 5, tmpImakefile);
  1234. else
  1235. writetmpfile(outFile, "XCOMM ", 6, tmpImakefile);
  1236. punwritten = pbuf + 1;
  1237. }
  1238. *pend = savec;
  1239. }
  1240. pbuf++;
  1241. }
  1242. if (outFile) {
  1243. writetmpfile(outFile, punwritten, pbuf-punwritten, tmpImakefile);
  1244. fclose(outFile);
  1245. return tmpImakefile;
  1246. }
  1247. return(imakefile);
  1248. }
  1249. static void
  1250. CleanCppOutput(FILE *tmpfd, const char *tmpfname)
  1251. {
  1252. char *input;
  1253. int blankline = 0;
  1254. while ((input = ReadLine(tmpfd, tmpfname))) {
  1255. if (isempty(input)) {
  1256. if (blankline++)
  1257. continue;
  1258. KludgeResetRule();
  1259. } else {
  1260. blankline = 0;
  1261. KludgeOutputLine(&input);
  1262. writetmpfile(tmpfd, input, strlen(input), tmpfname);
  1263. }
  1264. writetmpfile(tmpfd, "\n", 1, tmpfname);
  1265. }
  1266. fflush(tmpfd);
  1267. #ifdef NFS_STDOUT_BUG
  1268. /*
  1269. * On some systems, NFS seems to leave a large number of nulls at
  1270. * the end of the file. Ralph Swick says that this kludge makes the
  1271. * problem go away.
  1272. */
  1273. ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
  1274. #endif
  1275. }
  1276. /*
  1277. * Determine if a line has nothing in it. As a side effect, we trim white
  1278. * space from the end of the line. Cpp magic cookies are also thrown away.
  1279. * "XCOMM" token is transformed to "#".
  1280. */
  1281. static boolean
  1282. isempty(char *line)
  1283. {
  1284. char *pend;
  1285. /*
  1286. * Check for lines of the form
  1287. * # n "...
  1288. * or
  1289. * # line n "...
  1290. */
  1291. if (*line == '#') {
  1292. pend = line+1;
  1293. if (*pend == ' ')
  1294. pend++;
  1295. if (*pend == 'l' && pend[1] == 'i' && pend[2] == 'n' &&
  1296. pend[3] == 'e' && pend[4] == ' ')
  1297. pend += 5;
  1298. if (isdigit((int)*pend)) {
  1299. do {
  1300. pend++;
  1301. } while (isdigit((int)*pend));
  1302. if (*pend == '\n' || *pend == '\0')
  1303. return(TRUE);
  1304. if (*pend++ == ' ' && *pend == '"')
  1305. return(TRUE);
  1306. }
  1307. while (*pend)
  1308. pend++;
  1309. } else {
  1310. for (pend = line; *pend; pend++) {
  1311. if (*pend == 'X' && pend[1] == 'C' && pend[2] == 'O' &&
  1312. pend[3] == 'M' && pend[4] == 'M' &&
  1313. (pend == line || pend[-1] == ' ' || pend[-1] == '\t') &&
  1314. (pend[5] == ' ' || pend[5] == '\t' || pend[5] == '\0'))
  1315. {
  1316. *pend = '#';
  1317. strncpy(pend+1, pend+5, 1);
  1318. }
  1319. #ifdef MAGIC_MAKE_VARS
  1320. if (*pend == 'X' && pend[1] == 'V' && pend[2] == 'A' &&
  1321. pend[3] == 'R')
  1322. {
  1323. char varbuf[5];
  1324. int i;
  1325. if (pend[4] == 'd' && pend[5] == 'e' && pend[6] == 'f' &&
  1326. pend[7] >= '0' && pend[7] <= '9')
  1327. {
  1328. i = pend[7] - '0';
  1329. snprintf(varbuf, 5, "%0.4d", xvariable);
  1330. strncpy(pend+4, varbuf, 4);
  1331. xvariables[i] = xvariable;
  1332. xvariable = (xvariable + 1) % 10000;
  1333. }
  1334. else if (pend[4] == 'u' && pend[5] == 's' &&
  1335. pend[6] == 'e' && pend[7] >= '0' &&
  1336. pend[7] <= '9')
  1337. {
  1338. i = pend[7] - '0';
  1339. snprintf(varbuf, 5, "%0.4d", xvariables[i]);
  1340. strncpy(pend+4, varbuf, 4);
  1341. }
  1342. }
  1343. #endif
  1344. }
  1345. }
  1346. while (--pend >= line && (*pend == ' ' || *pend == '\t')) ;
  1347. pend[1] = '\0';
  1348. return (*line == '\0');
  1349. }
  1350. /*ARGSUSED*/
  1351. static char *
  1352. ReadLine(FILE *tmpfd, const char *tmpfname)
  1353. {
  1354. static boolean initialized = FALSE;
  1355. static char *buf, *pline, *end;
  1356. char *p1, *p2;
  1357. if (! initialized) {
  1358. int total_red;
  1359. struct stat st;
  1360. /*
  1361. * Slurp it all up.
  1362. */
  1363. fseek(tmpfd, 0, 0);
  1364. if (fstat(fileno(tmpfd), &st) < 0)
  1365. LogFatal("cannot stat %s for size", tmpMakefile);
  1366. pline = buf = Emalloc((int)st.st_size+1);
  1367. total_red = fread(buf, 1, st.st_size, tmpfd);
  1368. if (total_red == 0 && st.st_size != 0)
  1369. LogFatal("cannot read %s", tmpMakefile);
  1370. end = buf + total_red;
  1371. *end = '\0';
  1372. fseek(tmpfd, 0, 0);
  1373. #if defined(SYSV)
  1374. tmpfd = freopen(tmpfname, "w+", tmpfd);
  1375. if (! tmpfd)
  1376. LogFatal("cannot reopen %s.", tmpfname);
  1377. #else /* !SYSV */
  1378. int ret = ftruncate(fileno(tmpfd), (off_t) 0);
  1379. (void) ret;
  1380. #endif /* !SYSV */
  1381. initialized = TRUE;
  1382. fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
  1383. fprintf (tmpfd, "# %s\n",
  1384. "$TOG: imake.c /main/104 1998/03/24 12:45:15 kaleb $");
  1385. }
  1386. for (p1 = pline; p1 < end; p1++) {
  1387. if (*p1 == '@' && *(p1+1) == '@'
  1388. /* ignore ClearCase version-extended pathnames */
  1389. && !(p1 != pline && !isspace((int)*(p1-1))
  1390. && *(p1+2) == '/'))
  1391. { /* soft EOL */
  1392. *p1++ = '\0';
  1393. p1++; /* skip over second @ */
  1394. break;
  1395. }
  1396. else if (*p1 == '\n') { /* real EOL */
  1397. *p1++ = '\0';
  1398. break;
  1399. }
  1400. }
  1401. /*
  1402. * return NULL at the end of the file.
  1403. */
  1404. p2 = (pline == p1 ? NULL : pline);
  1405. pline = p1;
  1406. return(p2);
  1407. }
  1408. static void
  1409. writetmpfile(FILE *fd, const char *buf, int cnt, const char *fname)
  1410. {
  1411. if (fwrite(buf, sizeof(char), cnt, fd) == -1)
  1412. LogFatal("Cannot write to %s.", fname);
  1413. }
  1414. static char *
  1415. Emalloc(int size)
  1416. {
  1417. char *p;
  1418. if ((p = malloc(size)) == NULL)
  1419. LogFatal("Cannot allocate %d bytes.", size);
  1420. return(p);
  1421. }
  1422. #ifdef FIXUP_CPP_WHITESPACE
  1423. static void
  1424. KludgeOutputLine(char **pline)
  1425. {
  1426. char *p = *pline;
  1427. char quotechar = '\0';
  1428. switch (*p) {
  1429. case '#': /*Comment - ignore*/
  1430. break;
  1431. case '\t': /*Already tabbed - ignore it*/
  1432. break;
  1433. case ' ': /*May need a tab*/
  1434. default:
  1435. # ifdef INLINE_SYNTAX
  1436. if (*p == '<' && p[1] == '<') { /* inline file close */
  1437. InInline--;
  1438. InRule = TRUE;
  1439. break;
  1440. }
  1441. # endif
  1442. /*
  1443. * The following cases should not be treated as beginning of
  1444. * rules:
  1445. * variable := name (GNU make)
  1446. * variable = .*:.* (':' should be allowed as value)
  1447. * sed 's:/a:/b:' (: used in quoted values)
  1448. */
  1449. for (; *p; p++) {
  1450. if (quotechar) {
  1451. if (quotechar == '\\' ||
  1452. (*p == quotechar &&
  1453. p[-1] != '\\'))
  1454. quotechar = '\0';
  1455. continue;
  1456. }
  1457. switch (*p) {
  1458. case '\\':
  1459. case '"':
  1460. case '\'':
  1461. quotechar = *p;
  1462. break;
  1463. case '(':
  1464. quotechar = ')';
  1465. break;
  1466. case '{':
  1467. quotechar = '}';
  1468. break;
  1469. case '[':
  1470. quotechar = ']';
  1471. break;
  1472. case '=':
  1473. # ifdef REMOVE_CPP_LEADSPACE
  1474. if (!InRule && **pline == ' ') {
  1475. while (**pline == ' ')
  1476. (*pline)++;
  1477. }
  1478. # endif
  1479. goto breakfor;
  1480. # ifdef INLINE_SYNTAX
  1481. case '<':
  1482. if (p[1] == '<') /* inline file start */
  1483. InInline++;
  1484. break;
  1485. # endif
  1486. case ':':
  1487. if (p[1] == '=')
  1488. goto breakfor;
  1489. while (**pline == ' ')
  1490. (*pline)++;
  1491. InRule = TRUE;
  1492. return;
  1493. }
  1494. }
  1495. breakfor:
  1496. if (InRule && **pline == ' ')
  1497. **pline = '\t';
  1498. break;
  1499. }
  1500. }
  1501. static void
  1502. KludgeResetRule(void)
  1503. {
  1504. InRule = FALSE;
  1505. }
  1506. #endif /* FIXUP_CPP_WHITESPACE */
  1507. static char *
  1508. Strdup(const char *cp)
  1509. {
  1510. char *new = Emalloc(strlen(cp) + 1);
  1511. memcpy(new, cp, strlen(cp) + 1);
  1512. return new;
  1513. }