/* This file is part of PODIFF.
Copyright (C) 2011-2022 Sergey Poznyakoff
PODIFF is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
PODIFF is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this PODIFF. If not, see . */
%{
#include
#include "podiff.h"
#include "y.tab.h"
int skip_entry;
%}
%union {
char *string;
int number;
struct txtacc *acc;
struct list *lst;
struct msgtrans *msgtrans;
struct { unsigned line; int num; char *str; } imsgstr;
};
%token STRING FLAG COMMENT MSGCTXT
%token NUMBER
%token MSGID MSGID_PLURAL MSGSTR FUZZY OLDTRANS
%type msgid msgid_plural msgstr msgctxt
%type strings
%type msgstrlist entries ocomm comment
%type imsgstr
%type entry
%%
input : entries
{
msgtrans_list = $1;
msgtrans_list->cmp = msgtrans_sort_id;
}
;
entries : entry
{
$$ = list_create();
/*$$->free_entry = free;*/
if ($1)
list_append($$, $1);
}
| entries entry
{
if ($2)
list_append($1, $2);
$$ = $1;
}
;
entry : ocomm oflags msgctxt msgid msgstr
{
if (skip_entry)
$$ = NULL;
else {
$$ = emalloc(sizeof(*$$));
$$->comment = $1;
$$->msgctxt = $3;
$$->msgid = $4;
$$->msgid_plural = NULL;
$$->msgstr = list_create();
$$->msgstr->free_entry = free;
list_append($$->msgstr, $5);
}
skip_entry = 0;
}
| ocomm oflags msgctxt msgid msgid_plural msgstrlist
{
if (skip_entry)
$$ = NULL;
else {
$$ = emalloc(sizeof(*$$));
$$->comment = $1;
$$->msgctxt = $3;
$$->msgid = $4;
$$->msgid_plural = $5;
$$->msgstr = $6;
}
skip_entry = 0;
}
| ocomm oflags msgctxt oldentry
{
/* FIXME: Reclaim memory */
$$ = NULL;
}
;
oldentry : OLDTRANS
| oldentry OLDTRANS
;
oflags : /* empty */
| flags;
;
flags : flag
| flags flag
;
flag : FLAG
| FUZZY
{
skip_entry = skip_fuzzy_option;
}
;
ocomm : /* empty */
{
$$ = NULL;
}
| comment
;
comment : COMMENT
{
$$ = list_create();
list_append($$, $1);
}
| comment COMMENT
{
list_append($1, $2);
}
;
msgctxt : /* empty */
{
$$ = NULL;
}
| MSGCTXT strings
{
$$ = txtacc_finish($2, 1);
txtacc_free($2);
}
;
msgid : MSGID strings
{
$$ = txtacc_finish($2, 1);
txtacc_free($2);
}
;
msgid_plural: MSGID_PLURAL strings
{
$$ = txtacc_finish($2, 1);
txtacc_free($2);
}
;
msgstr : MSGSTR strings
{
$$ = txtacc_finish($2, 1);
txtacc_free($2);
}
;
imsgstr : MSGSTR { $$ = line_no; } '[' NUMBER ']' strings
{
$$.line = $2;
$$.num = $4;
$$.str = txtacc_finish($6, 1);
txtacc_free($6);
}
;
msgstrlist: imsgstr
{
if ($1.num != 0)
parse_error_at_line($1.line,
"msgstr number should be zero");
$$ = list_create();
$$->free_entry = free;
list_append($$, $1.str);
}
| msgstrlist imsgstr
{
if ($2.num != list_size($1))
parse_error_at_line($2.line,
"msgstr number out of sequence");
list_append($1, $2.str);
$$ = $1;
}
;
strings : STRING
{
$$ = txtacc_create();
txtacc_grow($$, $1, strlen($1));
}
| strings STRING
{
txtacc_grow($1, $2, strlen($2));
$$ = $1;
}
;
%%
int
yyerror(const char *s)
{
parse_error("%s", s);
}
int
msgtrans_sort_id(void const *a, void const *b)
{
struct msgtrans const *pa = a;
struct msgtrans const *pb = b;
int rc;
rc = strcmp(pa->msgid, pb->msgid);
if (rc == 0) {
if (pa->msgctxt) {
if (pb->msgctxt)
rc = strcmp(pa->msgctxt, pb->msgctxt);
else
rc = -1;
} else if (pb->msgctxt)
rc = 1;
}
return rc;
}