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.

399 lines
10 KiB

  1. /*****************************************************************************
  2. *
  3. * builtin.c
  4. *
  5. * Builtin macros.
  6. *
  7. *****************************************************************************/
  8. #include "m4.h"
  9. extern TOK tokColonTab;
  10. extern TOK tokEol;
  11. /*****************************************************************************
  12. *
  13. * opIfdef
  14. *
  15. * If $1 is defined, then return $2, else $3.
  16. *
  17. * If $# < 2, then there's no point in returning anything at all.
  18. *
  19. * The extra ptokNil covers us in the case where $# is 2.
  20. *
  21. * QUIRK! GNU m4 emits a warning if $# < 2. AT&T remains silent.
  22. * I side with AT&T on this one.
  23. *
  24. * QUIRK! GNU m4 emits `$0' if $# = 0. AT&T silently ignores
  25. * the entire macro call. I side with GNU on this one.
  26. *
  27. *****************************************************************************/
  28. DeclareOp(opIfdef)
  29. {
  30. if (ctokArgv >= 2) {
  31. if (pmacFindPtok(ptokArgv(1))) {
  32. PushPtok(ptokArgv(2));
  33. } else {
  34. PushPtok(ptokArgv(3));
  35. }
  36. } else if (ctokArgv == 0) {
  37. PushQuotedPtok(ptokArgv(0));
  38. } else {
  39. #ifdef STRICT_M4
  40. Warn("wrong number of arguments to %P", ptokArgv(0));
  41. #endif
  42. }
  43. }
  44. /*****************************************************************************
  45. *
  46. * opIfelse
  47. *
  48. * If $1 and $2 are identical, then return $3.
  49. * If there are only four arguments, then return $4.
  50. * Else, shift three and restart.
  51. *
  52. * If there are fewer than three arguments, then return nothing.
  53. *
  54. * The extra ptokNil saves us in the cases where $# = 2 + 3n.
  55. *
  56. * QUIRK! GNU m4 emits a warning if $# = 2 + 3n. AT&T remains silent.
  57. * I side with AT&T on this one.
  58. *
  59. *****************************************************************************/
  60. DeclareOp(opIfelse)
  61. {
  62. if (ctokArgv >= 3) { /* Need at least three for starters */
  63. ITOK itok = 1;
  64. do {
  65. if (fEqPtokPtok(ptokArgv(itok), ptokArgv(itok+1))) {
  66. PushPtok(ptokArgv(itok+2)); /* ptokNil saves us here */
  67. return;
  68. }
  69. itok += 3;
  70. } while (itok <= ctokArgv - 1); /* While at least two args left */
  71. if (itok == ctokArgv) { /* If only one left... */
  72. PushPtok(ptokArgv(itok));
  73. } else {
  74. Assert(itok == ctokArgv + 1); /* Else must be zero left */
  75. }
  76. return;
  77. }
  78. }
  79. /*****************************************************************************
  80. *
  81. * opShift
  82. *
  83. * Return all but the first argument, quoted and pushed back with
  84. * commas in between. We push them in reverse order so that they
  85. * show up properly.
  86. *
  87. *****************************************************************************/
  88. DeclareOpc(opcShift)
  89. {
  90. if (itok > 1) {
  91. PushQuotedPtok(ptok);
  92. if (itok > 2) {
  93. PushTch(tchComma);
  94. }
  95. }
  96. }
  97. DeclareOp(opShift)
  98. {
  99. EachReverseOpcArgvDw(opcShift, argv, 0);
  100. }
  101. /*****************************************************************************
  102. *
  103. * opLen
  104. *
  105. * Returns the length of its argument.
  106. * The extra ptokNil covers us in the case where $# is zero.
  107. *
  108. * QUIRK! AT&T m4 silently ignores the case where $# is zero, but
  109. * GNU m4 will emit `$0' so as to reduce potential conflict with an
  110. * identically-spelled language keyword. I side with GNU on this one.
  111. *
  112. * SOMEDAY! -- this quirk should be an op attribute.
  113. *
  114. *
  115. *****************************************************************************/
  116. DeclareOp(opLen)
  117. {
  118. if (ctokArgv) {
  119. #ifdef STRICT_M4
  120. if (ctokArgv != 1) {
  121. Warn("wrong number of arguments to %P", ptokArgv(0));
  122. }
  123. #endif
  124. PushAt(ctchArgv(1));
  125. } else {
  126. PushQuotedPtok(ptokArgv(0));
  127. }
  128. }
  129. /*****************************************************************************
  130. *
  131. * opTraceon
  132. *
  133. * With no arguments, turns on global tracing.
  134. * Otherwise, turns on local tracing on the specified macros.
  135. *
  136. * opTraceoff
  137. *
  138. * Turns off global tracing, and also turns off local tracing on the
  139. * specified macros (if any).
  140. *
  141. *****************************************************************************/
  142. DeclareOpc(opcTraceonoff)
  143. {
  144. PMAC pmac = pmacFindPtok(ptok);
  145. if (pmac) {
  146. pmac->pval->fTrace = dw;
  147. }
  148. }
  149. DeclareOp(opTraceon)
  150. {
  151. if (ctokArgv == 0) {
  152. g_fTrace = 1;
  153. } else {
  154. EachOpcArgvDw(opcTraceonoff, argv, 1);
  155. }
  156. }
  157. DeclareOp(opTraceoff)
  158. {
  159. g_fTrace = 0;
  160. EachOpcArgvDw(opcTraceonoff, argv, 0);
  161. }
  162. /*****************************************************************************
  163. *
  164. * opDnl
  165. *
  166. * Gobbles all characters up to and including the next newline.
  167. *
  168. * If EOF is reached, push the EOF back and stop.
  169. *
  170. * QUIRK! AT&T m4 silently ignores the case where $# > 0. GNU m4
  171. * issues a warning. I side with AT&T on this one.
  172. *
  173. *****************************************************************************/
  174. DeclareOp(opDnl)
  175. {
  176. TCH tch;
  177. #ifdef STRICT_M4
  178. if (ctokArgv != 0) {
  179. Warn("wrong number of arguments to %P", ptokArgv(0));
  180. }
  181. #endif
  182. while ((tch = tchGet()) != '\n') {
  183. if (tch == tchMagic) {
  184. TCH tch = tchGet();
  185. if (tch == tchEof) {
  186. PushPtok(&tokEof); /* Eek! Does this actually work? */
  187. break;
  188. }
  189. }
  190. }
  191. }
  192. /*****************************************************************************
  193. *
  194. * opChangequote - not implemented
  195. * opChangecom - not implemented
  196. * opUndivert - not implemented
  197. * opSyscmd - not implemented
  198. * opSysval - not implemented
  199. * opMaketemp - not implemented
  200. * opM4exit - not implemented
  201. * opM4wrap - not implemented
  202. *
  203. *****************************************************************************/
  204. /*****************************************************************************
  205. *
  206. * opDivert
  207. *
  208. * We currently support only two diversions:
  209. *
  210. * 0 = stdout
  211. * 1-9 = unsupported
  212. * <anything else> = /dev/null
  213. *
  214. * This is just barely enough to get DirectX building.
  215. *
  216. *****************************************************************************/
  217. DeclareOp(opDivert)
  218. {
  219. #ifdef STRICT_M4
  220. if (ctokArgv != 1) {
  221. Warn("wrong number of arguments to divert");
  222. }
  223. #endif
  224. if (ctokArgv > 0) {
  225. PTOK ptok = ptokArgv(1);
  226. if (ptok->ctch == 1 && ptok->u.ptch[0] == TEXT('0')) {
  227. g_pdivCur = g_pdivOut;
  228. } else {
  229. g_pdivCur = g_pdivNul;
  230. }
  231. }
  232. }
  233. /*****************************************************************************
  234. *
  235. * opDivnum
  236. *
  237. * We currently support only two diversions:
  238. *
  239. * 0 = stdout
  240. * 1-9 = unsupported
  241. * <anything else> = /dev/null
  242. *
  243. * This is just barely enough to get DirectX building.
  244. *
  245. *****************************************************************************/
  246. DeclareOp(opDivnum)
  247. {
  248. #ifdef STRICT_M4
  249. if (ctokArgv != 0) {
  250. Warn("wrong number of arguments to %P", ptokArgv(0));
  251. }
  252. #endif
  253. PushAt(g_pdivCur == g_pdivOut ? 0 : -1);
  254. }
  255. /*****************************************************************************
  256. *
  257. * opErrprint
  258. *
  259. * Prints its argument on the dianostic output file.
  260. * The extra ptokNil covers us in the case where $# is zero.
  261. *
  262. * QUIRK! AT&T m4 silently ignores excess arguments. GNU m4 emits
  263. * all arguments, separated by spaces. I side with AT&T on this one.
  264. *
  265. *****************************************************************************/
  266. DeclareOp(opErrprint)
  267. {
  268. #ifdef STRICT_M4
  269. if (ctokArgv != 1) {
  270. Warn("wrong number of arguments to errprint");
  271. }
  272. #endif
  273. AddPdivPtok(g_pdivErr, ptokArgv(1));
  274. FlushPdiv(g_pdivErr);
  275. }
  276. /*****************************************************************************
  277. *
  278. * opDumpdef
  279. *
  280. * With no arguments, dumps all definitions.
  281. * Otherwise, dumps only the specified macros.
  282. *
  283. * QUIRK! When given multiple arguments, AT&T m4 dumps the macros in
  284. * the order listed. GNU m4 dumps them in reverse order. (!)
  285. * I side with AT&T on this one.
  286. *
  287. *****************************************************************************/
  288. void STDCALL
  289. DumpdefPmac(PMAC pmac)
  290. {
  291. PTCH ptch, ptchMax;
  292. AddPdivPtok(g_pdivErr, &pmac->tokName);
  293. AddPdivPtok(g_pdivErr, &tokColonTab);
  294. ptch = ptchPtok(&pmac->pval->tok);
  295. ptchMax = ptchMaxPtok(&pmac->pval->tok);
  296. for ( ; ptch < ptchMax; ptch++) {
  297. AddPdivTch(g_pdivErr, *ptch); /* SOMEDAY -- internals! - do they show up okay? */
  298. }
  299. AddPdivPtok(g_pdivErr, &tokEol);
  300. }
  301. DeclareOpc(opcDumpdef)
  302. {
  303. PMAC pmac = pmacFindPtok(ptok);
  304. if (pmac) {
  305. DumpdefPmac(pmac);
  306. }
  307. }
  308. DeclareOp(opDumpdef)
  309. {
  310. if (ctokArgv == 0) {
  311. EachMacroOp(DumpdefPmac);
  312. } else {
  313. EachOpcArgvDw(opcDumpdef, argv, 0);
  314. }
  315. FlushPdiv(g_pdivErr);
  316. }
  317. /*****************************************************************************
  318. *
  319. * opInclude
  320. * opSinclude
  321. *
  322. * Pushes the contents of the file named in the argument.
  323. * Sinclude says nothing if the file is inaccessible.
  324. *
  325. * QUIRK! AT&T m4 silently ignores the case where $1 is null, but
  326. * GNU m4 issues an error (no such file or directory). I side with
  327. * GNU on this one.
  328. *
  329. * QUIRK! AT&T m4 silently ignores the case where $# is zero, but
  330. * GNU m4 will emit `$0' so as to reduce potential conflict with an
  331. * identically-spelled language keyword. I side with GNU on this one.
  332. *
  333. * QUIRK! AT&T m4 silently ignores arguments $2 onward. GNU emits
  334. * a warning but continues. I side with AT&T on this one.
  335. *
  336. *****************************************************************************/
  337. void STDCALL
  338. opIncludeF(ARGV argv, BOOL fFatal)
  339. {
  340. if (ctokArgv) {
  341. PTCH ptch = ptchDupPtok(ptokArgv(1));
  342. if (ptch) {
  343. if (hfInputPtchF(ptch, fFatal) == hfNil) {
  344. FreePv(ptch);
  345. }
  346. #ifdef STRICT_M4
  347. if (ctokArgv != 1) {
  348. Warn("excess arguments to built-in %P ignored", ptokArgv(0));
  349. }
  350. #endif
  351. }
  352. } else {
  353. PushQuotedPtok(ptokArgv(0));
  354. }
  355. }
  356. DeclareOp(opInclude)
  357. {
  358. opIncludeF(argv, 1);
  359. }
  360. DeclareOp(opSinclude)
  361. {
  362. opIncludeF(argv, 0);
  363. }