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.

213 lines
6.5 KiB

  1. /*****************************************************************************
  2. *
  3. * string.c
  4. *
  5. * String builtin macros.
  6. *
  7. *****************************************************************************/
  8. #include "m4.h"
  9. /*****************************************************************************
  10. *
  11. * opSubstr
  12. *
  13. * Return the substring of $1 starting from $2 and continuing for
  14. * $3 characters. If $3 is not supplied, then return the entire
  15. * remainder of the string.
  16. *
  17. * If $2 is out of range, then nothing is returned.
  18. *
  19. * If $3 is a negative number, then treat it as zero.
  20. *
  21. * The extra ptokNil covers us in the case where $# is 1.
  22. *
  23. *****************************************************************************/
  24. DeclareOp(opSubstr)
  25. {
  26. if (ctokArgv) {
  27. TOK tok;
  28. ITCH itch = (ITCH)atTraditionalPtok(ptokArgv(2));
  29. if (itch < ctchSPtok(ptokArgv(1))) {
  30. CTCH ctch;
  31. if (ctokArgv >= 3) {
  32. ctch = atTraditionalPtok(ptokArgv(3));
  33. if ((int)ctch < 0) {
  34. ctch = 0;
  35. }
  36. } else {
  37. ctch = ctchMax;
  38. }
  39. ctch = min(ctch, ctchSPtok(ptokArgv(1)) - itch);
  40. Assert(itch + ctch <= ctchSPtok(ptokArgv(1)));
  41. SetStaticPtokPtchCtch(&tok, ptchPtok(ptokArgv(1)) + itch, ctch);
  42. PushPtok(&tok);
  43. }
  44. } else {
  45. #ifdef STRICT_M4
  46. Warn("wrong number of arguments to %P", ptokArgv(0));
  47. #endif
  48. }
  49. }
  50. /*****************************************************************************
  51. *
  52. * opIndex
  53. *
  54. * Return the zero-based location of the first occurrence of $2 in $1,
  55. * or -1 if the substring does not appear. If there are multiple
  56. * matches, the leftmost one is returned.
  57. *
  58. * The extra ptokNil covers us in the case where $# is 1.
  59. *
  60. * QUIRK! AT&T returns -1 if $1 and $2 are both null strings.
  61. * GNU returns 0, which is what I do also.
  62. *
  63. *****************************************************************************/
  64. /* SOMEDAY! -- need minimum and maximum arg count */
  65. DeclareOp(opIndex)
  66. {
  67. if (ctokArgv) {
  68. /*
  69. * Note carefully: itch and itchMac need to be ints
  70. * because itchMac can underflow if you try to search
  71. * for a big string inside a small string.
  72. */
  73. int itch;
  74. int itchMac = ctchSPtok(ptokArgv(1)) - ctchSPtok(ptokArgv(2));
  75. for (itch = 0; itch <= itchMac; itch++) {
  76. if (fEqPtchPtchCtch(ptchPtok(ptokArgv(1)) + itch,
  77. ptchPtok(ptokArgv(2)),
  78. ctchSPtok(ptokArgv(2)))) {
  79. PushAt(itch);
  80. return;
  81. }
  82. }
  83. PushAt(-1);
  84. } else {
  85. PushQuotedPtok(ptokArgv(0));
  86. }
  87. }
  88. /*****************************************************************************
  89. *
  90. * opTranslit
  91. *
  92. * For each character in the $1, look for a match in $2. If found,
  93. * produce the corresponding character from $3. If there is no
  94. * such character, then produce nothing.
  95. *
  96. * Note that the algorithm must be as specified, in order for
  97. *
  98. * translit(abc,ab,ba)
  99. *
  100. * to result in `bac'.
  101. *
  102. * We actually walk $1 backwards so we can push directly instead
  103. * of having to build a temporary token. But the walking of $2
  104. * must be in the forward direction, so that `translit(a,aa,bc)'
  105. * results in `b' and not `c'.
  106. *
  107. * ptokNil saves us in the case where $# = 1.
  108. *
  109. * QUIRK! If given only one argument, AT&T emits $1 unchanged.
  110. * GNU emits nothing! AT&T is obviously correct, so I side
  111. * with them on this one.
  112. *
  113. *****************************************************************************/
  114. DeclareOp(opTranslit)
  115. {
  116. if (ctokArgv) {
  117. ITCH itch1 = ctchArgv(1);
  118. while ((int)--itch1 >= 0) {
  119. TCH tch = ptchArgv(1)[itch1];
  120. ITCH itch2;
  121. for (itch2 = 0; itch2 < ctchArgv(2); itch2++) {
  122. if (ptchArgv(2)[itch2] == tch) {
  123. if (itch2 < ctchArgv(3)) {
  124. PushTch(ptchArgv(3)[itch2]);
  125. }
  126. break;
  127. }
  128. }
  129. if (itch2 >= ctchArgv(2)) {
  130. PushTch(tch);
  131. }
  132. }
  133. } else {
  134. PushQuotedPtok(ptokArgv(0));
  135. }
  136. }
  137. /*****************************************************************************
  138. *
  139. * opPatsubst
  140. *
  141. * Scan $1 for any occurrences of $2. If found, replace them with $3.
  142. * If $3 is omitted, then the string is deleted.
  143. *
  144. * As a special case, if $2 is the null string, then $3 is inserted
  145. * at the beginning of the string and between each character of $1.
  146. *
  147. * NOTE! This is a GNU extension.
  148. *
  149. * NOTE! GNU supports regular expressions for $2. We support only
  150. * literal strings.
  151. *
  152. * NOTE! Scanning is required to be forwards, so we temporarily expand
  153. * into the Exp hold, then pop it off when we're done.
  154. *
  155. * QUIRK! If given only one argument, GNU emits nothing!
  156. * This is clearly wrong, so I emit $1.
  157. *
  158. *****************************************************************************/
  159. DeclareOp(opPatsubst)
  160. {
  161. if (ctokArgv) {
  162. CTCH ctchSrc = ctchArgv(1);
  163. PTCH ptchSrc = ptchArgv(1);
  164. CTCH ctchPat = ctchArgv(2); /* ptokNil saves us here */
  165. PTCH ptchPat = ptchArgv(2);
  166. TOK tok;
  167. OpenExpPtok(&tok);
  168. while (ctchSrc >= ctchPat) {
  169. if (fEqPtchPtchCtch(ptchPat, ptchSrc, ctchPat)) {
  170. if (ctokArgv >= 3) {
  171. AddExpPtok(ptokArgv(3));
  172. }
  173. if (ctchSrc == 0) {
  174. AddExpTch(*ptchSrc);
  175. ctchSrc--;
  176. ptchSrc++;
  177. } else {
  178. ctchSrc -= ctchPat;
  179. ptchSrc += ctchPat;
  180. }
  181. } else {
  182. AddExpTch(*ptchSrc);
  183. ctchSrc--;
  184. ptchSrc++;
  185. }
  186. }
  187. /* Flush out what's left of the string */
  188. while (ctchSrc) {
  189. AddExpTch(*ptchSrc);
  190. ctchSrc--;
  191. ptchSrc++;
  192. }
  193. CsopExpDopPdivPtok((DIVOP)PushZPtok, 0, &tok);
  194. } else {
  195. PushQuotedPtok(ptokArgv(0));
  196. }
  197. }