diff options
Diffstat (limited to 'src/numeric.c')
-rw-r--r-- | src/numeric.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/src/numeric.c b/src/numeric.c new file mode 100644 index 0000000..2a1042d --- /dev/null +++ b/src/numeric.c @@ -0,0 +1,226 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * numeric.c: Numeric handling functions. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * This program 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. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * $Id$ + */ + +#include "stdinc.h" + +#include "numeric.h" +#include "irc_string.h" +#include "memory.h" +#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); + DupString(replies[reply].translated, 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, "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; +} |