root/scripts/kconfig/kxgettext.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. escape
  2. file_line__new
  3. message__new
  4. mesage__find
  5. message__add_file_line
  6. message__add
  7. menu_build_message_list
  8. message__print_file_lineno
  9. message__print_gettext_msgid_msgstr
  10. menu__xgettext
  11. main

/*
 * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005
 *
 * Released under the terms of the GNU GPL v2.0
 */

#include <stdlib.h>
#include <string.h>

#include "lkc.h"

static char *escape(const char* text, char *bf, int len)
{
        char *bfp = bf;
        int multiline = strchr(text, '\n') != NULL;
        int eol = 0;
        int textlen = strlen(text);

        if ((textlen > 0) && (text[textlen-1] == '\n'))
                eol = 1;

        *bfp++ = '"';
        --len;

        if (multiline) {
                *bfp++ = '"';
                *bfp++ = '\n';
                *bfp++ = '"';
                len -= 3;
        }

        while (*text != '\0' && len > 1) {
                if (*text == '"')
                        *bfp++ = '\\';
                else if (*text == '\n') {
                        *bfp++ = '\\';
                        *bfp++ = 'n';
                        *bfp++ = '"';
                        *bfp++ = '\n';
                        *bfp++ = '"';
                        len -= 5;
                        ++text;
                        goto next;
                }
                else if (*text == '\\') {
                        *bfp++ = '\\';
                        len--;
                }
                *bfp++ = *text++;
next:
                --len;
        }

        if (multiline && eol)
                bfp -= 3;

        *bfp++ = '"';
        *bfp = '\0';

        return bf;
}

struct file_line {
        struct file_line *next;
        const char *file;
        int lineno;
};

static struct file_line *file_line__new(const char *file, int lineno)
{
        struct file_line *self = malloc(sizeof(*self));

        if (self == NULL)
                goto out;

        self->file   = file;
        self->lineno = lineno;
        self->next   = NULL;
out:
        return self;
}

struct message {
        const char       *msg;
        const char       *option;
        struct message   *next;
        struct file_line *files;
};

static struct message *message__list;

static struct message *message__new(const char *msg, char *option,
                                    const char *file, int lineno)
{
        struct message *self = malloc(sizeof(*self));

        if (self == NULL)
                goto out;

        self->files = file_line__new(file, lineno);
        if (self->files == NULL)
                goto out_fail;

        self->msg = strdup(msg);
        if (self->msg == NULL)
                goto out_fail_msg;

        self->option = option;
        self->next = NULL;
out:
        return self;
out_fail_msg:
        free(self->files);
out_fail:
        free(self);
        self = NULL;
        goto out;
}

static struct message *mesage__find(const char *msg)
{
        struct message *m = message__list;

        while (m != NULL) {
                if (strcmp(m->msg, msg) == 0)
                        break;
                m = m->next;
        }

        return m;
}

static int message__add_file_line(struct message *self, const char *file,
                                  int lineno)
{
        int rc = -1;
        struct file_line *fl = file_line__new(file, lineno);

        if (fl == NULL)
                goto out;

        fl->next    = self->files;
        self->files = fl;
        rc = 0;
out:
        return rc;
}

static int message__add(const char *msg, char *option, const char *file,
                        int lineno)
{
        int rc = 0;
        char bf[16384];
        char *escaped = escape(msg, bf, sizeof(bf));
        struct message *m = mesage__find(escaped);

        if (m != NULL)
                rc = message__add_file_line(m, file, lineno);
        else {
                m = message__new(escaped, option, file, lineno);

                if (m != NULL) {
                        m->next       = message__list;
                        message__list = m;
                } else
                        rc = -1;
        }
        return rc;
}

static void menu_build_message_list(struct menu *menu)
{
        struct menu *child;

        message__add(menu_get_prompt(menu), NULL,
                     menu->file == NULL ? "Root Menu" : menu->file->name,
                     menu->lineno);

        if (menu->sym != NULL && menu_has_help(menu))
                message__add(menu_get_help(menu), menu->sym->name,
                             menu->file == NULL ? "Root Menu" : menu->file->name,
                             menu->lineno);

        for (child = menu->list; child != NULL; child = child->next)
                if (child->prompt != NULL)
                        menu_build_message_list(child);
}

static void message__print_file_lineno(struct message *self)
{
        struct file_line *fl = self->files;

        putchar('\n');
        if (self->option != NULL)
                printf("# %s:00000\n", self->option);

        printf("#: %s:%d", fl->file, fl->lineno);
        fl = fl->next;

        while (fl != NULL) {
                printf(", %s:%d", fl->file, fl->lineno);
                fl = fl->next;
        }

        putchar('\n');
}

static void message__print_gettext_msgid_msgstr(struct message *self)
{
        message__print_file_lineno(self);

        printf("msgid %s\n"
               "msgstr \"\"\n", self->msg);
}

static void menu__xgettext(void)
{
        struct message *m = message__list;

        while (m != NULL) {
                /* skip empty lines ("") */
                if (strlen(m->msg) > sizeof("\"\""))
                        message__print_gettext_msgid_msgstr(m);
                m = m->next;
        }
}

int main(int ac, char **av)
{
        conf_parse(av[1]);

        menu_build_message_list(menu_get_root_menu(NULL));
        menu__xgettext();
        return 0;
}

/* [<][>][^][v][top][bottom][index][help] */