/* * Receive and process server output from @sock. * Return number of characters received on success, -1 on error. */ static int recv_output(int sock) { /* * Read a chunk of server output and feed its characters into a * simple state machine. * Initial state is SCANNING_ID. * In state SCANNING_ID, buffer the character. If it's a space, * decode the id that has been buffered, and enter state BUFFERING * or COPYING depending on its value. * In state BUFFERING, buffer the character. If it's newline, * pass id and buffered text to servercmd(), then enter state * SCANNING_ID. * In state COPYING, pass the character to outch(). If it's * newline, enter state SCANNING_ID. */ static enum { SCANNING_ID, BUFFERING, COPYING } state = SCANNING_ID; static int id; static struct lbuf lbuf; char buf[4096]; ssize_t n; int i, ch, len; char *line; n = read(sock, buf, sizeof(buf)); if (n < 0) return -1; for (i = 0; i < n; i++) { ch = buf[i]; switch (state) { case SCANNING_ID: if (ch == '\n') { /* FIXME gripe unexpected! */ lbuf_init(&lbuf); break; } lbuf_putc(&lbuf, ch); if (ch != ' ') break; line = lbuf_line(&lbuf); id = parseid(line); lbuf_init(&lbuf); switch (id) { case C_PROMPT: case C_FLUSH: case C_EXECUTE: case C_EXIT: case C_FLASH: case C_INFORM: case C_PIPE: case C_REDIR: state = BUFFERING; break; default: /* unknown or unexpected id, treat like C_DATA */ case C_DATA: state = COPYING; break; } break; case BUFFERING: len = lbuf_putc(&lbuf, ch); if (len) { line = lbuf_line(&lbuf); servercmd(id, line, len); lbuf_init(&lbuf); state = SCANNING_ID; } break; case COPYING: outch(ch); if (ch == '\n') state = SCANNING_ID; } } return n; }
int main(int argc, char *argv[]) { FILE *po, *lng; char *lngname, *p, line[LINELEN], translation[STRLEN], name[LINELEN]; int hasid, hasstr, hasname, hasline, headerdone, intranssection, usehash; int hasheader, haslngname, haslngcode, hasctxt, hasmsgctxt; int strnum, fuzzyline, cformatline, conflictline, namehash; time_t nowtime; struct tm *timestruct_p; if ((argc < 2 || argc > 3) || '/' == argv[1][0] || '-' == argv[1][0]) { printf("Usage: %s PO-file [nohash]\n\n" "Converts the Opera PO file specified on the command line " "into a simple LNG\n" "file suitable for internal testing.\n\n" "Write \"nohash\" as the second parameter to not use hashed " "identifiers\n" "(before Opera 9).\n\n" "Copyright (C) 2003-2011 Opera Software ASA. Not to be " "distributed.\n" #if defined __DATE__ && defined __TIME__ "Built " __DATE__ " " __TIME__ "\n" #endif , argv[0]); return 0; } /* Check for nohash flag */ if (3 == argc) { if (0 == strcmp(argv[2], "nohash")) { usehash = 0; } else { warning(0, "Invalid argument: %s\n", argv[2]); return 1; } } else { usehash = 1; } /* Construct output file name */ lngname = malloc(strlen(argv[1]) + 5); strcpy(lngname, argv[1]); p = strrchr(lngname, '.'); if (!p) { warning(0, "Malformed PO file name %s: no full stop.\n", argv[1]); return 1; } strcpy(p, ".lng"); poname = argv[1]; if (0 == strcmp(lngname, poname)) { warning(0, "Malformed PO file name %s: ends in \".lng\".\n", poname); return 1; } /* Open input */ printf("Opening %s\n", poname); po = fopen(poname, "rt"); if (!po) { warning(0, "Cannot open %s: %s.\n", poname, strerror(errno)); return 2; } /* Create output */ printf("Creating %s\n", lngname); lng = fopen(lngname, "wt"); if (!lng) { warning(0, "Cannot create %s: %s.\n", lngname, strerror(errno)); return 2; } nowtime = time(NULL); timestruct_p = localtime(&nowtime); fprintf(lng, "; Opera language file version 2.0\n" "; For internal testing only, may not be distributed.\n" "; Copyright (C) 1995-%u Opera Software ASA. All rights reserved.\n\n" "[Info]\n", timestruct_p->tm_year + 1900); hasid = FALSE; hasstr = FALSE; hasname = FALSE; headerdone = FALSE; intranssection = FALSE; hasheader = FALSE; haslngname = FALSE; haslngcode = FALSE; hasctxt = FALSE; hasmsgctxt = FALSE; fuzzyline = 0; cformatline = 0; conflictline = 0; /* Read PO file and transform */ linenum = 0; do { hasline = (NULL != fgets(line, LINELEN, po)); ++ linenum; if (hasline && 0 == strncmp(line, "#: ", 3)) { /* New entry starting */ char *colon = strchr(line + 3, ':'); if (colon) { hasname = TRUE; namehash = hash(line + 3, colon - line - 3); strncpy(name, line + 3, colon - line - 3); name[colon - line - 3] = 0; } else { warning(linenum, "Malformed header.\n"); } } else if (hasline && !hasctxt && 0 == strncmp(line, "msgctxt ", 8)) { hasmsgctxt = TRUE; if (!usehash) { warning(linenum, "Nohash mode not supported for msgctxt.\n"); return 1; } /* Make sure context matches "#:" line */ if (hasname) { char *firstquote, *lastquote; /* Get context name */ firstquote = strchr(line, '"'); lastquote = strrchr(line, '"'); if (firstquote && lastquote > firstquote + 1) { if (hash(firstquote + 1, lastquote - firstquote - 1) != namehash) { warning(linenum, "Malformed PO file: invalid msgctxt.\n"); return 1; } } hasctxt = TRUE; } else { warning(linenum, "Malformed header.\n"); } } else if (hasline && 0 == strncmp(line, "msgid ", 6)) { /* New entry starting */ hasid = TRUE; hasstr = FALSE; strnum = 0; /* Check if we are done with the header */ if (!headerdone && strstr(line, "::") != NULL) { headerdone = TRUE; } if (!headerdone) { /* Meta data */ if (strstr(line, "<LanguageName>") != NULL) { strnum = ID_LANGUAGENAME; haslngname = TRUE; } else if (strstr(line, "<LanguageCode>") != NULL) { strnum = ID_LANGUAGECODE; haslngcode = TRUE; } else if (0 == strcmp(line, "msgid \"\"\n") || 0 == strcmp(line, "msgid \"\"\r\n") ) { /* Do nothing with the initial header */ hasid = FALSE; } else { warning(linenum, "Cannot parse line:\n %s", line); } } else { /* Standard string, get the id number */ if (hasmsgctxt) { strnum = -1; } else { hasmsgctxt = FALSE; strnum = parseid(line); } switch (strnum) { case -1: /* Not found */ strnum = hasctxt ? namehash : 0; break; case -2: /* Syntax error */ hasid = FALSE; break; } } } else if (hasline && hasid && 0 == strncmp(line, "msgstr ", 7)) { char *firstquote, *lastquote; /* Begin a new translated string */ hasstr = TRUE; translation[0] = 0; /* Get data */ firstquote = strchr(line, '"'); lastquote = strrchr(line, '"'); if (lastquote > firstquote + 1) { if (lastquote - firstquote > STRLEN) { warning(linenum, "Translated string too long, ignored:\n %s", line); } else { memcpy(translation, firstquote + 1, lastquote - firstquote - 1); translation[lastquote - firstquote - 1] = 0; } } } else if (hasline && (hasid || hasstr) && '"' == line[0]) { if (0 == strnum && hasid && !hasstr) { /* Retrieve ID from first split line */ strnum = parseid(line); if (strnum < 0 && (!usehash || strnum != namehash)) { /* There should have been an ID here, cannot parse entry */ warning(linenum, "Cannot parse entry, invalid identifier."); hasid = FALSE; } } else if (hasstr) { /* Continue translated string */ char *firstquote = strchr(line, '"'); char *lastquote = strrchr(line, '"'); if (lastquote > firstquote + 1) { if (lastquote - firstquote + strlen(translation) > STRLEN) { warning(linenum, "Translated string too long, " "ignored:\n %s\n", line); } else { size_t old_strlen = strlen(translation); memcpy(translation + old_strlen, firstquote + 1, lastquote - firstquote - 1); translation[old_strlen + lastquote - firstquote - 1] = 0; } } } } else if (hasid && hasstr) { /* Report any delayed errors */ if (fuzzyline) { if (cformatline) { warning(fuzzyline, "Fuzzy c-format string discarded for %d.\n", strnum); } else { warning(fuzzyline, "Fuzzy translation for %d.\n", strnum); } } if (conflictline) { warning(conflictline, "Translation conflict for %d.\n", strnum); } /* We're done with the entry, print it to the file */ if (!headerdone && strnum < 0) { /* Special header strings */ switch (strnum) { case ID_LANGUAGENAME: if (!*translation) { warning(linenum - 1, "Language name empty.\n"); } else if (*translation == '<') { warning(linenum - 1, "Language name starts with \"<\".\n"); } fprintf(lng, "LanguageName=\"%s (testing)\"\n", translation); break; case ID_LANGUAGECODE: if (!*translation) { warning(linenum - 1, "Language code empty.\n"); } else if (*translation == '<') { warning(linenum - 1, "Language code starts with \"<\".\n"); } else if (!islower(*(unsigned char *) translation) || !islower(*(unsigned char *) &translation[1]) || !('_' == translation[2] || 0 == translation[2])) { warning(linenum - 1, "Language code not in ISO format:\n %s\n", translation); } fprintf(lng, "Language=\"%s\"\n", translation); break; } if (hasheader && haslngname && haslngcode) { headerdone = TRUE; } } else if (hasname && headerdone && (strnum > 0 || (strnum < 0 && strnum == namehash))) { /* Regular translated string */ if (namehash == 1850176044 /* hash("S_HTML_DIRECTION") */) { /* Magic for S_HTML_DIRECTION */ if (strcmp(translation, "ltr") == 0 || strcmp(translation, "rtl") == 0) { fprintf(lng, intranssection ? "\n[Info]\nDirection=%d\n" : "Direction=%d\n", strcmp(translation, "rtl") == 0); intranssection = FALSE; } else { warning(linenum - 1, "Bad S_HTML_DIRECTION string: \"%s\".\n", translation); } } if (!intranssection) { fputs("\n[Translation]\n\n", lng); intranssection = TRUE; } fprintf(lng, (usehash && !hasctxt) ? "; %s:%d\n" : "; %s\n", name, strnum); if (!usehash) { namehash = strnum; } if (fuzzyline && cformatline) { fprintf(lng, "%d=\"[FUZZY]\"\n", namehash); } else if (fuzzyline) { fprintf(lng, "%d=\"[FUZZY]%s\"\n", namehash, translation); } else if (0 == *translation) { warning(linenum - 1, "Missing translation for %d.\n", strnum); fprintf(lng, "; Untranslated %d=\"%s\"\n", namehash, translation); } else { if (0 == strcmp(translation, "[]")) { /* Special convention for empty strings */ translation[0] = 0; } fprintf(lng, "%d=\"%s\"\n", namehash, translation); } } else if (!hasname) { /* PO header line missing/broken */ warning(linenum, "Missing header, entry for %d discarded.\n", strnum); } else { /* Sanity check */ warning(linenum, "Internal program error: id number == %d.\n", strnum); } /* Prepare for next entry */ hasstr = FALSE; hasid = FALSE; hasname = FALSE; hasctxt = FALSE; fuzzyline = 0; cformatline = 0; conflictline = 0; } else if (hasline && !headerdone && 0 == strncmp(line, "\"Content-Type: ", 15)) { /* Extract charset information from the PO file */ char *charset = strstr(line, "charset="); if (charset) { char *backslash = strchr(charset + 8, '\\'); if (backslash) { fprintf(lng, "Charset=\"%.*s\"\n", (int) (backslash - charset - 8), charset + 8); } else { warning(linenum, "Cannot parse charset:\n %s\n", charset); } hasheader = TRUE; } } else if (hasline && !headerdone && 0 == strncmp(line, "\"Project-Id-Version: ", 21)) { /* Extract database information from the PO file */ char *dbversion = strstr(line, "dbversion "); if (dbversion) { char *backslash = strchr(dbversion + 10, '\\'); if (backslash) { fprintf(lng, "DB.version=\"%.*s\"\n", (int) (backslash - dbversion - 10), dbversion + 10); } else { warning(linenum, "Cannot parse dbversion:\n %s\n", dbversion); } hasheader = TRUE; } } else if (hasline && !hasid && '#' == line[0]) { /* Check fuzzy flag */ if (strstr(line, ", fuzzy") != NULL) { fuzzyline = linenum; } /* Check c-format flag */ if (strstr(line, ", c-format") != NULL) { cformatline = TRUE; } /* Check translation conflict flag */ if (0 == strncmp(line, "# Translation conflict:", 23)) { conflictline = linenum; } } } while (hasline); /* Finish up */ fclose(po); fclose(lng); puts("Done."); return 0; }
int main(int argc, char *argv[]) { struct stat from_sb, to_sb; mode_t *set; u_long fset; int ch, no_target; u_int iflags; char *p; const char *to_name; iflags = 0; group = owner = NULL; while ((ch = getopt(argc, argv, "B:bCcD:df:g:h:l:M:m:N:o:pSsT:Uv")) != -1) switch((char)ch) { case 'B': suffix = optarg; /* FALLTHROUGH */ case 'b': dobackup = 1; break; case 'C': docompare = 1; break; case 'c': /* For backwards compatibility. */ break; case 'D': destdir = optarg; break; case 'd': dodir = 1; break; case 'f': haveopt_f = 1; fflags = optarg; break; case 'g': haveopt_g = 1; group = optarg; break; case 'h': digest = optarg; break; case 'l': for (p = optarg; *p != '\0'; p++) switch (*p) { case 's': dolink &= ~(LN_HARD|LN_MIXED); dolink |= LN_SYMBOLIC; break; case 'h': dolink &= ~(LN_SYMBOLIC|LN_MIXED); dolink |= LN_HARD; break; case 'm': dolink &= ~(LN_SYMBOLIC|LN_HARD); dolink |= LN_MIXED; break; case 'a': dolink &= ~LN_RELATIVE; dolink |= LN_ABSOLUTE; break; case 'r': dolink &= ~LN_ABSOLUTE; dolink |= LN_RELATIVE; break; default: errx(1, "%c: invalid link type", *p); /* NOTREACHED */ } break; case 'M': metafile = optarg; break; case 'm': haveopt_m = 1; if (!(set = setmode(optarg))) errx(EX_USAGE, "invalid file mode: %s", optarg); mode = getmode(set, 0); free(set); break; case 'N': if (!setup_getid(optarg)) err(EX_OSERR, "Unable to use user and group " "databases in `%s'", optarg); break; case 'o': haveopt_o = 1; owner = optarg; break; case 'p': docompare = dopreserve = 1; break; case 'S': safecopy = 1; break; case 's': dostrip = 1; break; case 'T': tags = optarg; break; case 'U': dounpriv = 1; break; case 'v': verbose = 1; break; case '?': default: usage(); } argc -= optind; argv += optind; /* some options make no sense when creating directories */ if (dostrip && dodir) { warnx("-d and -s may not be specified together"); usage(); } if (getenv("DONTSTRIP") != NULL) { warnx("DONTSTRIP set - will not strip installed binaries"); dostrip = 0; } /* must have at least two arguments, except when creating directories */ if (argc == 0 || (argc == 1 && !dodir)) usage(); if (digest != NULL) { if (strcmp(digest, "none") == 0) { digesttype = DIGEST_NONE; } else if (strcmp(digest, "md5") == 0) { digesttype = DIGEST_MD5; } else if (strcmp(digest, "rmd160") == 0) { digesttype = DIGEST_RIPEMD160; } else if (strcmp(digest, "sha1") == 0) { digesttype = DIGEST_SHA1; } else if (strcmp(digest, "sha256") == 0) { digesttype = DIGEST_SHA256; } else if (strcmp(digest, "sha512") == 0) { digesttype = DIGEST_SHA512; } else { warnx("unknown digest `%s'", digest); usage(); } } /* need to make a temp copy so we can compare stripped version */ if (docompare && dostrip) safecopy = 1; /* get group and owner id's */ if (group != NULL && !dounpriv) { if (gid_from_group(group, &gid) == -1) { id_t id; if (!parseid(group, &id)) errx(1, "unknown group %s", group); gid = id; } } else gid = (gid_t)-1; if (owner != NULL && !dounpriv) { if (uid_from_user(owner, &uid) == -1) { id_t id; if (!parseid(owner, &id)) errx(1, "unknown user %s", owner); uid = id; } } else uid = (uid_t)-1; if (fflags != NULL && !dounpriv) { if (strtofflags(&fflags, &fset, NULL)) errx(EX_USAGE, "%s: invalid flag", fflags); iflags |= SETFLAGS; } if (metafile != NULL) { if ((metafp = fopen(metafile, "a")) == NULL) warn("open %s", metafile); } else digesttype = DIGEST_NONE; if (dodir) { for (; *argv != NULL; ++argv) install_dir(*argv); exit(EX_OK); /* NOTREACHED */ } to_name = argv[argc - 1]; no_target = stat(to_name, &to_sb); if (!no_target && S_ISDIR(to_sb.st_mode)) { if (dolink & LN_SYMBOLIC) { if (lstat(to_name, &to_sb) != 0) err(EX_OSERR, "%s vanished", to_name); if (S_ISLNK(to_sb.st_mode)) { if (argc != 2) { errno = ENOTDIR; err(EX_USAGE, "%s", to_name); } install(*argv, to_name, fset, iflags); exit(EX_OK); } } for (; *argv != to_name; ++argv) install(*argv, to_name, fset, iflags | DIRECTORY); exit(EX_OK); /* NOTREACHED */ } /* can't do file1 file2 directory/file */ if (argc != 2) { if (no_target) warnx("target directory `%s' does not exist", argv[argc - 1]); else warnx("target `%s' is not a directory", argv[argc - 1]); usage(); } if (!no_target && !dolink) { if (stat(*argv, &from_sb)) err(EX_OSERR, "%s", *argv); if (!S_ISREG(to_sb.st_mode)) { errno = EFTYPE; err(EX_OSERR, "%s", to_name); } if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) errx(EX_USAGE, "%s and %s are the same file", *argv, to_name); } install(*argv, to_name, fset, iflags); exit(EX_OK); /* NOTREACHED */ }