#include #include #include #include "internal.h" #include PUBLIC LANG_STRING::LANG_STRING (char _lang, const char *_str) { lang = _lang; str.setfrom (_str); } PUBLIC LANG_STRING *LANG_STRINGS::getitem(int no) { return (LANG_STRING*)ARRAY::getitem(no); } PUBLIC TR_STRING::TR_STRING(const char *_id) { changed = 0; id.setfrom (_id); } /* Return the ID of the translation unit */ PUBLIC const char *TR_STRING::getid() { return id.get(); } /* Indicate if this translation unit has been modified (by msgscan). This implied that the ID is still in use. */ PUBLIC int TR_STRING::was_changed () { return changed; } PUBLIC void TR_STRING::reset_changed () { changed = 0; rstmodified(); } /* Return how many translation are available for this translation unit. An obsolete message may have 0 translations. */ PUBLIC int TR_STRING::getnblang() { return tb.getnb(); } /* Add a comment line to the TR_STRING definition. */ PUBLIC void TR_STRING::add2comment(const char *_comment) { comment.append (_comment); } /* Add a new translation for this message */ PUBLIC SSTRING *TR_STRING::settranslation (char lang, const char *str) { changed = 1; setmodified(); LANG_STRING *ta = gettranslation (lang); if (ta == NULL){ ta = new LANG_STRING (lang,str); tb.add (ta); }else{ ta->str.setfrom (str); } return &ta->str; } /* Get the message for a given language Return NULL if not available. */ PUBLIC LANG_STRING *TR_STRING::gettranslation (char lang) { LANG_STRING *ret = NULL; int n = tb.getnb(); for (int i=0; ilang == lang){ ret = t; break; } } return ret; } /* Remove one translation. */ PUBLIC void TR_STRING::deltranslation (char lang) { int n = tb.getnb(); for (int i=0; ilang == lang){ tb.remove_del (t); break; } } } /* Get the message for a given language Return NULL if not available. */ PUBLIC const char *TR_STRING::getmsg (char lang) { const char *ret = NULL; LANG_STRING *t = gettranslation (lang); if (t != NULL) ret = t->str.get(); return ret; } PUBLIC void TR_STRING::write (FILE *fout) { if (!comment.is_empty()){ fputs (comment.get(),fout); } fprintf (fout,"!%s\n",id.get()); int n = tb.getnb(); for (int i=0; ilang); const char *pt = t->str.get(); if (strlen (pt) < 80){ fputs (pt,fout); }else{ while (*pt != '\0'){ char car = *pt++; fputc (car,fout); if (car == '\\' && pt[0] == 'n'){ fputc ('n',fout); pt++; if (pt[0] != '\0') fputs ("\n +",fout); } } } fputc ('\n',fout); } } /* Record the string (file name) where the message was defined. */ PUBLIC void TR_STRING::setorigin(const char *str) { origin.setfrom (str); } /* Return the string (generally a file name) telling where the message was defined. */ PUBLIC const char *TR_STRING::getorigin() { return origin.get(); } PUBLIC TR_STRINGS::TR_STRINGS() { version = 0; } PUBLIC TR_STRING *TR_STRINGS::getitem(int no) { return (TR_STRING*)ARRAY::getitem(no); } /* Find a translation unit with a given ID Return NULL if not found. */ PUBLIC TR_STRING *TR_STRINGS::getitem(const char *id) { TR_STRING *ret = NULL; int n = getnb(); for (int i=0; igetid(),id)==0){ ret = t; break; } } return ret; } /* Read a string dictionary Return -1 if there was any errors */ PUBLIC int TR_STRINGS::read (const char *fname) { FILE *fin = vfopen (fname,"r"); int err = 0; if (fin != NULL){ char buf[1000]; /* #Specification: string dictionary / format The reference dictionary for the translation system is an ASCII file. This file contain one record for each string resource. Each record spans multiple line with the following format. Note that this is not the file used by the running program. A binary file is produced for each supported language. So here it is: # # comments # ... @version 0 !id :lang string ... +... :lang string ... # "lang" is a single letter. "string" follows "lang". The string may continue over several line. A line starting with a '+" is a continuation line. Everything after is the string, including white spaces. Empty lines are ignored. */ TR_STRING *cur = NULL; SSTRING *curmsg = NULL; int noline = 0; SSTRING comment; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ noline++; char *pt = str_skip (buf); /* #Specification: dictionary file / comments msgscan is trying to preserve empty lines and comments between translation units. Not much inside translation units */ if (pt[0] == '#' || pt[0] == '\0'){ comment.append (buf); }else{ strip_end (buf); if (pt[0] == '@'){ // Special commands pt = str_skip (pt+1); if (strncmp(pt,"version",7)==0 && isspace(pt[7])){ pt = str_skip(pt+7); version = atoi(pt); }else{ fprintf (stderr,"Invalid line %d: %s\n" ,noline,buf); err++; } }else if (pt[0] == '!'){ cur = new TR_STRING (str_skip(pt+1)); add (cur); cur->add2comment(comment.get()); comment.setfrom (""); }else if (pt[0] == ':'){ curmsg = cur->settranslation (pt[1] ,str_skip(pt+2)); }else if (pt[0] == '+'){ curmsg->append (pt+1); }else if (buf[0] != '\0'){ fprintf (stderr,"Invalid line %d: %s\n" ,noline,pt); err++; } } } fclose (fin); int n = getnb(); for (int i=0; ireset_changed(); } rstmodified(); } return err ? -1 : 0; } /* Write back the ASCII dictionary Return -1 if any error. */ PUBLIC int TR_STRINGS::write (const char *fname) { int ret = -1; FILE *fout = vfopen (fname,"w"); if (fout != NULL){ fprintf (fout,"@version %d\n",version); int n = getnb(); for (int i=0; iwrite (fout); } ret = fclose (fout); } return ret; } /* Write back the ASCII dictionary, modified entry first Return -1 if any error. */ PUBLIC int TR_STRINGS::write_mod (const char *fname) { int ret = -1; FILE *fout = vfopen (fname,"w"); if (fout != NULL){ fprintf (fout,"@version %d\n",version); int n = getnb(); int i; for (i=0; iwas_modified()) t->write (fout); } for (i=0; iwas_modified()) t->write (fout); } ret = fclose (fout); } return ret; } /* Write the header file */ PUBLIC int TR_STRINGS::writeh(const char *sysname, const char *fname) { int ret = -1; FILE *fout = vfopen (fname,"w"); if (fout != NULL){ fprintf (fout,"extern const char **_dictionary_%s;\n" ,sysname); fprintf (fout,"#ifndef DICTIONARY_REQUEST\n"); char dictsys[100]; sprintf (dictsys,"_dictionary_%s",sysname); fprintf (fout,"\t#define DICTIONARY_REQUEST \\\n" "\tconst char **%s;\\\n" "\tTRANSLATE_SYSTEM_REQ _dictionary_req_%s(\"%s\",%s,%d,%d);\\\n" "\tvoid dummy_dict_%s(){}\n" ,dictsys,sysname,sysname,dictsys,getnb(),version,sysname); fprintf (fout,"#endif\n"); fprintf (fout,"#ifndef MSG_U\n"); fprintf (fout,"\t#define MSG_U(id,m)\t%s[id]\n",dictsys); fprintf (fout,"\t#define MSG_B(id,m,n)\t%s[id]\n",dictsys); fprintf (fout,"\t#define MSG_R(id)\t%s[id]\n",dictsys); fprintf (fout,"\t#define P_MSG_U(id,m)\tnew_trans_notload(%s,id)\n",dictsys); fprintf (fout,"\t#define P_MSG_B(id,m,n)\tnew_trans_notload(%s,id)\n",dictsys); fprintf (fout,"\t#define P_MSG_R(id)\tnew_trans_notload(%s,id)\n",dictsys); fprintf (fout,"#endif\n"); int n = getnb(); for (int i=0; igetid(),i); } ret = fclose (fout); } return ret; } /* Record a version number only if it is higher than the current one. */ PUBLIC void TR_STRINGS::setversion (int ver) { if (ver > version) version = ver; } /* Return the version number of this dictionary. */ PUBLIC int TR_STRINGS::getversion () { return version; } /* Remove one translation for all messages. */ PUBLIC void TR_STRINGS::deltranslation (char lang) { int n = getnb(); for (int i=0; ideltranslation (lang); } } /* Show all obsolete message. */ PUBLIC void TR_STRINGS::showold (char deflang) { int n = getnb(); for (int i=0; igettranslation (deflang); if (l == NULL){ fprintf (stderr,"Obsolete message: %s\n",t->getid()); } } }