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
12static 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++;
50next:
51		--len;
52	}
53
54	if (multiline && eol)
55		bfp -= 3;
56
57	*bfp++ = '"';
58	*bfp = '\0';
59
60	return bf;
61}
62
63struct file_line {
64	struct file_line *next;
65	const char *file;
66	int lineno;
67};
68
69static 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;
79out:
80	return self;
81}
82
83struct message {
84	const char	 *msg;
85	const char	 *option;
86	struct message	 *next;
87	struct file_line *files;
88};
89
90static struct message *message__list;
91
92static 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;
110out:
111	return self;
112out_fail_msg:
113	free(self->files);
114out_fail:
115	free(self);
116	self = NULL;
117	goto out;
118}
119
120static 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
133static 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;
145out:
146	return rc;
147}
148
149static 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
171static 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
189static 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
208static 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
216static 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
228int 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