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