Leaked source code of windows server 2003
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.

324 lines
8.5 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. #ifdef POSIX
  79. Die("Cannot open %s: %s", ptch, strerror(errno));
  80. #else
  81. LPTSTR ptszError;
  82. DWORD dwError = GetLastError();
  83. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS |
  84. FORMAT_MESSAGE_FROM_SYSTEM, 0, dwError,
  85. 0, (LPTSTR)&ptszError, 0, NULL);
  86. if (!ptszError)
  87. {
  88. ptszError = TEXT("unknown error");
  89. }
  90. Die("Cannot open %s: error %d: %s", ptch, dwError, ptszError);
  91. #endif
  92. #endif
  93. }
  94. }
  95. return hf;
  96. }
  97. /*****************************************************************************
  98. *
  99. * InputHfPtsz
  100. *
  101. * Push the requested file onto the input stream, with appropriate
  102. * end-of-input markers.
  103. *
  104. * If hf is not hfNil, then it is the file handle to push and
  105. * ptch is the friendly to associate with it.
  106. *
  107. * If hf is hfNil, then ptch is a filename which should be opened and
  108. * pushed.
  109. *
  110. *****************************************************************************/
  111. void STDCALL
  112. InputHfPtsz(HF hf, PTCH ptch)
  113. {
  114. pstmPushStringCtch(2);
  115. PushPtok(&tokEoi);
  116. ptch = ptchDupPtch(ptch);
  117. if (ptch) {
  118. if (hf == hfNil) {
  119. hfInputPtchF(ptch, 1);
  120. } else {
  121. pstmPushHfPtch(hf, ptch);
  122. }
  123. }
  124. }
  125. /*****************************************************************************
  126. *
  127. * DefinePtsz
  128. *
  129. * Handle a macro definition on the command line.
  130. *
  131. * The macro name consists of everything up to the `='.
  132. *
  133. * If there is no `=', then everything is the name and the value
  134. * is null.
  135. *
  136. * We need four tok's in our fake argv:
  137. *
  138. * argv[-1] = $#
  139. * argv[0] = `define' (we don't bother setting this)
  140. * argv[1] = var
  141. * argv[2] = value
  142. *
  143. *****************************************************************************/
  144. void STDCALL
  145. DefinePtsz(PTSTR ptszVar)
  146. {
  147. PTSTR ptsz, ptszValue;
  148. int itok;
  149. TOK rgtok[4];
  150. for (itok = 0; itok < cA(rgtok); itok++) {
  151. D(rgtok[itok].sig = sigUPtok);
  152. D(rgtok[itok].tsfl = 0);
  153. }
  154. SetPtokCtch(&rgtok[0], 3);
  155. /*
  156. * Look for the = if we have one.
  157. */
  158. for (ptsz = ptszVar; *ptsz; ptsz++) {
  159. if (*ptsz == TEXT('=')) {
  160. *ptsz = TEXT('\0');
  161. ptszValue = ptsz + 1;
  162. goto foundval;
  163. }
  164. }
  165. ptszValue = ptsz;
  166. foundval:;
  167. SetStaticPtokPtchCtch(&rgtok[3], ptszValue, strlen(ptszValue));
  168. SetStaticPtokPtchCtch(&rgtok[2], ptszVar, strlen(ptszVar));
  169. opDefine(&rgtok[1]);
  170. }
  171. /*****************************************************************************
  172. *
  173. * SetIncludePathPtsz
  174. *
  175. * Set the include path, which will be used to resolve filenames.
  176. *
  177. *****************************************************************************/
  178. const TCHAR c_tszIncludePath[] =
  179. TEXT("Error: Cannot specify -I more than once. (If you need multiple") EOL
  180. TEXT(" directories, separate them with a semicolon.)") EOL
  181. ;
  182. BOOL STDCALL
  183. SetIncludePathPtsz(PTSTR ptszPath)
  184. {
  185. if (g_ptszIncludePath) {
  186. cbWriteHfPvCb(hfErr, c_tszIncludePath, cbCtch(cA(c_tszIncludePath) - 1));
  187. return FALSE;
  188. }
  189. g_ptszIncludePath = ptszPath;
  190. return TRUE;
  191. }
  192. /*****************************************************************************
  193. *
  194. * Usage
  195. *
  196. * Quick usage string.
  197. *
  198. *****************************************************************************/
  199. const TCHAR c_tszUsage[] =
  200. TEXT("Usage: m4 [-?] [-Dvar[=value]] [filename(s)]") EOL
  201. EOL
  202. TEXT("Win32 implementation of the m4 preprocessor.") EOL
  203. EOL
  204. TEXT("-?") EOL
  205. TEXT(" Displays this usage string.") EOL
  206. EOL
  207. TEXT("-Dvar[=value]") EOL
  208. TEXT(" Defines an M4 preprocessor symbol with optional initial value.") EOL
  209. TEXT(" If no initial value is supplied, then the symbol is define with") EOL
  210. TEXT(" a null value.") EOL
  211. EOL
  212. TEXT("[filename(s)]") EOL
  213. TEXT(" Optional list of files to process. If no files are given, then") EOL
  214. TEXT(" preprocesses from stdin. The result is sent to stdout.") EOL
  215. EOL
  216. TEXT("See m4.man for language description.") EOL
  217. TEXT("See m4.txt for implementation description.") EOL
  218. ;
  219. /*****************************************************************************
  220. *
  221. * main
  222. *
  223. *****************************************************************************/
  224. int CDECL
  225. main(int argc, char **argv)
  226. {
  227. InitHash();
  228. InitPredefs();
  229. InitDiversions();
  230. Gc();
  231. ++argv, --argc; /* Eat $0 */
  232. /*
  233. * Process the command line options.
  234. */
  235. for ( ; argc && argv[0][0] == TEXT('-') && argv[0][1]; argv++, argc--) {
  236. switch (argv[0][1]) {
  237. case TEXT('D'):
  238. DefinePtsz(argv[0]+2);
  239. break;
  240. case TEXT('I'):
  241. if (!SetIncludePathPtsz(argv[0]+2)) {
  242. return 1;
  243. }
  244. break;
  245. default: /* Unknown - show usage */
  246. cbWriteHfPvCb(hfErr, c_tszUsage, cbCtch(cA(c_tszUsage) - 1));
  247. return 1;
  248. }
  249. }
  250. if (argc == 0) {
  251. argc = 1;
  252. argv[0] = TEXT("-"); /* Append imaginary "-" */
  253. }
  254. for ( ; argc; argv++, argc--) {
  255. if (argv[0][0] == '-' && argv[0][1] == '\0') {
  256. InputHfPtsz(hfIn, TEXT("<stdin>"));
  257. } else {
  258. InputHfPtsz(hfNil, argv[0]);
  259. }
  260. for (;;) {
  261. TOK tok;
  262. TYP typ = typXtokPtok(&tok);
  263. if (typ == typMagic) {
  264. if (ptchPtok(&tok)[1] == tchEoi) {
  265. break;
  266. }
  267. } else {
  268. AddPdivPtok(g_pdivCur, &tok);
  269. }
  270. PopArgPtok(&tok);
  271. }
  272. Gc();
  273. }
  274. FlushPdiv(g_pdivOut);
  275. FlushPdiv(g_pdivErr);
  276. /*
  277. * No point in flushing the null device.
  278. */
  279. return 0;
  280. }