char* translate(const char* loc, const char* cmd, const char* cat, const char* msg) { register char* r; char* t; int p; int oerrno; Catalog_t* cp; Message_t* mp; oerrno = errno; r = (char*)msg; /* * quick out */ if (!cmd && !cat) goto done; if (cmd && (t = strrchr(cmd, '/'))) cmd = (const char*)(t + 1); /* * initialize the catalogs dictionary */ if (!state.catalogs) { if (state.error) goto done; if (!(state.tmp = sfstropen())) { state.error = 1; goto done; } if (!(state.catalogs = dtopen(&state.catalog_disc, Dtset))) { sfclose(state.tmp); state.error = 1; goto done; } if (streq(loc, "debug")) state.debug = loc; } /* * get the message * or do we have to spell it out for you */ if ((!cmd || !(mp = match(cmd, msg))) && (!cat || !(mp = match(cat, msg))) && (!error_info.catalog || !(mp = match(error_info.catalog, msg))) && (!ast.id || !(mp = match(ast.id, msg))) || !(cp = mp->cat)) { #if DEBUG_trace > 1 sfprintf(sfstderr, "AHA#%d:%s cmd %s cat %s:%s id %s msg `%s'\n", __LINE__, __FILE__, cmd, cat, error_info.catalog, ast.id, msg); #endif goto done; } /* * adjust for the current locale */ #if DEBUG_trace sfprintf(sfstderr, "AHA#%d:%s cp->locale `%s' %p loc `%s' %p\n", __LINE__, __FILE__, cp->locale, cp->locale, loc, loc); #endif if (cp->locale != loc) { cp->locale = loc; if (cp->cat != NOCAT) catclose(cp->cat); if ((cp->cat = find(cp->locale, cp->name)) == NOCAT) cp->debug = streq(cp->locale, "debug"); else cp->debug = 0; #if DEBUG_trace sfprintf(sfstderr, "AHA#%d:%s cp->cat %p cp->debug %d NOCAT %p\n", __LINE__, __FILE__, cp->cat, cp->debug, NOCAT); #endif } if (cp->cat == NOCAT) { if (cp->debug) { p = tempget(state.tmp); sfprintf(state.tmp, "(%s,%d,%d)", cp->name, mp->set, mp->seq); r = tempuse(state.tmp, p); } else if (ast.locale.set & AST_LC_debug) { p = tempget(state.tmp); sfprintf(state.tmp, "(%s,%d,%d)%s", cp->name, mp->set, mp->seq, r); r = tempuse(state.tmp, p); } goto done; } /* * get the translated message */ r = catgets(cp->cat, mp->set, mp->seq, msg); if (ast.locale.set & AST_LC_translate) sfprintf(sfstderr, "translate locale=%s catalog=%s set=%d seq=%d \"%s\" => \"%s\"\n", cp->locale, cp->name, mp->set, mp->seq, msg, r == (char*)msg ? "NOPE" : r); if (r != (char*)msg) { if (streq(r, (char*)msg)) r = (char*)msg; else if (strcmp(fmtfmt(r), fmtfmt(msg))) { sfprintf(sfstderr, "locale %s catalog %s message %d.%d \"%s\" does not match \"%s\"\n", cp->locale, cp->name, mp->set, mp->seq, r, msg); r = (char*)msg; } } if (ast.locale.set & AST_LC_debug) { p = tempget(state.tmp); sfprintf(state.tmp, "(%s,%d,%d)%s", cp->name, mp->set, mp->seq, r); r = tempuse(state.tmp, p); } done: if (r == (char*)msg && loc == state.debug) { p = tempget(state.tmp); sfprintf(state.tmp, "(%s,%s,%s,\"%s\")", loc, cmd, cat, r); r = tempuse(state.tmp, p); } errno = oerrno; return r; }
void* _fmtdispatch(Fmt *f, const void *fmt, int isrunes) { Rune rune, r; int i, n, w, p; uint32_t fl; const void *ret; w = f->width; p = f->prec; fl = f->flags; f->flags = 0; f->width = f->prec = 0; for(;;){ if(isrunes){ r = *(Rune*)fmt; fmt = (Rune*)fmt + 1; }else{ fmt = (char*)fmt + chartorune(&rune, fmt); r = rune; } f->r = r; switch(r){ case '\0': ret = nil; goto end; case '.': f->flags |= FmtWidth|FmtPrec; continue; case '0': if(!(f->flags & FmtWidth)){ f->flags |= FmtZero; continue; } /* fall through */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': i = 0; while(r >= '0' && r <= '9'){ i = i * 10 + r - '0'; if(isrunes){ r = *(Rune*)fmt; fmt = (Rune*)fmt + 1; }else{ r = *(char*)fmt; fmt = (char*)fmt + 1; } } if(isrunes) fmt = (Rune*)fmt - 1; else fmt = (char*)fmt - 1; numflag: if(f->flags & FmtWidth){ f->flags |= FmtPrec; f->prec = i; }else{ f->flags |= FmtWidth; f->width = i; } continue; case '*': i = va_arg(f->args, int); if(i < 0){ /* * negative precision => * ignore the precision. */ if(f->flags & FmtPrec){ f->flags &= ~FmtPrec; f->prec = 0; continue; } i = -i; f->flags |= FmtLeft; } goto numflag; } n = (*fmtfmt(r))(f); if(n < 0){ ret = nil; break; } if(n == 0){ ret = fmt; break; } } end: f->width = w; f->prec = p; f->flags = fl; return (void*)ret; }
int main(int argc, char** argv) { register Mc_t* mc; register char* s; register char* t; register int c; register int q; register int i; int num; char* b; char* e; char* catfile; char* msgfile; Sfio_t* sp; Sfio_t* mp; Sfio_t* tp; Xl_t* px; Xl_t* bp; Xl_t* xp = 0; int format = 0; int list = 0; int set = 0; NoP(argc); error_info.id = "msggen"; for (;;) { switch (optget(argv, usage)) { case 'f': format = list = 1; continue; case 'l': list = 1; continue; case 's': set = 1; continue; case '?': error(ERROR_USAGE|4, "%s", opt_info.arg); continue; case ':': error(2, "%s", opt_info.arg); continue; } break; } argv += opt_info.index; if (error_info.errors || !(catfile = *argv++)) error(ERROR_USAGE|4, "%s", optusage(NiL)); /* * set and list only need catfile */ if (set) { sfprintf(sfstdout, "%d\n", mcindex(catfile, NiL, NiL, NiL)); return error_info.errors != 0; } else if (list) { if (!(sp = sfopen(NiL, catfile, "r"))) error(ERROR_SYSTEM|3, "%s: cannot read catalog", catfile); if (!(mc = mcopen(sp))) error(ERROR_SYSTEM|3, "%s: catalog content error", catfile); sfclose(sp); if (format) { for (set = 1; set <= mc->num; set++) if (mc->set[set].num) { sfprintf(sfstdout, "$set %d\n", set); for (num = 1; num <= mc->set[set].num; num++) if (s = mc->set[set].msg[num]) sfprintf(sfstdout, "%d \"%s\"\n", num, fmtfmt(s)); } } else { if (*mc->translation) { ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "$translation "); sfprintf(sfstdout, "%s", mc->translation); ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "\n"); } ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "$quote \"\n"); for (set = 1; set <= mc->num; set++) if (mc->set[set].num) { ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "$set %d\n", set); for (num = 1; num <= mc->set[set].num; num++) if (s = mc->set[set].msg[num]) { ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "%d \"", num); while (c = *s++) { /*INDENT...*/ switch (c) { case 0x22: /* " */ case 0x5C: /* \ */ sfputc(sfstdout, 0x5C); break; case 0x07: /* \a */ c = 0x61; sfputc(sfstdout, 0x5C); break; case 0x08: /* \b */ c = 0x62; sfputc(sfstdout, 0x5C); break; case 0x0A: /* \n */ c = 0x6E; sfputc(sfstdout, 0x5C); break; case 0x0B: /* \v */ c = 0x76; sfputc(sfstdout, 0x5C); break; case 0x0C: /* \f */ c = 0x66; sfputc(sfstdout, 0x5C); break; case 0x0D: /* \r */ c = 0x72; sfputc(sfstdout, 0x5C); break; } /*...UNDENT*/ sfputc(sfstdout, c); } ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "\"\n"); } } } mcclose(mc); return error_info.errors != 0; } else if (!(msgfile = *argv++) || *argv) error(3, "exactly one message file must be specified"); /* * open the files and handles */ if (!(tp = sfstropen())) error(ERROR_SYSTEM|3, "out of space [string stream]"); if (!(mp = sfopen(NiL, msgfile, "r"))) error(ERROR_SYSTEM|3, "%s: cannot read message file", msgfile); sp = sfopen(NiL, catfile, "r"); if (!(mc = mcopen(sp))) error(ERROR_SYSTEM|3, "%s: catalog content error", catfile); if (sp) sfclose(sp); xp = translation(xp, mc->translation); /* * read the message file */ q = 0; set = 1; error_info.file = msgfile; while (s = sfgetr(mp, '\n', 1)) { error_info.line++; if (!*s) continue; if (*s == '$') { if (!*++s || isspace(*s)) continue; for (t = s; *s && !isspace(*s); s++); if (*s) *s++ = 0; if (streq(t, "delset")) { while (isspace(*s)) s++; num = (int)strtol(s, NiL, 0); if (num < mc->num && mc->set[num].num) for (i = 1; i <= mc->set[num].num; i++) mcput(mc, num, i, NiL); } else if (streq(t, "quote")) q = *s ? *s : 0; else if (streq(t, "set")) { while (isspace(*s)) s++; num = (int)strtol(s, &e, 0); if (e != s) set = num; else error(2, "set number expected"); } else if (streq(t, "translation")) xp = translation(xp, s); } else { t = s + sfvalue(mp); num = (int)strtol(s, &e, 0); if (e != s) { s = e; if (!*s) { if (mcput(mc, set, num, NiL)) error(2, "(%d,%d): cannot delete message", set, num); } else if (isspace(*s++)) { if (t > (s + 1) && *(t -= 2) == '\\') { sfwrite(tp, s, t - s); while (s = sfgetr(mp, '\n', 0)) { error_info.line++; t = s + sfvalue(mp); if (t <= (s + 1) || *(t -= 2) != '\\') break; sfwrite(tp, s, t - s); } if (!(s = sfstruse(tp))) error(ERROR_SYSTEM|3, "out of space"); } if (q) { if (*s++ != q) { error(2, "(%d,%d): %c quote expected", set, num, q); continue; } b = t = s; while (c = *s++) { if (c == '\\') { c = chresc(s - 1, &e); s = e; if (c) *t++ = c; else error(1, "nul character ignored"); } else if (c == q) break; else *t++ = c; } if (*s) { error(2, "(%d,%d): characters after quote not expected", set, num); continue; } *t = 0; s = b; } if (mcput(mc, set, num, s)) error(2, "(%d,%d): cannot add message", set, num); } else error(2, "message text expected"); } else error(2, "message number expected"); } } error_info.file = 0; error_info.line = 0; /* * fix up the translation record */ if (xp) { t = ""; for (;;) { for (bp = 0, px = xp; px; px = px->next) if (px->date && (!bp || strcoll(bp->date, px->date) < 0)) bp = px; if (!bp) break; sfprintf(tp, "%s%s %s", t, bp->name, bp->date); t = ", "; bp->date = 0; } if (!(mc->translation = sfstruse(tp))) error(ERROR_SYSTEM|3, "out of space"); } /* * dump the catalog to a local temporary * rename if no errors */ if (!(s = pathtemp(NiL, 0, "", error_info.id, NiL)) || !(sp = sfopen(NiL, s, "w"))) error(ERROR_SYSTEM|3, "%s: cannot write catalog file", catfile); if (mcdump(mc, sp) || mcclose(mc) || sfclose(sp)) { remove(s); error(ERROR_SYSTEM|3, "%s: temporary catalog file write error", s); } remove(catfile); if (rename(s, catfile)) error(ERROR_SYSTEM|3, "%s: cannot rename from temporary catalog file %s", catfile, s); return error_info.errors != 0; }