#include #include #include #include #include "gettext.h" typedef struct _MSG { u32 id; char* msgstr; struct _MSG *next; } MSG; static MSG *baseMSG=0; #define HASHWORDBITS 32 /* Defines the so called `hashpjw' function by P.J. Weinberger [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, 1986, 1987 Bell Telephone Laboratories, Inc.] */ //static inline u32 hash_string (const char *str_param) { u32 hval, g; const char *str = str_param; /* Compute the hash value for the given string. */ hval = 0; while (*str != '\0') { hval <<= 4; hval += (u8) *str++; g = hval & ((u32) 0xf << (HASHWORDBITS - 4)); if (g != 0) { hval ^= g >> (HASHWORDBITS - 8); hval ^= g; } } return hval; } // limit string length to max n chars u32 hash_string_n (const char *str_param, int n) { u32 hval, g; const char *str = str_param; /* Compute the hash value for the given string. */ hval = 0; while (n && *str != '\0') { hval <<= 4; hval += (u8) *str++; g = hval & ((u32) 0xf << (HASHWORDBITS - 4)); if (g != 0) { hval ^= g >> (HASHWORDBITS - 8); hval ^= g; } n--; } return hval; } /* Expand some escape sequences found in the argument string. */ static char * expand_escape (const char *str) { char *retval, *rp; const char *cp = str; retval = (char *) malloc (strlen (str)+1); if (retval==NULL) return NULL; rp = retval; while (cp[0] != '\0' && cp[0] != '\\') *rp++ = *cp++; if (cp[0] == '\0') goto terminate; do { /* Here cp[0] == '\\'. */ switch (*++cp) { case '\"': /* " */ *rp++ = '\"'; ++cp; break; case 'a': /* alert */ *rp++ = '\a'; ++cp; break; case 'b': /* backspace */ *rp++ = '\b'; ++cp; break; case 'f': /* form feed */ *rp++ = '\f'; ++cp; break; case 'n': /* new line */ *rp++ = '\n'; ++cp; break; case 'r': /* carriage return */ *rp++ = '\r'; ++cp; break; case 't': /* horizontal tab */ *rp++ = '\t'; ++cp; break; case 'v': /* vertical tab */ *rp++ = '\v'; ++cp; break; case '\\': *rp = '\\'; ++cp; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { int ch = *cp++ - '0'; if (*cp >= '0' && *cp <= '7') { ch *= 8; ch += *cp++ - '0'; if (*cp >= '0' && *cp <= '7') { ch *= 8; ch += *cp++ - '0'; } } *rp = ch; } break; default: *rp = '\\'; break; } while (cp[0] != '\0' && cp[0] != '\\') *rp++ = *cp++; } while (cp[0] != '\0'); /* Terminate string. */ terminate: *rp = '\0'; return retval; } static MSG *findMSG(u32 id) { MSG *msg; for (msg=baseMSG; msg; msg=msg->next) { if (msg->id == id) return msg; } return NULL; } static MSG *setMSG(const char *msgid, const char *msgstr) { if (!*msgstr) return NULL; char *tmp = expand_escape(msgid); u32 id = hash_string(tmp); free(tmp); MSG *msg = findMSG(id); if (!msg) { msg = (MSG *)malloc(sizeof(MSG)); msg->id = id; msg->msgstr = NULL; msg->next = baseMSG; baseMSG = msg; } if (msg) { if (msgstr) { if (msg->msgstr) free(msg->msgstr); //msg->msgstr = strdup(msgstr); msg->msgstr = expand_escape(msgstr); } return msg; } return NULL; } void gettextCleanUp(void) { while (baseMSG) { MSG *nextMsg =baseMSG->next; free(baseMSG->msgstr); free(baseMSG); baseMSG = nextMsg; } } char *str_cat_realloc(char *str, char *cat) { char *newstr = malloc(strlen(str) + strlen(cat) + 1); strcpy(newstr, str); strcat(newstr, cat); free(str); return newstr; } bool gettextLoadLanguage(const char* langFile) { FILE *f; char line[200]; char *lastID=NULL; char *lastSTR=NULL; char *str, *end; gettextCleanUp(); f = fopen(langFile, "r"); if (!f) return false; while (fgets(line, sizeof(line), f)) { // lines starting with # are comments //if (line[0] == '#') // continue; if (strncmp(line, "msgid \"", 7) == 0) { char *msgid; if (lastSTR) { free(lastSTR); lastSTR=NULL; } if (lastID) { free(lastID); lastID=NULL; } msgid = &line[7]; end = strrchr(msgid, '"'); if (end && end >= msgid) { *end = 0; lastID = strdup(msgid); } } else if (line[0] == '"' && lastID && !lastSTR) { // multiline continuation of msgid str = &line[1]; end = strrchr(str, '"'); if (end && end >= str) { *end = 0; lastID = str_cat_realloc(lastID, str); } } else if (strncmp(line, "msgstr \"", 8) == 0) { if (lastID == NULL) continue; str = &line[8]; end = strrchr(str, '"'); if (end && end >= str) { *end = 0; lastSTR = strdup(str); } } else if (line[0] == '"' && lastID && lastSTR) { // multiline continuation of msgstr str = &line[1]; end = strrchr(str, '"'); if (end && end >= str) { *end = 0; lastSTR = str_cat_realloc(lastSTR, str); } } else if (lastID && lastSTR) { setMSG(lastID, lastSTR); free(lastID); free(lastSTR); lastID=NULL; lastSTR=NULL; } } // end of file, add last msg: if (lastID && lastSTR) { setMSG(lastID, lastSTR); free(lastID); free(lastSTR); lastID=NULL; lastSTR=NULL; } fclose(f); return true; } const char *gettext(const char *msgid) { MSG *msg = findMSG(hash_string(msgid)); if (msg && msg->msgstr) msgid = msg->msgstr; // skip ~~ char *xx = strstr(msgid, "~~"); if (xx) msgid = xx + 2; return msgid; } char** translate_array(int n, char *src[], char *dest[]) { int i; if (n && src && dest) { for (i=0; i