1 /*
2  * ========================================================================
3  * Copyright 2006-2007 University of Washington
4  * Copyright 2013-2021 Eduardo Chappa
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * ========================================================================
13  */
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ctype.h>
19 
20 
21 typedef struct helplist {
22     char            *name;
23     struct helplist *next;
24 } HELPLIST_S;
25 
26 
27 HELPLIST_S *help_list;
28 
29 
30 void  preamble(FILE *ofp);
31 void  body(FILE *ifp, FILE *ofp);
32 char *quote_clean(char *rawline);
33 int   only_tags(char *line);
34 int   append_to_help_list(HELPLIST_S **, char *new);
35 void  print_help_list(HELPLIST_S *, FILE *fp);
36 
37 
38 int
main(int argc,char ** argv)39 main(int argc, char **argv)
40 {
41     preamble(stdout);
42     body(stdin, stdout);
43     exit(0);
44 }
45 
46 
47 void
preamble(FILE * ofp)48 preamble(FILE *ofp)
49 {
50     fprintf(ofp, "\n\t\t/*\n");
51     fprintf(ofp, "\t\t * AUTOMATICALLY GENERATED FILE!\n");
52     fprintf(ofp, "\t\t * DO NOT EDIT!!\n");
53     fprintf(ofp, "\t\t * See help_c_gen.c.\n\t\t */\n\n\n");
54     fprintf(ofp, "#include <stdio.h>\n#include \"headers.h\"\n#include \"helptext.h\"\n\n");
55 }
56 
57 
58 void
body(FILE * ifp,FILE * ofp)59 body(FILE *ifp, FILE *ofp)
60 {
61     char  rawline[10000];
62     char *line;
63 #define SPACE ' '
64     char *p, *helpname;
65     int   in_text = 0, new_topic = 0, first_one = 1, justtags;
66 
67     while(fgets(rawline, sizeof(rawline), ifp) != NULL){
68 	if(rawline[0] == '#')
69 	  continue;
70 
71 	line = quote_clean(rawline);
72 
73 	if(!line){
74 	    /*
75 	     * Put errors in result so that it will cause a compile
76 	     * error and be noticed.
77 	     */
78 	    fprintf(ofp, "Error: quote_clean returns NULL for help line\n  %s\n", rawline);
79 	    exit(-1);
80 	}
81 
82 	justtags = 0;
83 	if(!strncmp(line, "====", 4)){
84 	    p = line;
85 	    /* skip to first space */
86 	    while(*p && *p != SPACE)
87 	      p++;
88 
89 	    if(!*p){
90 		fprintf(ofp, "Error: help input line\n  %s\n No space after ====\n", rawline);
91 		exit(-1);
92 	    }
93 
94 	    /* skip spaces */
95 	    while(*p && *p == SPACE)
96 	      p++;
97 
98 	    if(!*p){
99 		fprintf(ofp, "Error: help input line\n  %s\n Missing helpname after ====\n", rawline);
100 		exit(-1);
101 	    }
102 
103 	    helpname = p;
104 
105 	    /* skip to next space */
106 	    while(*p && *p != SPACE)
107 	      p++;
108 
109 	    *p = '\0';		/* tie off helpname */
110 
111 	    /* finish previous one */
112 	    if(in_text)
113 	      fprintf(ofp, "NULL\n};\n\n\n");
114 
115 	    in_text = new_topic = 1;
116 
117 	    fprintf(ofp, "char *%s[] = {\n", helpname);
118 
119 	    if(append_to_help_list(&help_list, helpname) < 0){
120 		fprintf(ofp, "Error: Can't allocate memory for help_list after line\n  %s\n", rawline);
121 		exit(-1);
122 	    }
123 	}
124 	else if(line[0] == '\0'){
125 	    if(in_text)
126 	      fprintf(ofp, "\" \",\n");		/* why the space? */
127 	}
128 	else if(only_tags(line)){
129 	    if(in_text){
130 		fprintf(ofp, "\"%s\",\n", line);
131 		justtags = 1;
132 	    }
133 	}
134 
135 	if(line[0] && line[0] != '='){
136 	    if(in_text && !justtags){
137 		if(first_one){
138 		    first_one = 0;
139 		    fprintf(ofp, "/*\n");
140 		    fprintf(ofp, "TRANSLATORS: The translation strings for pith/helptext.c\n");
141 		    fprintf(ofp, "are automatically generated by a script from the help\n");
142 		    fprintf(ofp, "text in pith/pine.hlp. This means that the translation job for\n");
143 		    fprintf(ofp, "the help text is particularly difficult.\n");
144 		    fprintf(ofp, "This is HTML source so please leave the text inside HTML tags untranslated.\n");
145 		    fprintf(ofp, "HTML tags like <LI> or <TITLE> should, of course, be left untranslated.\n");
146 		    fprintf(ofp, "Special HTML characters like &lt; (less than character) should be left alone.\n");
147 		    fprintf(ofp, "Alpine option names are short phrases with the words separated by\n");
148 		    fprintf(ofp, "dashes. An example of an option name is Quell-Extra-Post-Prompt.\n");
149 		    fprintf(ofp, "Option names should not be translated.\n");
150 		    fprintf(ofp, "The file pith/helptext.c contains many separate help topics.\n");
151 		    fprintf(ofp, "Some of them are very short and some are long. If left unsorted the\n");
152 		    fprintf(ofp, "text for a single topic is together in the translation file. The start\n");
153 		    fprintf(ofp, "of each new topic is marked by the comment\n");
154 		    fprintf(ofp, "TRANSLATORS: Start of new help topic.\n");
155 		    fprintf(ofp, "*/\n");
156 		}
157 		else if(new_topic){
158 		    new_topic = 0;
159 		    fprintf(ofp, "/* TRANSLATORS: Start of new help topic. */\n");
160 		}
161 
162 		fprintf(ofp, "N_(\"%s\"),\n", line);
163 	    }
164 	    else{
165 		; /* skip leading cruft */
166 	    }
167 	}
168     }
169 
170     if(in_text)
171       fprintf(ofp, "NULL\n};\n\n\n");
172 
173     print_help_list(help_list, ofp);
174 }
175 
176 
177 char *
quote_clean(char * rawline)178 quote_clean(char *rawline)
179 {
180     char *p, *q, *cleaned = NULL;
181     size_t len;
182 
183     if(rawline){
184 	len = strlen(rawline);
185 	cleaned = (char *) malloc((2*len+1) * sizeof(char));
186 
187 	if(cleaned){
188 	    p = rawline;
189 	    q = cleaned;
190 
191 	    while(*p && *p != '\n'){
192 		if(*p == '"' && !(p > rawline && *(p-1) == '\\'))
193 		  *q++ = '\\';
194 
195 		*q++ = *p++;
196 	    }
197 
198 	    *q = '\0';
199 	}
200     }
201 
202     return cleaned;
203 }
204 
205 
206 int
only_tags(char * line)207 only_tags(char *line)
208 {
209     char *p;
210     int   is_tags = 1;	/* only tags seen so far */
211 
212     if(!line)
213       return 0;
214 
215     p = line;
216 
217     while(is_tags && *p){
218 	/* leading space before a tag */
219 	while(*p && isspace(*p))
220 	  p++;
221 
222 	if(*p == '<'){
223 	    p++;
224 	    /* skip through interior of tag */
225 	    while(*p && *p != '<' && *p != '>')
226 	      p++;
227 
228 	    if(*p == '>'){
229 		p++;
230 		/* trailing space after tag */
231 		while(*p && isspace(*p))
232 		  p++;
233 	    }
234 	    else
235 	      is_tags = 0;
236 	}
237 	else if(*p)
238 	  is_tags = 0;
239     }
240 
241     return is_tags;
242 }
243 
244 
245 int
append_to_help_list(HELPLIST_S ** head,char * name)246 append_to_help_list(HELPLIST_S **head, char *name)
247 {
248     HELPLIST_S *new, *h;
249     size_t len;
250 
251     if(!(name && *name && head))
252       return 0;
253 
254     new = (HELPLIST_S *) malloc(sizeof(*new));
255     if(!new)
256       return -1;
257 
258     memset(new, 0, sizeof(*new));
259     len = strlen(name);
260     new->name = (char *) malloc((len+1) * sizeof(char));
261     strncpy(new->name, name, len);
262     new->name[len] = '\0';
263 
264     if(*head){
265 	for(h = *head; h->next; h = h->next)
266 	  ;
267 
268 	h->next = new;
269     }
270     else
271       *head = new;
272 
273     return 0;
274 }
275 
276 
277 void
print_help_list(HELPLIST_S * head,FILE * fp)278 print_help_list(HELPLIST_S *head, FILE *fp)
279 {
280     HELPLIST_S *h;
281 
282     if(head){
283 	fprintf(fp, "struct help_texts h_texts[] = {\n");
284 
285 	for(h = head; h; h = h->next)
286 	  if(h->name && h->name[0])
287 	    fprintf(fp, "{%s,\"%s\"},\n", h->name, h->name);
288 
289 	fprintf(fp, "{NO_HELP, NULL}\n};\n");
290     }
291 }
292