Esempio n. 1
0
/*
 * 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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
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 */
}