1 /*
2  * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005
3  *
4  * Released under the terms of the GNU GPL v2.0
5  */
6 
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #include "lkc.h"
11 
escape(const char * text,char * bf,int len)12 static char *escape(const char* text, char *bf, int len)
13 {
14 	char *bfp = bf;
15 	int multiline = strchr(text, '\n') != NULL;
16 	int eol = 0;
17 	int textlen = strlen(text);
18 
19 	if ((textlen > 0) && (text[textlen-1] == '\n'))
20 		eol = 1;
21 
22 	*bfp++ = '"';
23 	--len;
24 
25 	if (multiline) {
26 		*bfp++ = '"';
27 		*bfp++ = '\n';
28 		*bfp++ = '"';
29 		len -= 3;
30 	}
31 
32 	while (*text != '\0' && len > 1) {
33 		if (*text == '"')
34 			*bfp++ = '\\';
35 		else if (*text == '\n') {
36 			*bfp++ = '\\';
37 			*bfp++ = 'n';
38 			*bfp++ = '"';
39 			*bfp++ = '\n';
40 			*bfp++ = '"';
41 			len -= 5;
42 			++text;
43 			goto next;
44 		}
45 		else if (*text == '\\') {
46 			*bfp++ = '\\';
47 			len--;
48 		}
49 		*bfp++ = *text++;
50 next:
51 		--len;
52 	}
53 
54 	if (multiline && eol)
55 		bfp -= 3;
56 
57 	*bfp++ = '"';
58 	*bfp = '\0';
59 
60 	return bf;
61 }
62 
63 struct file_line {
64 	struct file_line *next;
65 	const char *file;
66 	int lineno;
67 };
68 
file_line__new(const char * file,int lineno)69 static struct file_line *file_line__new(const char *file, int lineno)
70 {
71 	struct file_line *self = malloc(sizeof(*self));
72 
73 	if (self == NULL)
74 		goto out;
75 
76 	self->file   = file;
77 	self->lineno = lineno;
78 	self->next   = NULL;
79 out:
80 	return self;
81 }
82 
83 struct message {
84 	const char	 *msg;
85 	const char	 *option;
86 	struct message	 *next;
87 	struct file_line *files;
88 };
89 
90 static struct message *message__list;
91 
message__new(const char * msg,char * option,const char * file,int lineno)92 static struct message *message__new(const char *msg, char *option,
93 				    const char *file, int lineno)
94 {
95 	struct message *self = malloc(sizeof(*self));
96 
97 	if (self == NULL)
98 		goto out;
99 
100 	self->files = file_line__new(file, lineno);
101 	if (self->files == NULL)
102 		goto out_fail;
103 
104 	self->msg = strdup(msg);
105 	if (self->msg == NULL)
106 		goto out_fail_msg;
107 
108 	self->option = option;
109 	self->next = NULL;
110 out:
111 	return self;
112 out_fail_msg:
113 	free(self->files);
114 out_fail:
115 	free(self);
116 	self = NULL;
117 	goto out;
118 }
119 
mesage__find(const char * msg)120 static struct message *mesage__find(const char *msg)
121 {
122 	struct message *m = message__list;
123 
124 	while (m != NULL) {
125 		if (strcmp(m->msg, msg) == 0)
126 			break;
127 		m = m->next;
128 	}
129 
130 	return m;
131 }
132 
message__add_file_line(struct message * self,const char * file,int lineno)133 static int message__add_file_line(struct message *self, const char *file,
134 				  int lineno)
135 {
136 	int rc = -1;
137 	struct file_line *fl = file_line__new(file, lineno);
138 
139 	if (fl == NULL)
140 		goto out;
141 
142 	fl->next    = self->files;
143 	self->files = fl;
144 	rc = 0;
145 out:
146 	return rc;
147 }
148 
message__add(const char * msg,char * option,const char * file,int lineno)149 static int message__add(const char *msg, char *option, const char *file,
150 			int lineno)
151 {
152 	int rc = 0;
153 	char bf[16384];
154 	char *escaped = escape(msg, bf, sizeof(bf));
155 	struct message *m = mesage__find(escaped);
156 
157 	if (m != NULL)
158 		rc = message__add_file_line(m, file, lineno);
159 	else {
160 		m = message__new(escaped, option, file, lineno);
161 
162 		if (m != NULL) {
163 			m->next	      = message__list;
164 			message__list = m;
165 		} else
166 			rc = -1;
167 	}
168 	return rc;
169 }
170 
menu_build_message_list(struct menu * menu)171 static void menu_build_message_list(struct menu *menu)
172 {
173 	struct menu *child;
174 
175 	message__add(menu_get_prompt(menu), NULL,
176 		     menu->file == NULL ? "Root Menu" : menu->file->name,
177 		     menu->lineno);
178 
179 	if (menu->sym != NULL && menu_has_help(menu))
180 		message__add(menu_get_help(menu), menu->sym->name,
181 			     menu->file == NULL ? "Root Menu" : menu->file->name,
182 			     menu->lineno);
183 
184 	for (child = menu->list; child != NULL; child = child->next)
185 		if (child->prompt != NULL)
186 			menu_build_message_list(child);
187 }
188 
message__print_file_lineno(struct message * self)189 static void message__print_file_lineno(struct message *self)
190 {
191 	struct file_line *fl = self->files;
192 
193 	putchar('\n');
194 	if (self->option != NULL)
195 		printf("# %s:00000\n", self->option);
196 
197 	printf("#: %s:%d", fl->file, fl->lineno);
198 	fl = fl->next;
199 
200 	while (fl != NULL) {
201 		printf(", %s:%d", fl->file, fl->lineno);
202 		fl = fl->next;
203 	}
204 
205 	putchar('\n');
206 }
207 
message__print_gettext_msgid_msgstr(struct message * self)208 static void message__print_gettext_msgid_msgstr(struct message *self)
209 {
210 	message__print_file_lineno(self);
211 
212 	printf("msgid %s\n"
213 	       "msgstr \"\"\n", self->msg);
214 }
215 
menu__xgettext(void)216 static void menu__xgettext(void)
217 {
218 	struct message *m = message__list;
219 
220 	while (m != NULL) {
221 		/* skip empty lines ("") */
222 		if (strlen(m->msg) > sizeof("\"\""))
223 			message__print_gettext_msgid_msgstr(m);
224 		m = m->next;
225 	}
226 }
227 
main(int ac,char ** av)228 int main(int ac, char **av)
229 {
230 	conf_parse(av[1]);
231 
232 	menu_build_message_list(menu_get_root_menu(NULL));
233 	menu__xgettext();
234 	return 0;
235 }
236