Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
7.7 KiB

  1. /*****************************************************************************
  2. *
  3. * main.c
  4. *
  5. * Main program.
  6. *
  7. *****************************************************************************/
  8. #include "m4.h"
  9. /*****************************************************************************
  10. *
  11. * InitDiversions
  12. *
  13. *****************************************************************************/
  14. void STDCALL
  15. InitDiversions(void)
  16. {
  17. g_pdivOut = pdivAlloc();
  18. g_pdivOut->hf = hfOut;
  19. g_pdivOut->ptchName = ptchDupPtch(TEXT("<stdout>"));
  20. if (fInteractiveHf(g_pdivOut->hf)) {
  21. UnbufferPdiv(g_pdivOut);
  22. }
  23. g_pdivErr = pdivAlloc();
  24. g_pdivErr->hf = hfErr;
  25. g_pdivErr->ptchName = ptchDupPtch(TEXT("<stderr>"));
  26. g_pdivNul = pdivAlloc();
  27. g_pdivNul->hf = hfOpenPtchOf(c_tszNullDevice, OF_WRITE);
  28. g_pdivNul->ptchName = ptchDupPtch(TEXT("<nul>"));
  29. g_pdivArg = pdivAlloc();
  30. g_pdivExp = pdivAlloc();
  31. g_pdivCur = g_pdivOut;
  32. }
  33. /*****************************************************************************
  34. *
  35. * hfPathOpenPtch
  36. *
  37. * Open a file, searching the -I include path if necessary.
  38. *
  39. *****************************************************************************/
  40. LPTSTR g_ptszIncludePath;
  41. HF STDCALL
  42. hfPathOpenPtch(PTCH ptch)
  43. {
  44. /* First try in the current directory */
  45. HFILE hf = hfOpenPtchOf(ptch, OF_READ);
  46. if (hf == hfNil) {
  47. /* If that failed, then look on the g_ptszIncludePath (if any) */
  48. if (g_ptszIncludePath) {
  49. TCHAR tszNewPath[MAX_PATH];
  50. if (SearchPath(g_ptszIncludePath, ptch, NULL, MAX_PATH, tszNewPath, NULL)) {
  51. hf = hfOpenPtchOf(tszNewPath, OF_READ);
  52. }
  53. }
  54. }
  55. return hf;
  56. }
  57. /*****************************************************************************
  58. *
  59. * hfInputPtchF
  60. *
  61. * Push the requested file onto the input stream, returning the
  62. * file handle, or hfNil on failure. The filename should be on
  63. * the heap. If fFatal is set, then die if the file could not be
  64. * opened.
  65. *
  66. *****************************************************************************/
  67. HF STDCALL
  68. hfInputPtchF(PTCH ptch, F fFatal)
  69. {
  70. HFILE hf = hfPathOpenPtch(ptch);
  71. if (hf != hfNil) {
  72. pstmPushHfPtch(hf, ptch);
  73. } else {
  74. if (fFatal) {
  75. #ifdef ATT_ERROR
  76. Die("can't open file");
  77. #else
  78. Die("Cannot open %s: %s", ptch, strerror(errno));
  79. #endif
  80. }
  81. }
  82. return hf;
  83. }
  84. /*****************************************************************************
  85. *
  86. * InputHfPtsz
  87. *
  88. * Push the requested file onto the input stream, with appropriate
  89. * end-of-input markers.
  90. *
  91. * If hf is not hfNil, then it is the file handle to push and
  92. * ptch is the friendly to associate with it.
  93. *
  94. * If hf is hfNil, then ptch is a filename which should be opened and
  95. * pushed.
  96. *
  97. *****************************************************************************/
  98. void STDCALL
  99. InputHfPtsz(HF hf, PTCH ptch)
  100. {
  101. pstmPushStringCtch(2);
  102. PushPtok(&tokEoi);
  103. ptch = ptchDupPtch(ptch);
  104. if (ptch) {
  105. if (hf == hfNil) {
  106. hfInputPtchF(ptch, 1);
  107. } else {
  108. pstmPushHfPtch(hf, ptch);
  109. }
  110. }
  111. }
  112. /*****************************************************************************
  113. *
  114. * DefinePtsz
  115. *
  116. * Handle a macro definition on the command line.
  117. *
  118. * The macro name consists of everything up to the `='.
  119. *
  120. * If there is no `=', then everything is the name and the value
  121. * is null.
  122. *
  123. * We need four tok's in our fake argv:
  124. *
  125. * argv[-1] = $#
  126. * argv[0] = `define' (we don't bother setting this)
  127. * argv[1] = var
  128. * argv[2] = value
  129. *
  130. *****************************************************************************/
  131. void STDCALL
  132. DefinePtsz(PTSTR ptszVar)
  133. {
  134. PTSTR ptsz, ptszValue;
  135. int itok;
  136. TOK rgtok[4];
  137. for (itok = 0; itok < cA(rgtok); itok++) {
  138. D(rgtok[itok].sig = sigUPtok);
  139. D(rgtok[itok].tsfl = 0);
  140. }
  141. SetPtokCtch(&rgtok[0], 3);
  142. /*
  143. * Look for the = if we have one.
  144. */
  145. for (ptsz = ptszVar; *ptsz; ptsz++) {
  146. if (*ptsz == TEXT('=')) {
  147. *ptsz = TEXT('\0');
  148. ptszValue = ptsz + 1;
  149. goto foundval;
  150. }
  151. }
  152. ptszValue = ptsz;
  153. foundval:;
  154. SetStaticPtokPtchCtch(&rgtok[3], ptszValue, strlen(ptszValue));
  155. SetStaticPtokPtchCtch(&rgtok[2], ptszVar, strlen(ptszVar));
  156. opDefine(&rgtok[1]);
  157. }
  158. /*****************************************************************************
  159. *
  160. * SetIncludePathPtsz
  161. *
  162. * Set the include path, which will be used to resolve filenames.
  163. *
  164. *****************************************************************************/
  165. const TCHAR c_tszIncludePath[] =
  166. TEXT("Error: Cannot specify -I more than once. (If you need multiple") EOL
  167. TEXT(" directories, separate them with a semicolon.)") EOL
  168. ;
  169. BOOL STDCALL
  170. SetIncludePathPtsz(PTSTR ptszPath)
  171. {
  172. if (g_ptszIncludePath) {
  173. cbWriteHfPvCb(hfErr, c_tszIncludePath, cbCtch(cA(c_tszIncludePath) - 1));
  174. return FALSE;
  175. }
  176. g_ptszIncludePath = ptszPath;
  177. return TRUE;
  178. }
  179. /*****************************************************************************
  180. *
  181. * Usage
  182. *
  183. * Quick usage string.
  184. *
  185. *****************************************************************************/
  186. const TCHAR c_tszUsage[] =
  187. TEXT("Usage: m4 [-?] [-Dvar[=value]] [filename(s)]") EOL
  188. EOL
  189. TEXT("Win32 implementation of the m4 preprocessor.") EOL
  190. EOL
  191. TEXT("-?") EOL
  192. TEXT(" Displays this usage string.") EOL
  193. EOL
  194. TEXT("-Dvar[=value]") EOL
  195. TEXT(" Defines an M4 preprocessor symbol with optional initial value.") EOL
  196. TEXT(" If no initial value is supplied, then the symbol is define with") EOL
  197. TEXT(" a null value.") EOL
  198. EOL
  199. TEXT("[filename(s)]") EOL
  200. TEXT(" Optional list of files to process. If no files are given, then") EOL
  201. TEXT(" preprocesses from stdin. The result is sent to stdout.") EOL
  202. EOL
  203. TEXT("See m4.man for language description.") EOL
  204. TEXT("See m4.txt for implementation description.") EOL
  205. ;
  206. /*****************************************************************************
  207. *
  208. * main
  209. *
  210. *****************************************************************************/
  211. int CDECL
  212. main(int argc, char **argv)
  213. {
  214. InitHash();
  215. InitPredefs();
  216. InitDiversions();
  217. Gc();
  218. ++argv, --argc; /* Eat $0 */
  219. /*
  220. * Process the command line options.
  221. */
  222. for ( ; argc && argv[0][0] == TEXT('-') && argv[0][1]; argv++, argc--) {
  223. switch (argv[0][1]) {
  224. case TEXT('D'):
  225. DefinePtsz(argv[0]+2);
  226. break;
  227. case TEXT('I'):
  228. if (!SetIncludePathPtsz(argv[0]+2)) {
  229. return 1;
  230. }
  231. break;
  232. default: /* Unknown - show usage */
  233. cbWriteHfPvCb(hfErr, c_tszUsage, cbCtch(cA(c_tszUsage) - 1));
  234. return 1;
  235. }
  236. }
  237. if (argc == 0) {
  238. argc = 1;
  239. argv[0] = TEXT("-"); /* Append imaginary "-" */
  240. }
  241. for ( ; argc; argv++, argc--) {
  242. if (argv[0][0] == '-' && argv[0][1] == '\0') {
  243. InputHfPtsz(hfIn, TEXT("<stdin>"));
  244. } else {
  245. InputHfPtsz(hfNil, argv[0]);
  246. }
  247. for (;;) {
  248. TOK tok;
  249. TYP typ = typXtokPtok(&tok);
  250. if (typ == typMagic) {
  251. if (ptchPtok(&tok)[1] == tchEoi) {
  252. break;
  253. }
  254. } else {
  255. AddPdivPtok(g_pdivCur, &tok);
  256. }
  257. PopArgPtok(&tok);
  258. }
  259. Gc();
  260. }
  261. FlushPdiv(g_pdivOut);
  262. FlushPdiv(g_pdivErr);
  263. /*
  264. * No point in flushing the null device.
  265. */
  266. return 0;
  267. }