/* This file is part of VK/KittenPHP-DB-Engine. VK/KittenPHP-DB-Engine 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 2 of the License, or (at your option) any later version. VK/KittenPHP-DB-Engine 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 VK/KittenPHP-DB-Engine. If not, see . This program is released under the GPL with the additional exemption that compiling, linking, and/or using OpenSSL is allowed. You are free to remove this exemption from derived works. Copyright 2011-2013 Vkontakte Ltd 2011-2013 Vitaliy Valtman */ #include #include #include #include "vkext_flex.h" #include "vkext_flex_auto.c" #define BUFF_LEN (1 << 16) static char buff[BUFF_LEN]; char *estrdup (const char *s) { char *d = malloc (strlen (s) + 1); if (d == NULL) return NULL; strcpy (d,s); return d; } char *do_flex (const char *name, int name_len, const char *case_name, int case_name_len, int sex, const char *type, int lang_id) { if (name_len > (1 << 10)) { return estrdup (name); } struct lang *cur_lang; if (lang_id < 0 || lang_id >= LANG_NUM || !langs[lang_id]) { return estrdup (name); } cur_lang = langs[lang_id]; assert (cur_lang); int t = -1; if (!strcmp (type, "names")) { if (cur_lang->names_start < 0) { return estrdup (name); } t = cur_lang->names_start; } else if (!strcmp (type, "surnames")) { if (cur_lang->surnames_start < 0) { return estrdup (name); } t = cur_lang->surnames_start; } else { return estrdup (name); } assert (t >= 0); if (sex != 1) { sex = 0; } int ca = -1; int i; for (i = 0; i < CASES_NUM; i++) if (!strcmp (cases_names[i], case_name)) { ca = i; break; } if (ca == -1 || ca >= cur_lang->cases_num) { return estrdup (name); } assert (ca >= 0 && ca < cur_lang->cases_num); int p = 0; int wp = 0; while (p < name_len) { int pp = p; while (pp < name_len && name[pp] != '-') { pp++; } int hyphen = (name[pp] == '-'); int tt = t; int best = -1; int save_pp = pp; int new_tt; int isf = 0; if (pp - p > 0) { const char *fle = cur_lang->flexible_symbols; while (*fle) { if (*fle == name[pp - 1]) { isf = 1; break; } fle ++; } } while (1 && isf) { assert (tt >= 0); if (cur_lang->nodes[tt].tail_len >= 0 && (!cur_lang->nodes[tt].hyphen || hyphen)) { best = tt; } unsigned char c; if (pp == p - 1) { break; } pp --; if (pp < p) { c = 0; } else { c = name[pp]; } new_tt = -1; int l = cur_lang->nodes[tt].children_start; int r = cur_lang->nodes[tt].children_end; if (r - l <= 4) { for (i = l; i < r; i++) if (cur_lang->children[2 * i] == c) { new_tt = cur_lang->children[2 * i + 1] ; break; } } else { int x; while (r - l > 1) { x = (r + l) >> 1; if (cur_lang->children[2 * x] <= c) { l = x; } else { r = x; } } if (cur_lang->children[2 * l] == c) { new_tt = cur_lang->children[2 * l + 1]; } } if (new_tt == -1) { break; } else { tt = new_tt; } } if (best == -1) { memcpy (buff + wp, name + p, save_pp - p); wp += (save_pp - p); } else { int r = -1; if (!sex) { r = cur_lang->nodes[best].male_endings; } else { r = cur_lang->nodes[best].female_endings; } if (r < 0 || !cur_lang->endings[r * cur_lang->cases_num + ca]) { memcpy (buff + wp, name + p, save_pp - p); wp += (save_pp - p); } else { int ml = save_pp - p - cur_lang->nodes[best].tail_len; if (ml < 0) { ml = 0; } memcpy (buff + wp, name + p, ml); wp += ml; strcpy (buff + wp, cur_lang->endings[r * cur_lang->cases_num + ca]); wp += strlen (cur_lang->endings[r * cur_lang->cases_num + ca]); } } if (hyphen) { buff[wp++] = '-'; } else { buff[wp++] = 0; } p = save_pp + 1; } return estrdup (buff); }