Add '3rd-party/xfpt/' from commit '24eaa721effcf2f56d1da62344ee27ac9721d3ec'
[exim.git] / 3rd-party / xfpt / src / xfpt.c
1 /*************************************************
2 *     xfpt - Simple ASCII->Docbook processor     *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge, 2012 */
6 /* Written by Philip Hazel. */
7
8 /* This module contains the main program and initialization functions. */
9
10 #include "xfpt.h"
11
12
13
14 /*************************************************
15 *                 Static variables               *
16 *************************************************/
17
18 static uschar *xfpt_filename = NULL;
19 static uschar *out_filename = NULL;
20
21
22
23
24 /*************************************************
25 *                  Usage                         *
26 *************************************************/
27
28 static void
29 usage(void)
30 {
31 (void)fprintf(stderr,
32   "Usage: xfpt [-help]\n"
33   "            [-o <output-file>]\n"
34   "            [-S <share-directory>]\n"
35   "            [-v]\n"
36   "            [input-file]\n");
37 }
38
39
40
41
42 /*************************************************
43 *          Command line argument decoding        *
44 *************************************************/
45
46 /* Arguments: as for main()
47    Returns:   TRUE if OK
48 */
49
50 static BOOL
51 xfpt_decode_arg(int argc, char **argv)
52 {
53 int i;
54 for (i = 1; i < argc; i++)
55   {
56   uschar *arg = US argv[i];
57   if (*arg != '-') break;
58   if (Ustrcmp(arg, "-o") == 0)
59     {
60     out_filename = US argv[++i];
61     if (out_filename == NULL) { usage(); return FALSE; }
62     }
63   else if (Ustrcmp(arg, "-S") == 0)
64     {
65     xfpt_share = US argv[++i];
66     if (xfpt_share == NULL) { usage(); return FALSE; }
67     }
68   else if (Ustrcmp(arg, "-help") == 0 || Ustrcmp(arg, "--help") == 0)
69     {
70     usage();
71     return FALSE;
72     }
73   else if (Ustrcmp(arg, "-v") == 0)
74     {
75     (void)fprintf(stdout, "xpft version %s\n", xfpt_version);
76     exit(0);
77     }
78   else
79     {
80     (void)fprintf(stderr, "xfpt: unknown option \"%s\"\n", arg);
81     usage();
82     return FALSE;
83     }
84   }
85
86 /* Require there to be either 0 or 1 command line argument left. */
87
88 if (argc > i + 1)
89   {
90   usage();
91   return FALSE;
92   }
93
94 /* This will set NULL if there is no file name. If there is a file name and no
95 output file is specified, default it to the input name with a .xml extension. */
96
97 xfpt_filename = US argv[i];
98 if (xfpt_filename != NULL && out_filename == NULL)
99   {
100   uschar *p;
101   int len = Ustrlen(xfpt_filename);
102   out_filename = misc_malloc(len + 5);
103   Ustrcpy(out_filename, xfpt_filename);
104   if ((p = Ustrrchr(out_filename, '.')) != NULL) len = p - out_filename;
105   Ustrcpy(out_filename + len, ".xml");
106   }
107
108 return TRUE;
109 }
110
111
112
113 /*************************************************
114 *          Entry point and main program          *
115 *************************************************/
116
117 int
118 main(int argc, char **argv)
119 {
120 BOOL para_unfinished[MAXNEST+1];
121 int warnpop = 0;
122 uschar *p, *q;
123
124 if (!xfpt_decode_arg(argc, argv)) return EXIT_FAILURE;
125
126 inbuffer = misc_malloc(INBUFFSIZE);
127 parabuffer = misc_malloc(PARABUFFSIZE);
128
129 /* Set up the first file */
130
131 istackbase = istack = misc_malloc(sizeof(istackstr));
132 istack->prev = NULL;
133 istack->linenumber = 0;
134
135 from_type_ptr = 0;
136 from_type[from_type_ptr] = FROM_FILE;
137
138 if (xfpt_filename == NULL)
139   {
140   istack->file = stdin;
141   Ustrcpy(istack->filename, US"(stdin)");
142   }
143 else
144   {
145   Ustrcpy(istack->filename, xfpt_filename);
146   istack->file = Ufopen(xfpt_filename, "rb");
147   if (istack->file == NULL)
148     error(0, istack->filename, strerror(errno));    /* Hard */
149   }
150
151 /* Set up the output file. */
152
153 if (out_filename == NULL || Ustrcmp(out_filename, "-") == 0)
154   {
155   outfile = stdout;
156   }
157 else
158   {
159   outfile = Ufopen(out_filename, "wb");
160   if (outfile == NULL)
161     error(0, out_filename, strerror(errno));   /* Hard error */
162   }
163
164 /* Process the input */
165
166 nest_level = 0;
167 para_unfinished[0] = FALSE;
168
169 while ((p = read_nextline()) != NULL)
170   {
171   if (*p == '.') dot_process(p); else switch (literal_state)
172     {
173     case LITERAL_LAYOUT:
174     para_process(p);
175     break;
176
177     case LITERAL_TEXT:
178     literal_process(p);
179     break;
180
181     case LITERAL_XML:
182     (void)fprintf(outfile, "%s", CS p);
183     break;
184
185     default:
186     case LITERAL_OFF:
187     q = p;
188     while (isspace(*q)) q++;
189     if (*q != 0)
190       {
191       int nest_info;
192       p = read_paragraph(p, &nest_info);
193       if (!para_unfinished[nest_level])
194         {
195         (void)fprintf(outfile, "<");
196         para_process(US"para&xfpt.rev;");
197         (void)fprintf(outfile, ">\n");
198         }
199
200       para_process(p);
201       if (nest_info == NEST_BEGIN)
202         {
203         if (nest_level >= MAXNEST) error(27); else
204           {
205           nest_literal_stack[nest_level] = literal_state;
206           para_unfinished[nest_level++] = TRUE;
207           }
208         }
209       else (void)fprintf(outfile, "</para>\n");
210
211       para_unfinished[nest_level] = FALSE;
212
213       if (nest_info == NEST_END)
214         {
215         if (nest_level <= 0) error(28);
216           else literal_state = nest_literal_stack[--nest_level];
217         }
218       }
219     break;
220     }
221   }
222
223 /* Empty the stack of pushed texts, close the output, and we are done. */
224
225 while (pushed != NULL)
226   {
227   if (!suppress_warnings)
228     {
229     if (pushed->check != 0)
230       {
231       if (warnpop++ == 0)
232         fprintf(stderr,
233            "** Warning: one or more items were left unclosed at the end of processing.\n"
234            "   The numbers are the lines in the original file %s from where\n"
235            "   the items were generated:\n",
236            ((xfpt_filename == NULL)? "(stdin)" : (char *)xfpt_filename));
237       if (pushed->macname == NULL)
238         fprintf(stderr, "%d: %s\n", pushed->check, pushed->string);
239       else
240         fprintf(stderr, "%d: .%s\n", pushed->check, pushed->macname);
241
242       if (warnpop > 10)
243         {
244         fprintf(stderr, "... too many to list\n");
245         suppress_warnings = TRUE;
246         }
247       }
248     }
249   para_process(pushed->string);
250   (void)fprintf(outfile, "\n");
251   pushed = pushed->next;
252   }
253
254 (void)fclose(outfile);
255
256 return return_code;
257 }
258
259 /* End of xfpt.c */