#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
#define MAX_PATH_LEN 1024
#define MAX_DOMAIN_LEN 1024
#define MAX_STRING_LEN 2048
#define USAGE "Usage: xgettext [-a [-x exclude-file]] [-jns]\
[-c comment-tag]\n [-d default-domain] [-m prefix] \
[-M suffix] [-p pathname] files ...\n\
xgettext -h\n"
#define DEFAULT_DOMAIN "messages"
extern char yytext[];
extern int yylex(void);
struct strlist_st {
char *str;
struct strlist_st *next;
};
struct element_st {
char istextdomain;
char isduplicate;
struct strlist_st *msgid;
struct strlist_st *msgstr;
struct strlist_st *comment;
char *fname;
int linenum;
struct element_st *next;
};
struct domain_st {
char *dname;
struct element_st *gettext_head;
struct element_st *gettext_tail;
struct element_st *textdomain_head;
struct element_st *textdomain_tail;
struct domain_st *next;
};
static struct domain_st *def_dom = NULL;
static struct domain_st *dom_head = NULL;
static struct domain_st *dom_tail = NULL;
static struct exclude_st {
struct strlist_st *exstr;
struct exclude_st *next;
} *excl_head;
static int aflg = FALSE;
static int cflg = FALSE;
static char *comment_tag = NULL;
static char *default_domain = NULL;
static int hflg = FALSE;
static int jflg = FALSE;
static int mflg = FALSE;
static int Mflg = FALSE;
static char *suffix = NULL;
static char *prefix = NULL;
static int nflg = FALSE;
static int pflg = FALSE;
static char *pathname = NULL;
static int sflg = FALSE;
static int tflg = FALSE;
static int xflg = FALSE;
static char *exclude_file = NULL;
static int in_comment = FALSE;
static int in_cplus_comment = FALSE;
static int in_gettext = FALSE;
static int in_dgettext = FALSE;
static int in_dcgettext = FALSE;
static int in_textdomain = FALSE;
static int in_str = FALSE;
static int in_quote = FALSE;
static int is_last_comment_line = FALSE;
static int is_first_comma_found = FALSE;
static int in_skippable_string = FALSE;
static int num_nested_open_paren = 0;
static int linenum_saved = 0;
int stdin_only = FALSE;
char curr_file[MAX_PATH_LEN];
static char curr_domain[MAX_DOMAIN_LEN];
static char curr_line[MAX_STRING_LEN];
static char qstring_buf[MAX_STRING_LEN];
int curr_linenum = 1;
int warn_linenum = 0;
static struct strlist_st *strhead = NULL;
static struct strlist_st *strtail = NULL;
static struct strlist_st *commhead = NULL;
static struct strlist_st *commtail = NULL;
int gargc;
char **gargv;
static void add_line_to_comment(void);
static void add_qstring_to_str(void);
static void add_str_to_element_list(int, char *);
static void copy_strlist_to_str(char *, struct strlist_st *);
static void end_ansi_string(void);
static void free_strlist(struct strlist_st *);
void handle_newline(void);
static void initialize_globals(void);
static void output_comment(FILE *, struct strlist_st *);
static void output_msgid(FILE *, struct strlist_st *, int);
static void output_textdomain(FILE *, struct element_st *);
static void print_help(void);
static void read_exclude_file(void);
static void trim_line(char *);
static void write_all_files(void);
static void write_one_file(struct domain_st *);
static void lstrcat(char *, const char *);
static struct domain_st *new_domain(void);
static struct strlist_st *new_strlist(void);
static struct element_st *new_element(void);
static struct exclude_st *new_exclude(void);
int
main(int argc, char **argv)
{
int opterr = FALSE;
int c;
initialize_globals();
while ((c = getopt(argc, argv, "jhax:nsc:d:m:M:p:t")) != EOF) {
switch (c) {
case 'a':
aflg = TRUE;
break;
case 'c':
cflg = TRUE;
comment_tag = optarg;
break;
case 'd':
default_domain = optarg;
break;
case 'h':
hflg = TRUE;
break;
case 'j':
jflg = TRUE;
break;
case 'M':
Mflg = TRUE;
suffix = optarg;
break;
case 'm':
mflg = TRUE;
prefix = optarg;
break;
case 'n':
nflg = TRUE;
break;
case 'p':
pflg = TRUE;
pathname = optarg;
break;
case 's':
sflg = TRUE;
break;
case 't':
tflg = TRUE;
break;
case 'x':
xflg = TRUE;
exclude_file = optarg;
break;
case '?':
opterr = TRUE;
break;
}
}
if (hflg == TRUE) {
(void) fprintf(stderr, USAGE);
print_help();
exit(0);
}
if ((xflg == TRUE) && (aflg == FALSE))
opterr = TRUE;
if ((jflg == TRUE) && (aflg == TRUE)) {
(void) fprintf(stderr,
"-a and -j options cannot be used together.\n");
opterr = TRUE;
}
if ((jflg == TRUE) && (sflg == TRUE)) {
(void) fprintf(stderr,
"-j and -s options cannot be used together.\n");
opterr = TRUE;
}
if (opterr == TRUE) {
(void) fprintf(stderr, USAGE);
exit(2);
}
if (optind == argc) {
(void) fprintf(stderr, USAGE);
exit(2);
}
if (xflg == TRUE) {
read_exclude_file();
}
if (argv[optind][0] == '-') {
stdin_only = TRUE;
optind++;
} else {
stdin_only = FALSE;
}
gargc = argc;
gargv = argv;
#ifdef DEBUG
(void) printf("optind=%d\n", optind);
{
int i = optind;
for (; i < argc; i++) {
(void) printf(" %d, <%s>\n", i, argv[i]);
}
}
#endif
if (stdin_only == FALSE) {
if (freopen(argv[optind], "r", stdin) == NULL) {
(void) fprintf(stderr,
"ERROR, can't open input file: %s\n", argv[optind]);
exit(2);
}
(void) strcpy(curr_file, gargv[optind]);
optind++;
}
(void) yylex();
#ifdef DEBUG
printf("\n======= default_domain ========\n");
print_one_domain(def_dom);
printf("======= domain list ========\n");
print_all_domain(dom_head);
#endif
write_all_files();
return (0);
}
static void
print_help(void)
{
(void) fprintf(stderr, "\n");
(void) fprintf(stderr, "-a\t\t\tfind ALL strings\n");
(void) fprintf(stderr,
"-c <comment-tag>\tget comments containing <flag>\n");
(void) fprintf(stderr,
"-d <default-domain>\tuse <default-domain> for default domain\n");
(void) fprintf(stderr, "-h\t\t\tHelp\n");
(void) fprintf(stderr,
"-j\t\t\tupdate existing file with the current result\n");
(void) fprintf(stderr,
"-M <suffix>\t\tfill in msgstr with msgid<suffix>\n");
(void) fprintf(stderr,
"-m <prefix>\t\tfill in msgstr with <prefix>msgid\n");
(void) fprintf(stderr,
"-n\t\t\tline# file name and line number info in output\n");
(void) fprintf(stderr,
"-p <pathname>\t\tuse <pathname> for output file directory\n");
(void) fprintf(stderr,
"-s\t\t\tgenerate sorted output files\n");
(void) fprintf(stderr, "-x <exclude-file>\texclude strings in file "
"<exclude-file> from output\n");
(void) fprintf(stderr,
"-\t\t\tread stdin, use as a filter (input only)\n");
}
static void
extract_filename_linenumber(char *mline)
{
int num;
char *p, *q, *r;
p = mline;
while ((p = strchr(p, '\n')) != NULL) {
p++;
curr_linenum++;
}
p = strchr(mline, ' ');
if (p == NULL)
return;
q = strchr(++p, ' ');
if (q == NULL) {
if ((num = atoi(p)) > 0) {
curr_linenum = num;
return;
}
} else {
*q++ = 0;
if (*q == '"') {
q++;
r = strchr(q, '"');
if (r == NULL) {
return;
}
*r = 0;
if ((num = atoi(p)) > 0) {
curr_linenum = num;
(void) strcpy(curr_file, q);
}
}
}
}
void
handle_macro_line(void)
{
#ifdef DEBUG
(void) printf("Macro line=<%s>\n", yytext);
#endif
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if (in_comment == FALSE) {
extract_filename_linenumber(yytext);
}
curr_linenum--;
handle_newline();
}
void
handle_cplus_comment_line(void)
{
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if ((in_comment == FALSE) &&
(in_skippable_string == FALSE)) {
in_cplus_comment = TRUE;
in_comment = TRUE;
}
}
void
handle_open_comment(void)
{
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if ((in_comment == FALSE) &&
(in_skippable_string == FALSE)) {
in_comment = TRUE;
is_last_comment_line = FALSE;
free_strlist(commhead);
commhead = commtail = NULL;
}
}
void
handle_close_comment(void)
{
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if (in_skippable_string == FALSE) {
in_comment = FALSE;
is_last_comment_line = TRUE;
}
}
void
handle_gettext(void)
{
if (tflg == TRUE) {
return;
}
num_nested_open_paren = 0;
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if (in_comment == FALSE) {
in_gettext = TRUE;
linenum_saved = curr_linenum;
curr_domain[0] = '\0';
}
}
void
handle_dgettext(void)
{
if (tflg == TRUE) {
return;
}
num_nested_open_paren = 0;
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if (in_comment == FALSE) {
in_dgettext = TRUE;
linenum_saved = curr_linenum;
curr_domain[0] = '\0';
}
}
void
handle_dcgettext(void)
{
if (tflg == FALSE) {
return;
}
num_nested_open_paren = 0;
is_first_comma_found = FALSE;
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if (in_comment == FALSE) {
in_dcgettext = TRUE;
linenum_saved = curr_linenum;
curr_domain[0] = '\0';
}
}
void
handle_textdomain(void)
{
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if (in_comment == FALSE) {
in_textdomain = TRUE;
linenum_saved = curr_linenum;
curr_domain[0] = '\0';
}
}
void
handle_open_paren(void)
{
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if (in_comment == FALSE) {
if ((in_gettext == TRUE) ||
(in_dgettext == TRUE) ||
(in_dcgettext == TRUE) ||
(in_textdomain == TRUE)) {
in_str = TRUE;
num_nested_open_paren++;
}
}
}
void
handle_close_paren(void)
{
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if (in_comment == FALSE) {
if ((in_gettext == TRUE) ||
(in_dgettext == TRUE) ||
(in_dcgettext == TRUE) ||
(in_textdomain == TRUE)) {
if (--num_nested_open_paren > 0)
return;
add_str_to_element_list(in_textdomain, curr_domain);
in_str = FALSE;
in_gettext = FALSE;
in_dgettext = FALSE;
in_dcgettext = FALSE;
in_textdomain = FALSE;
} else if (aflg == TRUE) {
end_ansi_string();
}
}
}
void
handle_esc_newline(void)
{
if (cflg == TRUE)
lstrcat(curr_line, "\\");
curr_linenum++;
if (in_quote == TRUE) {
add_qstring_to_str();
} else if ((in_comment == TRUE) ||
(is_last_comment_line == TRUE)) {
if (in_cplus_comment == FALSE) {
add_line_to_comment();
}
}
curr_line[0] = '\0';
}
void
handle_quote(void)
{
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_comment == TRUE) {
} else if ((in_gettext == TRUE) ||
(in_dgettext == TRUE) ||
(in_dcgettext == TRUE) ||
(in_textdomain == TRUE)) {
if (in_str == TRUE) {
if (in_quote == FALSE) {
in_quote = TRUE;
} else {
add_qstring_to_str();
in_quote = FALSE;
}
}
} else if (aflg == TRUE) {
if (in_str == TRUE) {
if (in_quote == TRUE) {
in_quote = FALSE;
add_qstring_to_str();
} else {
in_quote = TRUE;
}
} else {
in_str = TRUE;
in_quote = TRUE;
linenum_saved = curr_linenum;
}
} else {
in_skippable_string = (in_skippable_string == TRUE) ?
FALSE : TRUE;
}
}
void
handle_spaces(void)
{
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
}
}
static void
copy_strlist_to_str(char *str, struct strlist_st *strlist)
{
struct strlist_st *p;
str[0] = '\0';
if (strlist != NULL) {
p = strlist;
while (p != NULL) {
if (p->str != NULL) {
lstrcat(str, p->str);
}
p = p->next;
}
}
}
void
handle_comma(void)
{
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if (in_comment == FALSE) {
if (in_str == TRUE) {
if (in_dgettext == TRUE) {
copy_strlist_to_str(curr_domain, strhead);
free_strlist(strhead);
strhead = strtail = NULL;
} else if (in_dcgettext == TRUE) {
if (is_first_comma_found == FALSE) {
copy_strlist_to_str(curr_domain,
strhead);
free_strlist(strhead);
strhead = strtail = NULL;
is_first_comma_found = TRUE;
}
} else if (aflg == TRUE) {
end_ansi_string();
}
}
}
}
void
handle_character(void)
{
if (cflg == TRUE)
lstrcat(curr_line, yytext);
if (in_quote == TRUE) {
lstrcat(qstring_buf, yytext);
} else if (in_comment == FALSE) {
if (in_str == TRUE) {
if (aflg == TRUE) {
end_ansi_string();
}
}
}
}
void
handle_newline(void)
{
curr_linenum++;
if ((in_comment == TRUE) ||
(is_last_comment_line == TRUE)) {
if (in_cplus_comment == TRUE) {
in_cplus_comment = FALSE;
in_comment = FALSE;
} else {
add_line_to_comment();
}
}
curr_line[0] = '\0';
}
static void
end_ansi_string(void)
{
if ((aflg == TRUE) &&
(in_str == TRUE) &&
(in_gettext == FALSE) &&
(in_dgettext == FALSE) &&
(in_dcgettext == FALSE) &&
(in_textdomain == FALSE)) {
add_str_to_element_list(FALSE, curr_domain);
in_str = FALSE;
}
}
static void
initialize_globals(void)
{
default_domain = strdup(DEFAULT_DOMAIN);
curr_domain[0] = '\0';
curr_file[0] = '\0';
qstring_buf[0] = '\0';
}
static void
trim_line(char *line)
{
int i, p, len;
int first = 0;
int last = 0;
char c;
len = strlen(line);
i = len - 1;
while (1) {
c = line[i--];
if ((c != ' ') && (c != '\n') && (c != '\t')) {
last = ++i;
break;
}
}
if (strncmp("msgid ", line, 6) == 0) {
i = 5;
} else if (strncmp("msgstr ", line, 7) == 0) {
i = 6;
} else if (strncmp("# ", line, 2) == 0) {
i = 2;
} else {
i = 0;
}
while (1) {
c = line[i++];
if ((c != ' ') && (c != '\n') && (c != '\t')) {
first = --i;
break;
}
}
if (line[first] == '"') {
first++;
}
if (line[last] == '"') {
last--;
}
p = first;
for (i = 0; i <= (last-first); i++) {
line[i] = line[p++];
}
line [i] = '\0';
}
static void
read_exclude_file(void)
{
FILE *fp;
struct exclude_st *tmp_excl;
struct strlist_st *tail;
int ignore_line;
char line [MAX_STRING_LEN];
if ((fp = fopen(exclude_file, "r")) == NULL) {
(void) fprintf(stderr, "ERROR, can't open exclude file: %s\n",
exclude_file);
exit(2);
}
ignore_line = TRUE;
while (fgets(line, MAX_STRING_LEN, fp) != NULL) {
if ((line[0] == '\n') || (line[0] == '#')) {
continue;
} else if (strncmp(line, "msgstr", 6) == 0) {
ignore_line = TRUE;
} else if (strncmp(line, "domain", 6) == 0) {
ignore_line = TRUE;
} else if (strncmp(line, "msgid", 5) == 0) {
ignore_line = FALSE;
tmp_excl = new_exclude();
tmp_excl->exstr = new_strlist();
trim_line(line);
tmp_excl->exstr->str = strdup(line);
tail = tmp_excl->exstr;
tmp_excl->next = excl_head;
excl_head = tmp_excl;
} else {
if (ignore_line == FALSE) {
trim_line(line);
tail->next = new_strlist();
tail->next->str = strdup(line);
tail = tail->next;
}
}
}
#ifdef DEBUG
tmp_excl = excl_head;
while (tmp_excl != NULL) {
printf("============================\n");
tail = tmp_excl->exstr;
while (tail != NULL) {
printf("%s###\n", tail->str);
tail = tail->next;
}
tmp_excl = tmp_excl->next;
}
#endif
}
static struct strlist_st *
get_next_ch(struct strlist_st *p, int *m, char *c)
{
char ch, oct, hex;
int value, i;
while (1) {
if (p == NULL) {
break;
} else if (p->str == NULL) {
p = p->next;
} else if (p->str[*m] == '\0') {
p = p->next;
*m = 0;
} else {
break;
}
}
if (p == NULL) {
*c = 0;
return (NULL);
}
if (p->str[*m] != '\\') {
*c = p->str[*m];
*m = *m + 1;
return (p);
} else {
*m = *m + 1;
ch = p->str[*m];
switch (ch) {
case 'a':
*c = '\a';
break;
case 'b':
*c = '\b';
break;
case 'f':
*c = '\f';
break;
case 'n':
*c = '\n';
break;
case 'r':
*c = '\r';
break;
case 't':
*c = '\t';
break;
case 'v':
*c = '\v';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
value = ch;
for (i = 0; i < 2; i++) {
*m = *m + 1;
oct = p->str[*m];
if ((oct >= '0') && (oct <= '7')) {
value = value * 8 + (oct - '0');
} else {
*m = *m - 1;
break;
}
}
*c = value;
#ifdef DEBUG
#endif
break;
case 'x':
value = 0;
*m = *m + 1;
while (p->str[*m] == '0') {
*m = *m + 1;
}
value = 0;
for (i = 0; i < 2; i++) {
hex = p->str[*m];
*m = *m + 1;
if (isdigit(hex)) {
value = value * 16 + (hex - '0');
} else if (isxdigit(hex)) {
hex = tolower(hex);
value = value * 16 + (hex - 'a' + 10);
} else {
*m = *m - 1;
break;
}
}
*c = value;
#ifdef DEBUG
(void) fprintf(stderr, "hex=%d\n", value);
#endif
*m = *m - 1;
break;
default :
*c = p->str[*m];
break;
}
*m = *m + 1;
return (p);
}
}
static int
msgidcmp(struct strlist_st *id1, struct strlist_st *id2)
{
char c1, c2;
int m1, m2;
m1 = 0;
m2 = 0;
while (1) {
id1 = get_next_ch(id1, &m1, &c1);
id2 = get_next_ch(id2, &m2, &c2);
if ((c1 == 0) && (c2 == 0)) {
return (0);
}
if (c1 > c2) {
return (1);
} else if (c1 < c2) {
return (-1);
}
}
}
static int
isduplicate(struct element_st *list, struct strlist_st *str)
{
struct element_st *p;
if (list == NULL) {
return (FALSE);
}
p = list;
while (p != NULL) {
if (p->msgid != NULL) {
if (msgidcmp(p->msgid, str) == 0) {
return (TRUE);
}
}
p = p->next;
}
return (FALSE);
}
static void
add_line_to_comment(void)
{
struct strlist_st *tmp_str;
tmp_str = new_strlist();
tmp_str->str = strdup(curr_line);
tmp_str->next = NULL;
if (commhead == NULL) {
commhead = tmp_str;
commtail = tmp_str;
} else {
commtail->next = tmp_str;
commtail = commtail->next;
}
is_last_comment_line = FALSE;
}
static void
add_qstring_to_str(void)
{
struct strlist_st *tmp_str;
tmp_str = new_strlist();
tmp_str->str = strdup(qstring_buf);
tmp_str->next = NULL;
if (strhead == NULL) {
strhead = tmp_str;
strtail = tmp_str;
} else {
strtail->next = tmp_str;
strtail = strtail->next;
}
qstring_buf[0] = '\0';
}
static struct domain_st *
find_domain_node(char *dname)
{
struct domain_st *tmp_dom, *p;
if (aflg == TRUE) {
if (def_dom == NULL) {
def_dom = new_domain();
}
return (def_dom);
}
if ((dname == NULL) ||
(dname[0] == '\0') ||
(strcmp(dname, default_domain) == 0)) {
if (def_dom == NULL) {
def_dom = new_domain();
}
if (strcmp(dname, default_domain) == 0) {
(void) fprintf(stderr, "%s \"%s\" is used in dgettext "
"of file:%s line:%d.\n",
"Warning: default domain name",
default_domain, curr_file, curr_linenum);
}
return (def_dom);
} else {
p = dom_head;
while (p != NULL) {
if (strcmp(p->dname, dname) == 0) {
return (p);
}
p = p->next;
}
tmp_dom = new_domain();
tmp_dom->dname = strdup(dname);
if (dom_head == NULL) {
dom_head = tmp_dom;
dom_tail = tmp_dom;
} else {
dom_tail->next = tmp_dom;
dom_tail = dom_tail->next;
}
return (tmp_dom);
}
}
static void
free_strlist(struct strlist_st *ptr)
{
struct strlist_st *p;
p = ptr;
ptr = NULL;
while (p != NULL) {
ptr = p->next;
free(p->str);
free(p);
p = ptr;
}
}
static int
isexcluded(struct strlist_st *strlist)
{
struct exclude_st *p;
p = excl_head;
while (p != NULL) {
if (msgidcmp(p->exstr, strlist) == 0) {
return (TRUE);
}
p = p->next;
}
return (FALSE);
}
static int
isextracted(struct strlist_st *strlist)
{
struct strlist_st *p;
char *first, *pc;
p = strlist;
while (p != NULL) {
first = strdup(p->str);
while ((first != NULL) && (first[0] != '\0')) {
pc = first;
while (1) {
if (*pc == '\0') {
break;
} else if ((*pc == ' ') || (*pc == '\t')) {
*pc++ = '\0';
break;
}
pc++;
}
if (strcmp(first, comment_tag) == 0) {
return (TRUE);
}
first = pc;
}
p = p->next;
}
return (FALSE);
}
static void
add_str_to_element_list(int istextdomain, char *domain_list)
{
struct element_st *tmp_elem;
struct element_st *p, *q;
struct domain_st *tmp_dom;
int result;
if (strhead == NULL) {
return;
}
tmp_dom = find_domain_node(domain_list);
if ((istextdomain == FALSE) &&
(isexcluded(strhead) == TRUE)) {
free_strlist(strhead);
strhead = strtail = NULL;
return;
}
tmp_elem = new_element();
tmp_elem->msgid = strhead;
tmp_elem->istextdomain = istextdomain;
if (istextdomain == FALSE) {
if ((cflg == TRUE) && (commhead != NULL)) {
if (isextracted(commhead) == TRUE) {
tmp_elem->comment = commhead;
} else {
free_strlist(commhead);
}
commhead = commtail = NULL;
}
}
tmp_elem->linenum = linenum_saved;
tmp_elem->fname = strdup(curr_file);
if (sflg == TRUE) {
if (istextdomain == TRUE) {
if (tmp_dom->textdomain_head == NULL) {
tmp_dom->textdomain_head = tmp_elem;
tmp_dom->textdomain_tail = tmp_elem;
} else {
tmp_dom->textdomain_tail->next = tmp_elem;
tmp_dom->textdomain_tail = tmp_elem;
}
strhead = strtail = NULL;
return;
}
q = NULL;
p = tmp_dom->gettext_head;
while (p != NULL) {
result = msgidcmp(strhead, p->msgid);
if (result == 0) {
free_strlist(strhead);
strhead = strtail = NULL;
return;
} else if (result > 0) {
q = p;
p = p->next;
} else {
tmp_elem->next = p;
if (q != NULL) {
q->next = tmp_elem;
} else {
tmp_dom->gettext_head = tmp_elem;
}
strhead = strtail = NULL;
return;
}
}
if (q != NULL) {
q->next = tmp_elem;
} else {
tmp_dom->gettext_head = tmp_elem;
}
} else {
if (tmp_dom != NULL) {
if (isduplicate(tmp_dom->gettext_head,
tmp_elem->msgid) == TRUE) {
tmp_elem->isduplicate = TRUE;
}
}
if (tmp_dom->gettext_head == NULL) {
tmp_dom->gettext_head = tmp_elem;
tmp_dom->gettext_tail = tmp_elem;
} else {
tmp_dom->gettext_tail->next = tmp_elem;
tmp_dom->gettext_tail = tmp_elem;
}
}
strhead = strtail = NULL;
}
static void
write_all_files(void)
{
struct domain_st *tmp;
write_one_file(def_dom);
tmp = dom_head;
while (tmp != NULL) {
write_one_file(tmp);
tmp = tmp->next;
}
}
static void
add_node_to_polist(struct element_st **pohead,
struct element_st **potail, struct element_st *elem)
{
if (elem == NULL) {
return;
}
if (*pohead == NULL) {
*pohead = *potail = elem;
} else {
(*potail)->next = elem;
*potail = (*potail)->next;
}
}
#define INIT_STATE 0
#define IN_MSGID 1
#define IN_MSGSTR 2
#define IN_COMMENT 3
static struct element_st *
read_po(char *fname)
{
struct element_st *tmp_elem = NULL;
struct element_st *ehead = NULL, *etail = NULL;
struct strlist_st *comment_tail = NULL;
struct strlist_st *msgid_tail = NULL;
struct strlist_st *msgstr_tail = NULL;
int state = INIT_STATE;
char line [MAX_STRING_LEN];
FILE *fp;
if ((fp = fopen(fname, "r")) == NULL) {
return (NULL);
}
while (fgets(line, MAX_STRING_LEN, fp) != NULL) {
if (line[0] == '\n') {
continue;
} else if (line[0] == '#') {
if ((tmp_elem != NULL) && (state == IN_MSGSTR)) {
add_node_to_polist(&ehead, &etail, tmp_elem);
}
if ((state == INIT_STATE) || (state == IN_MSGSTR)) {
state = IN_COMMENT;
tmp_elem = new_element();
tmp_elem->comment = comment_tail =
new_strlist();
line[strlen(line)-1] = 0;
comment_tail->str = strdup(line+2);
} else if (state == IN_COMMENT) {
comment_tail->next = new_strlist();
comment_tail = comment_tail->next;
line[strlen(line)-1] = 0;
comment_tail->str = strdup(line+2);
}
} else if (strncmp(line, "domain", 6) == 0) {
continue;
} else if (strncmp(line, "msgid", 5) == 0) {
if (state == IN_MSGSTR) {
add_node_to_polist(&ehead, &etail, tmp_elem);
tmp_elem = new_element();
} else if (state == INIT_STATE) {
tmp_elem = new_element();
}
state = IN_MSGID;
trim_line(line);
tmp_elem->msgid = msgid_tail = new_strlist();
msgid_tail->str = strdup(line);
} else if (strncmp(line, "msgstr", 6) == 0) {
state = IN_MSGSTR;
trim_line(line);
tmp_elem->msgstr = msgstr_tail = new_strlist();
msgstr_tail->str = strdup(line);
} else {
if (state == IN_MSGID) {
trim_line(line);
msgid_tail->next = new_strlist();
msgid_tail = msgid_tail->next;
msgid_tail->str = strdup(line);
} else if (state == IN_MSGSTR) {
trim_line(line);
msgstr_tail->next = new_strlist();
msgstr_tail = msgstr_tail->next;
msgstr_tail->str = strdup(line);
}
}
}
if (tmp_elem != NULL) {
add_node_to_polist(&ehead, &etail, tmp_elem);
}
#ifdef DEBUG
{
struct domain_st *tmp_domain = new_domain();
char tmpstr[256];
sprintf(tmpstr, "existing_po file : <%s>", fname);
tmp_domain->dname = strdup(tmpstr);
tmp_domain->gettext_head = ehead;
printf("======= existing po file <%s> ========\n", fname);
print_one_domain(tmp_domain);
}
#endif
(void) fclose(fp);
return (ehead);
}
static struct element_st *
append_list(struct element_st *l1, struct element_st *l2)
{
struct element_st *p = NULL, *q = NULL, *l1_tail = NULL;
if (l1 == NULL)
return (l2);
if (l2 == NULL)
return (l1);
p = l2;
while (p != NULL) {
q = l1;
while (q != NULL) {
if (msgidcmp(p->msgid, q->msgid) == 0) {
p->isduplicate = TRUE;
break;
}
q = q->next;
}
p = p->next;
}
l1_tail = l1;
while (l1_tail->next != NULL) {
if (l1->next == NULL)
break;
l1_tail = l1_tail-> next;
}
l1_tail->next = l2;
return (l1);
}
static void
write_one_file(struct domain_st *head)
{
FILE *fp;
char fname [MAX_PATH_LEN];
char dname [MAX_DOMAIN_LEN];
struct element_st *p;
struct element_st *existing_po_list;
dname[0] = '\0';
if ((head != NULL) &&
(head->dname != NULL)) {
(void) strcpy(dname, head->dname);
} else {
(void) strcpy(dname, default_domain);
}
fname[0] = 0;
if (pflg == TRUE) {
(void) strcat(fname, pathname);
(void) strcat(fname, "/");
}
(void) strcat(fname, dname);
(void) strcat(fname, ".po");
if (jflg == TRUE) {
if (head == NULL) {
return;
}
existing_po_list = read_po(fname);
head->gettext_head = append_list(existing_po_list,
head->gettext_head);
#ifdef DEBUG
if (head->dname != NULL) {
printf("===after merge (-j option): <%s>===\n",
head->dname);
} else {
printf("===after merge (-j option): <NULL>===\n");
}
print_one_domain(head);
#endif
}
if ((fp = fopen(fname, "w")) == NULL) {
(void) fprintf(stderr,
"ERROR, can't open output file: %s\n", fname);
exit(2);
}
(void) fprintf(fp, "domain \"%s\"\n", dname);
if (head == NULL)
return;
if (sflg == TRUE) {
p = head->textdomain_head;
while (p != NULL) {
output_textdomain(fp, p);
p = p->next;
}
}
p = head->gettext_head;
while (p != NULL) {
if (((cflg == TRUE) || (jflg == TRUE)) &&
(p->istextdomain != TRUE)) {
output_comment(fp, p->comment);
}
if ((nflg == TRUE) && (p->istextdomain == FALSE) &&
(p->linenum > 0)) {
(void) fprintf(fp, "# File:%s, line:%d\n",
p->fname, p->linenum);
}
if ((sflg == FALSE) &&
(p->istextdomain == TRUE)) {
output_textdomain(fp, p);
} else {
output_msgid(fp, p->msgid, p->isduplicate);
}
p = p->next;
}
(void) fclose(fp);
}
static void
output_textdomain(FILE *fp, struct element_st *p)
{
if (p == NULL)
return;
(void) fprintf(fp, "# File:%s, line:%d, textdomain(\"%s\");\n",
p->fname, p->linenum, p->msgid->str);
}
static void
output_comment(FILE *fp, struct strlist_st *p)
{
if (p == NULL)
return;
while (p != NULL) {
(void) fprintf(fp, "# %s\n", p->str);
p = p->next;
}
}
static void
output_msgid(FILE *fp, struct strlist_st *p, int duplicate)
{
struct strlist_st *q;
if (p == NULL)
return;
if (duplicate == TRUE) {
(void) fprintf(fp, "# ");
}
(void) fprintf(fp, "msgid \"%s\"\n", p->str);
q = p->next;
while (q != NULL) {
if (duplicate == TRUE) {
(void) fprintf(fp, "# ");
}
(void) fprintf(fp, " \"%s\"\n", q->str);
q = q->next;
}
if (duplicate == TRUE) {
(void) fprintf(fp, "# ");
}
if ((mflg == TRUE) || (Mflg == TRUE)) {
if (mflg == TRUE) {
if ((Mflg == TRUE) && (p->next == NULL)) {
(void) fprintf(fp, "msgstr \"%s%s%s\"\n",
prefix, p->str, suffix);
} else {
(void) fprintf(fp, "msgstr \"%s%s\"\n",
prefix, p->str);
}
} else {
if ((Mflg == TRUE) && (p->next == NULL)) {
(void) fprintf(fp, "msgstr \"%s%s\"\n",
p->str, suffix);
} else {
(void) fprintf(fp, "msgstr \"%s\"\n", p->str);
}
}
q = p->next;
while (q != NULL) {
if (duplicate == TRUE) {
(void) fprintf(fp, "# ");
}
(void) fprintf(fp, " \"%s\"\n", q->str);
q = q->next;
}
if ((Mflg == TRUE) && (p->next != NULL) &&
(suffix[0] != '\0')) {
(void) fprintf(fp, " \"%s\"\n", suffix);
}
} else {
(void) fprintf(fp, "msgstr\n");
}
}
static struct element_st *
new_element(void)
{
struct element_st *tmp;
tmp = (struct element_st *)malloc(sizeof (struct element_st));
tmp->istextdomain = FALSE;
tmp->isduplicate = FALSE;
tmp->msgid = NULL;
tmp->msgstr = NULL;
tmp->comment = NULL;
tmp->fname = NULL;
tmp->linenum = 0;
tmp->next = NULL;
return (tmp);
}
static struct domain_st *
new_domain(void)
{
struct domain_st *tmp;
tmp = (struct domain_st *)malloc(sizeof (struct domain_st));
tmp->dname = NULL;
tmp->gettext_head = NULL;
tmp->gettext_tail = NULL;
tmp->textdomain_head = NULL;
tmp->textdomain_tail = NULL;
tmp->next = NULL;
return (tmp);
}
static struct strlist_st *
new_strlist(void)
{
struct strlist_st *tmp;
tmp = (struct strlist_st *)malloc(sizeof (struct strlist_st));
tmp->str = NULL;
tmp->next = NULL;
return (tmp);
}
static struct exclude_st *
new_exclude(void)
{
struct exclude_st *tmp;
tmp = (struct exclude_st *)malloc(sizeof (struct exclude_st));
tmp->exstr = NULL;
tmp->next = NULL;
return (tmp);
}
static void
lstrcat(char *s1, const char *s2)
{
char *es1 = &s1[MAX_STRING_LEN];
char *ss1 = s1;
while (*s1++)
;
--s1;
while (*s1++ = *s2++)
if (s1 >= es1) {
s1[-1] = '\0';
if ((in_comment == TRUE || in_quote == TRUE) &&
(warn_linenum != curr_linenum)) {
if (stdin_only == FALSE) {
(void) fprintf(stderr,
"WARNING: file %s line %d exceeds "\
"%d characters: \"%15.15s\"\n",
curr_file, curr_linenum,
MAX_STRING_LEN, ss1);
} else {
(void) fprintf(stderr,
"WARNING: line %d exceeds "\
"%d characters: \"%15.15s\"\n",
curr_linenum, MAX_STRING_LEN, ss1);
}
warn_linenum = curr_linenum;
}
break;
}
}
#ifdef DEBUG
void
print_element_list(struct element_st *q)
{
struct strlist_st *r;
while (q != NULL) {
printf(" istextdomain = %d\n", q->istextdomain);
printf(" isduplicate = %d\n", q->isduplicate);
if ((q->msgid != NULL) && (q->msgid->str != NULL)) {
printf(" msgid = <%s>\n", q->msgid->str);
r = q->msgid->next;
while (r != NULL) {
printf(" <%s>\n", r->str);
r = r->next;
}
} else {
printf(" msgid = <NULL>\n");
}
if ((q->msgstr != NULL) && (q->msgstr->str != NULL)) {
printf(" msgstr= <%s>\n", q->msgstr->str);
r = q->msgstr->next;
while (r != NULL) {
printf(" <%s>\n", r->str);
r = r->next;
}
} else {
printf(" msgstr= <NULL>\n");
}
if (q->comment == NULL) {
printf(" comment = <NULL>\n");
} else {
printf(" comment = <%s>\n", q->comment->str);
r = q->comment->next;
while (r != NULL) {
printf(" <%s>\n", r->str);
r = r->next;
}
}
if (q->fname == NULL) {
printf(" fname = <NULL>\n");
} else {
printf(" fname = <%s>\n", q->fname);
}
printf(" linenum = %d\n", q->linenum);
printf("\n");
q = q->next;
}
}
void
print_one_domain(struct domain_st *p)
{
struct element_st *q;
if (p == NULL) {
printf("domain pointer = <NULL>\n");
return;
} else if (p->dname == NULL) {
printf("domain_name = <%s>\n", "<NULL>");
} else {
printf("domain_name = <%s>\n", p->dname);
}
q = p->gettext_head;
print_element_list(q);
q = p->textdomain_head;
print_element_list(q);
}
void
print_all_domain(struct domain_st *dom_list)
{
struct domain_st *p;
struct element_st *q;
p = dom_list;
while (p != NULL) {
print_one_domain(p);
p = p->next;
}
}
#endif