- /* Read the actual macro arguments and store pointers to these arguments
- * into the array of actual arguments in the macro definition.
- */
- ArgCount = 0;
- ParCount = 0;
- ArgStart = Buf;
- B = Buf;
- while (1) {
- C = *lptr;
- if (C == '(') {
- *B++ = gch ();
- ++ParCount;
- } else if (IsQuoteChar(C)) {
- B = CopyQuotedString (C, B);
- } else if (C == ',' || C == ')') {
- if (ParCount == 0) {
- /* End of actual argument */
- gch ();
- *B++ = '\0';
- while (IsBlank(*ArgStart)) {
- ++ArgStart;
- }
- if (ArgCount < M->ArgCount) {
- M->ActualArgs[ArgCount++] = ArgStart;
- } else if (C != ')' || *ArgStart != '\0' || M->ArgCount > 0) {
- /* Be sure not to count the single empty argument for a
- * macro that does not have arguments.
- */
- ++ArgCount;
- }
-
- /* Start the next one */
- ArgStart = B;
- if (C == ')') {
- break;
- }
- } else {
- *B++ = gch ();
- if (C == ')') {
- --ParCount;
- }
- }
- } else if (IsBlank (C)) {
- /* Squeeze runs of blanks */
- *B++ = ' ';
- skipblank ();
- } else if (C == '\0') {
- /* End of line inside macro argument list - read next line */
- if (NextLine () == 0) {
- return 0;
- }
+ /* Argument handling loop */
+ while (CurC != '\0') {
+
+ /* If we have an identifier, check if it's a macro */
+ if (IsSym (Ident)) {
+
+ /* Check if it's a macro argument */
+ if ((ArgIdx = FindMacroArg (E->M, Ident)) >= 0) {
+
+ /* A macro argument. Get the corresponding actual argument. */
+ Arg = ME_GetActual (E, ArgIdx);
+
+ /* Copy any following whitespace */
+ HaveSpace = SkipWhitespace (0);
+
+ /* If a ## operator follows, we have to insert the actual
+ * argument as is, otherwise it must be macro replaced.
+ */
+ if (CurC == '#' && NextC == '#') {
+
+ /* ### Add placemarker if necessary */
+ SB_Append (&E->Replacement, Arg);
+
+ } else {
+
+ /* Replace the formal argument by a macro replaced copy
+ * of the actual.
+ */
+ SB_Reset (Arg);
+ MacroReplacement (Arg, &E->Replacement);
+
+ /* If we skipped whitespace before, re-add it now */
+ if (HaveSpace) {
+ SB_AppendChar (&E->Replacement, ' ');
+ }
+ }
+
+
+ } else {
+
+ /* An identifier, keep it */
+ SB_AppendStr (&E->Replacement, Ident);
+
+ }
+
+ } else if (CurC == '#' && NextC == '#') {
+
+ /* ## operator. */
+ NextChar ();
+ NextChar ();
+ SkipWhitespace (0);
+
+ /* Since we need to concatenate the token sequences, remove
+ * any whitespace that was added to target, since it must come
+ * from the input.
+ */
+ while (IsSpace (SB_LookAtLast (&E->Replacement))) {
+ SB_Drop (&E->Replacement, 1);
+ }
+
+ /* If the next token is an identifier which is a macro argument,
+ * replace it, otherwise do nothing.
+ */
+ if (IsSym (Ident)) {
+
+ /* Check if it's a macro argument */
+ if ((ArgIdx = FindMacroArg (E->M, Ident)) >= 0) {
+
+ /* Get the corresponding actual argument and add it. */
+ SB_Append (&E->Replacement, ME_GetActual (E, ArgIdx));
+
+ } else {
+
+ /* Just an ordinary identifier - add as is */
+ SB_AppendStr (&E->Replacement, Ident);
+
+ }
+ }
+
+ } else if (CurC == '#' && E->M->ArgCount >= 0) {
+
+ /* A # operator within a macro expansion of a function like
+ * macro. Read the following identifier and check if it's a
+ * macro parameter.
+ */
+ NextChar ();
+ SkipWhitespace (0);
+ if (!IsSym (Ident) || (ArgIdx = FindMacroArg (E->M, Ident)) < 0) {
+ PPError ("`#' is not followed by a macro parameter");
+ } else {
+ /* Make a valid string from Replacement */
+ Arg = ME_GetActual (E, ArgIdx);
+ SB_Reset (Arg);
+ Stringize (Arg, &E->Replacement);
+ }
+
+ } else if (IsQuote (CurC)) {
+ CopyQuotedString (&E->Replacement);