1 /*************************************************
2 * xfpt - Simple ASCII->Docbook processor *
3 *************************************************/
5 /* Copyright (c) University of Cambridge, 2010 */
6 /* Written by Philip Hazel. */
8 /* This module contains code for reading the input. */
15 /*************************************************
16 * Process macro line *
17 *************************************************/
19 /* This is the place where macro arguments are substituted. In a section
20 delimited by .eacharg/.endeach, the variable macro_argbase is set to the first
21 of the relative arguments. This function is also called from para.c in order to
22 handle inline macro calls.
25 p the macro input line
26 b where to put the result
32 read_process_macroline(uschar *p, uschar *b)
40 argstr *argbase, *arg;
42 /* If we are including an optional substring, when we get to the terminator,
52 /* Until we hit a dollar, just copy verbatim */
54 if (*p != '$') { *b++ = *p++; continue; }
56 /* If the character after $ is another $, insert a literal $. */
58 if (p[1] == '$') { p++; *b++ = *p++; continue; }
60 /* If the character after $ is +, we are dealing with arguments
61 relative to macro_arg0 in a ".eacharg" section. Otherwise, we are dealing
62 with an absolute argument number. */
67 if (macro_argbase == NULL) /* Not in a .eacharg section */
74 argbase = macro_argbase;
76 else argbase = macrocurrent->args;
78 /* $= introduces an optional substring */
85 error(17, p[1], "$=");
90 while (isdigit(*(++p))) argn = argn * 10 + *p - '0';
95 for (i = 1; i < argn; i++)
97 if (arg == NULL) break;
101 if (arg == NULL || arg->string[0] == 0)
103 while (*p != 0 && *p != optend) p++;
104 if (*p == optend) p++;
110 /* Not '=' after $; this is an argument substitution */
114 error(17, p[1], "$");
119 while (isdigit(*(++p))) argn = argn * 10 + *p - '0';
121 /* Handle $0 - currently no meaning */
128 /* Seek an argument in this invocation */
131 for (i = 1; i < argn; i++)
133 if (arg == NULL) break;
137 /* If not found, seek a default argument for an absolute substitution, but
138 not for a relative one. */
140 if (arg == NULL && argbase == macrocurrent->args)
142 arg = macrocurrent->macro->args;
143 for (i = 1; i < argn; i++)
145 if (arg == NULL) break;
150 /* If we have found an argument, substitute it. */
152 if (arg != NULL) b += sprintf(CS b, "%s", arg->string);
160 /*************************************************
161 * Get the next line of input *
162 *************************************************/
164 /* There may be a saved line already in the buffer, following the reading of a
165 paragraph or a .nonl directive. Otherwise, take the next line from one of three
168 (1) If popto is not negative, get an appropropriate line off the stack.
169 (2) If we are in a macro, get the next macro line.
170 (3) If we are in a file, read a new line from a file and handle any
173 There can be arbitrary nesting of macros and files, because a .include
174 directive may appear inside a macro. The current from_type vector is used to
175 keep track of what is current.
178 Returns: pointer to the next line or NULL
187 /* Handle a dot line that terminated a paragraph, or a .nonl line */
189 if (next_line != NULL)
191 uschar *yield = next_line;
196 /* Handle a line off the stack */
200 pushstr *ps = pushed;
201 if (ps == NULL) error(12); else
204 (void)sprintf(CS inbuffer, "%s\n", ps->string);
211 /* Handle a line off the stack when there is a matching line at the top or
212 below for the given letter. When we reach the matching line, stop popping. The
213 value of popto is set greater than zero only when it is known that there's a
218 pushstr *ps = pushed;
219 if (ps->letter == popto) popto = -1;
220 (void)sprintf(CS inbuffer, "%s\n", ps->string);
226 /* Get the next line from the current macro or the current file. We need a loop
227 for handling the ends of macros and files. First check for having previously
228 reached the end of the input. */
230 if (from_type_ptr < 0) return NULL;
234 if (from_type[from_type_ptr] == FROM_MACRO)
236 if (macrocurrent->nextline == NULL)
238 macroexe *temp = macrocurrent;
239 macrocurrent = macrocurrent->prev;
244 read_process_macroline(macrocurrent->nextline->string, inbuffer);
245 macrocurrent->nextline = macrocurrent->nextline->next;
250 /* When reading from a file, handle continuation lines, but only within the
255 if (Ufgets(inbuffer, INBUFFSIZE, istack->file) == NULL)
257 istackstr *prev = istack->prev;
258 fclose(istack->file);
264 istack->linenumber++;
272 while (p > q && isspace(p[-1])) p--;
274 if (p - q < 3 || Ustrncmp(p - 3, "&&&", 3) != 0) break;
279 if (istack == NULL ||
280 Ufgets(q, INBUFFSIZE - (q - inbuffer), istack->file) == NULL)
283 istack->linenumber++;
285 while (*p == ' ' || *p == '\t') p++;
287 if (p > q) memmove(q, p, len + 1);
294 /* We get here if the end of a macro or a file was reached. The appropriate
295 chain has been popped. Back up the stack of input types before the loop
296 repeats. When we reach the end of the stack, we have reached the end of all
299 if (--from_type_ptr < 0) return NULL;
307 /*************************************************
308 * Complete the reading of a paragraph *
309 *************************************************/
311 /* This function is called after a line has been identified as the start of a
312 paragraph. We need to read the rest so that flags can be matched across the
313 entire paragraph. (If there is nested material such as a footnote, this applies
314 only to the separate parts, not across the nesting.) The text is copied into
315 the paragraph buffer. Directives that are encountered in the paragraph are
316 processed, with two exceptions.
318 (1) For .literal, we set next_line so it is processed next, and exit. This is
319 the end of the paragraph.
321 (2) For .nest, we set *nest_info, according to whether it is the start or
322 end of a nested section, and exit.
326 nest_info returns NEST_NO, NEST_START, or NEST_END
328 Returns: the paragraph
333 read_paragraph(uschar *p, int *nest_info)
335 uschar *q = parabuffer;
336 int length = Ustrlen(p);
338 memcpy(q, p, length);
341 *nest_info = NEST_NO; /* Not hit .nest */
347 if ((p = read_nextline()) == NULL) break;
349 if (Ustrncmp(p, ".literal ", 9) == 0)
355 if (Ustrncmp(p, ".nest ", 6) == 0)
358 while (isspace(*p)) p++;
360 while (s > p && isspace(s[-1])) s--;
362 if (Ustrcmp(p, "begin") == 0) *nest_info = NEST_BEGIN;
363 else if (Ustrcmp(p, "end") == 0) *nest_info = NEST_END;
374 /* End paragraph on encountering a completely blank line */
376 for (s = p; *s == ' ' || *s == '\t'; s++);
377 if (*s == '\n') break;
380 memcpy(q, p, length);