diff options
Diffstat (limited to 'src/numeric.c')
-rw-r--r-- | src/numeric.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/numeric.c b/src/numeric.c index e08c48d..21c574e 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -30,3 +30,198 @@ #include "log.h" #include "send.h" #include "client.h" +#include "messages.tab" + +static char used_locale[LOCALE_LENGTH] = "standard"; + +/* + * form_str + * + * inputs - numeric + * output - corresponding string + * side effects - NONE + */ +const char* form_str(int numeric) +{ + assert(-1 < numeric); + assert(numeric < ERR_LAST_ERR_MSG); + + if (numeric > ERR_LAST_ERR_MSG) + numeric = ERR_LAST_ERR_MSG; + if (numeric < 0) + numeric = ERR_LAST_ERR_MSG; + + assert(replies[numeric].standard != NULL); + + return (replies[numeric].translated != NULL ? replies[numeric].translated : + replies[numeric].standard); +} + +/* Attempts to change a numeric with index "reply" to "new_reply". + * Returns 1 if ok, 0 otherwise. + */ +static int +change_reply(const char *locale, int linecnt, int reply, char *new_reply) +{ + int found; + char *new = new_reply; + const char *old = replies[reply].standard; + + for (; *new; new++) + { + if (*new == '%') + { + if (!*++new) break; + if (*new != '%') + { + /* We've just found a format symbol. Check if it is the next format + * symbol in the original reply. + */ + for (; *new >= '0' && *new <= '9'; new++); /* skip size prefix */ + found = 0; + for (; *old; old++) + { + if (*old == '%') + { + if (!*++old) break; /* shouldn't happen */ + if (*old != '%') + { + for (; *old >= '0' && *old <= '9'; old++); /* skip size prefix */ + if (*new != *old++) + { + ilog(LOG_TYPE_IRCD, "Incompatible format symbols (%s.lang, %d)", + locale, linecnt); + return 0; + } + found = 1; + break; + } + } + } + if (!found) + { + ilog(LOG_TYPE_IRCD, "Too many format symbols (%s.lang, %d)", locale, linecnt); + return(0); + } + } + } + } + + MyFree(replies[reply].translated); + replies[reply].translated = xstrdup(new_reply); + return(1); +} + +/* Loads a language file. Errors are logged into the log file. */ +void +set_locale(const char *locale) +{ + int i, res = 1, linecnt = 0; + char buffer[IRCD_BUFSIZE + 1]; + char *ident, *reply; + FILE *f; + + /* Restore standard replies */ + for (i = 0; i <= ERR_LAST_ERR_MSG; i++) /* 0 isn't a magic number! ;> */ + { + if (replies[i].translated != NULL) + { + MyFree(replies[i].translated); + replies[i].translated = NULL; + } + } + + if (strchr(locale, '/') != NULL) + { + strlcpy(used_locale, "standard", sizeof(used_locale)); /* XXX paranoid */ + return; + } + + /* yes, I know - the slash isn't necessary. But I have to be sure + * that it'll work even if some lame admin won't put "/" at the end + * of MSGPATH. + */ + snprintf(buffer, sizeof(buffer), "%s/%s.lang", MSGPATH, locale); + if ((f = fopen(buffer, "r")) == NULL) + { + strlcpy(used_locale, "standard", sizeof(used_locale)); /* XXX */ + return; + } + + /* Process the language file */ + while (fgets(buffer, sizeof(buffer), f)) + { + ++linecnt; + if (buffer[0] == ';') + continue; /* that's a comment */ + + if ((ident = strpbrk(buffer, "\r\n")) != NULL) + *ident = '\0'; + + /* skip spaces if there are any */ + for (ident = buffer; *ident == ' ' || *ident == '\t'; ident++)/* null */; + if (*ident == '\0') + continue; /* empty line */ + + /* skip after the reply identificator */ + for (reply = ident; *reply != ' ' && *reply != '\t' && *reply != ':'; + reply++) + if (*reply == '\0') goto error; + + if (*reply == ' ' || *reply == '\t') + { + for (*reply++ = '\0'; *reply == ' ' || *reply == '\t'; reply++); + if (*reply != ':') + { + error: + ilog(LOG_TYPE_IRCD, "Invalid line in language file (%s.lang, %d)", + locale, linecnt); + res = 0; + continue; + } + } + else + *reply++ = '\0'; + if (*ident == '\0') + goto error; + + /* skip to the beginning of reply */ + while (*reply == ' ' || *reply == '\t') reply++; + if (*reply == '\0') + goto error; + + for (i = 0; i <= ERR_LAST_ERR_MSG; i++) + { + if (replies[i].name != NULL) + { + if (irccmp(replies[i].name, ident) == 0) + { + if (!change_reply(locale, linecnt, i, reply)) res = 0; + i = -1; + break; + } + } + } + if (i != -1) + { + ilog(LOG_TYPE_IRCD, + "Unknown numeric %s (%s.lang, %d)", ident, locale, linecnt); + res = 0; + } + } + fclose(f); + + strlcpy(used_locale, locale, sizeof(used_locale)); + if (!res) + sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE, + "Language file [%s] contains " + "errors, check server log file for more details", + used_locale); +} + +/* Returns the name of current locale. */ +const char * +get_locale(void) +{ + return used_locale; +} |