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