1 /* Copyright 2010-2019 Free Software Foundation, Inc.
2 
3    This program is free software: you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation, either version 3 of the License, or
6    (at your option) any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
15 
16 #include <config.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <string.h>
21 
22 #include "parser.h"
23 #include "text.h"
24 #include "convert.h"
25 
26 
27 static void expand_cmd_args_to_texi (ELEMENT *e, TEXT *result);
28 static void convert_to_texinfo_internal (ELEMENT *e, TEXT *result);
29 
30 
31 #define ADD(x) text_append (result, x)
32 
33 /* Return value to be freed by caller. */
34 char *
node_extra_to_texi(NODE_SPEC_EXTRA * nse)35 node_extra_to_texi (NODE_SPEC_EXTRA *nse)
36 {
37   TEXT result;
38 
39   if (!nse)
40     return "";
41   text_init (&result);
42 
43   if (nse->manual_content
44       && nse->manual_content->contents.number > 0)
45     {
46       text_append_n (&result, "(", 1);
47       convert_to_texinfo_internal (nse->manual_content, &result);
48       text_append_n (&result, ")", 1);
49     }
50   if (nse->node_content
51       && nse->node_content->contents.number > 0)
52     {
53       convert_to_texinfo_internal (nse->node_content, &result);
54     }
55   return result.text;
56 }
57 
58 static void
expand_cmd_args_to_texi(ELEMENT * e,TEXT * result)59 expand_cmd_args_to_texi (ELEMENT *e, TEXT *result)
60 {
61   enum command_id cmd = e->cmd;
62   KEY_PAIR *k;
63 
64   if (cmd)
65     {
66       ADD("@");  ADD(command_name(cmd));
67     }
68 
69   // TODO extra spaces
70   k = lookup_extra (e, "spaces_before_argument");
71   if (k)
72     ADD((char *)k->value);
73 
74   // TODO multitable or block command
75 
76   if (cmd == CM_macro || cmd == CM_rmacro)
77     {
78       KEY_PAIR *k;
79       char *s = 0;
80       k = lookup_extra (e, "arg_line");
81       if (k)
82         s = (char *)k->value;
83       if (s)
84         {
85           ADD(s);
86           return;
87         }
88     }
89 
90   // TODO node
91 
92   if (e->args.number > 0)
93     {
94       int braces, arg_nr, i;
95       braces = (e->args.list[0]->type == ET_brace_command_arg
96                 || e->args.list[0]->type == ET_brace_command_context);
97       if (braces)
98         ADD("{");
99 
100       if (e->cmd == CM_verb)
101         {
102           k = lookup_extra (e, "delimiter");
103           ADD((char *)k->value);
104         }
105 
106       arg_nr = 0;
107       for (i = 0; i < e->args.number; i++)
108         {
109           if (command_data(cmd).flags & CF_brace)
110             {
111               if (arg_nr)
112                 ADD(",");
113               arg_nr++;
114             }
115           k = lookup_extra (e->args.list[i], "spaces_before_argument");
116           if (k)
117             ADD((char *)k->value);
118           convert_to_texinfo_internal (e->args.list[i], result);
119           k = lookup_extra (e->args.list[i], "spaces_after_argument");
120           if (k)
121             ADD((char *)k->value);
122         }
123 
124       if (e->cmd == CM_verb)
125         {
126           k = lookup_extra (e, "delimiter");
127           ADD((char *)k->value);
128         }
129 
130       if (braces)
131         ADD("}");
132     }
133 }
134 
135 static void
convert_to_texinfo_internal(ELEMENT * e,TEXT * result)136 convert_to_texinfo_internal (ELEMENT *e, TEXT *result)
137 {
138   if (e->text.end > 0)
139     ADD(e->text.text);
140   else
141     {
142       if (e->cmd
143           || e->type == ET_def_line
144           || e->type == ET_menu_entry
145           || e->type == ET_menu_comment)
146         {
147           expand_cmd_args_to_texi (e, result);
148         }
149 
150       if (e->type == ET_bracketed
151           || e->type == ET_bracketed_def_content)
152         {
153           KEY_PAIR *k;
154           ADD("{");
155           k = lookup_extra (e, "spaces_before_argument");
156           if (k)
157             ADD((char *)k->value);
158         }
159       if (e->contents.number > 0)
160         {
161           int i;
162           for (i = 0; i < e->contents.number; i++)
163             convert_to_texinfo_internal (e->contents.list[i], result);
164         }
165       if (e->type == ET_bracketed)
166         ADD("}");
167 
168       // TODO: raw block command
169       if (command_flags (e) & CF_block)
170         {
171           ADD("@end ");
172           ADD(command_name(e->cmd));
173           if (command_data(e->cmd).data != BLOCK_raw)
174             ADD("\n");
175         }
176     }
177 
178   return;
179 }
180 #undef ADD
181 
182 /* Return value to be freed by caller. */
183 char *
convert_to_texinfo(ELEMENT * e)184 convert_to_texinfo (ELEMENT *e)
185 {
186   TEXT result;
187 
188   if (!e)
189     return strdup ("");
190   text_init (&result);
191   convert_to_texinfo_internal (e, &result);
192   return result.text;
193 }
194 
195 /* Very stripped-down version of Texinfo::Convert::Text.
196    Convert the contents of E to plain text.  Suitable for specifying a file
197    name containing an at sign or braces.  Set *SUPERFLUOUS_ARG if the contents
198    of E are too complicated to convert properly. */
199 char *
convert_to_text(ELEMENT * e,int * superfluous_arg)200 convert_to_text (ELEMENT *e, int *superfluous_arg)
201 {
202 #define ADD(x) text_append (&result, x)
203 
204   TEXT result; int i;
205 
206   if (!e)
207     return "";
208   text_init (&result);
209   for (i = 0; i < e->contents.number; i++)
210     {
211       ELEMENT *e1 = contents_child_by_index (e, i);
212       if (e1->text.end > 0)
213         ADD(e1->text.text);
214       else if (e1->cmd == CM_AT_SIGN
215                || e1->cmd == CM_atchar)
216         ADD("@");
217       else if (e1->cmd == CM_OPEN_BRACE
218                || e1->cmd == CM_lbracechar)
219         ADD("{");
220       else if (e1->cmd == CM_CLOSE_BRACE
221                || e1->cmd == CM_rbracechar)
222         ADD("}");
223       else
224         *superfluous_arg = 1;
225     }
226   return result.text;
227 }
228 #undef ADD
229 
230