From 06a486fd6f5bfb765cdfc9f475677d08e8bbe95a Mon Sep 17 00:00:00 2001 From: jbj Date: Wed, 16 Sep 1998 21:17:27 +0000 Subject: [PATCH] More work with xref files. CVS patchset: 2322 CVS date: 1998/09/16 21:17:27 --- tools/fstrcmp.c | 636 +++++++++++++++++++++++++++++++++++++++++++++ tools/fstrcmp.h | 25 ++ tools/rpmgettext.c | 227 ++++++++++++++-- 3 files changed, 866 insertions(+), 22 deletions(-) create mode 100644 tools/fstrcmp.c create mode 100644 tools/fstrcmp.h diff --git a/tools/fstrcmp.c b/tools/fstrcmp.c new file mode 100644 index 000000000..b1f597127 --- /dev/null +++ b/tools/fstrcmp.c @@ -0,0 +1,636 @@ +/* Functions to make fuzzy comparisons between strings + Copyright (C) 1988, 1989, 1992, 1993, 1995 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + + Derived from GNU diff 2.7, analyze.c et al. + + The basic algorithm is described in: + "An O(ND) Difference Algorithm and its Variations", Eugene Myers, + Algorithmica Vol. 1 No. 2, 1986, pp. 251-266; + see especially section 4.2, which describes the variation used below. + + The basic algorithm was independently discovered as described in: + "Algorithms for Approximate String Matching", E. Ukkonen, + Information and Control Vol. 64, 1985, pp. 100-118. + + Modified to work on strings rather than files + by Peter Miller , October 1995 */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#else +# include +#endif + +#include + +#ifdef HAVE_LIMITS_H +# include +#else +# define INT_MAX ((int)(~(unsigned)0 >> 1)) +#endif + +#include "system.h" +#include "fstrcmp.h" + + +/* + * Data on one input string being compared. + */ +struct string_data +{ + /* The string to be compared. */ + const char *data; + + /* The length of the string to be compared. */ + int data_length; + + /* The number of characters inserted or deleted. */ + int edit_count; +}; + +static struct string_data string[2]; + + +#ifdef MINUS_H_FLAG + +/* This corresponds to the diff -H flag. With this heuristic, for + strings with a constant small density of changes, the algorithm is + linear in the strings size. This is unlikely in typical uses of + fstrcmp, and so is usually compiled out. Besides, there is no + interface to set it true. */ +static int heuristic; + +#endif + + +/* Vector, indexed by diagonal, containing 1 + the X coordinate of the + point furthest along the given diagonal in the forward search of the + edit matrix. */ +static int *fdiag; + +/* Vector, indexed by diagonal, containing the X coordinate of the point + furthest along the given diagonal in the backward search of the edit + matrix. */ +static int *bdiag; + +/* Edit scripts longer than this are too expensive to compute. */ +static int too_expensive; + +/* Snakes bigger than this are considered `big'. */ +#define SNAKE_LIMIT 20 + +struct partition +{ + /* Midpoints of this partition. */ + int xmid, ymid; + + /* Nonzero if low half will be analyzed minimally. */ + int lo_minimal; + + /* Likewise for high half. */ + int hi_minimal; +}; + + +/* NAME + diag - find diagonal path + + SYNOPSIS + int diag(int xoff, int xlim, int yoff, int ylim, int minimal, + struct partition *part); + + DESCRIPTION + Find the midpoint of the shortest edit script for a specified + portion of the two strings. + + Scan from the beginnings of the strings, and simultaneously from + the ends, doing a breadth-first search through the space of + edit-sequence. When the two searches meet, we have found the + midpoint of the shortest edit sequence. + + If MINIMAL is nonzero, find the minimal edit script regardless + of expense. Otherwise, if the search is too expensive, use + heuristics to stop the search and report a suboptimal answer. + + RETURNS + Set PART->(XMID,YMID) to the midpoint (XMID,YMID). The diagonal + number XMID - YMID equals the number of inserted characters + minus the number of deleted characters (counting only characters + before the midpoint). Return the approximate edit cost; this is + the total number of characters inserted or deleted (counting + only characters before the midpoint), unless a heuristic is used + to terminate the search prematurely. + + Set PART->LEFT_MINIMAL to nonzero iff the minimal edit script + for the left half of the partition is known; similarly for + PART->RIGHT_MINIMAL. + + CAVEAT + This function assumes that the first characters of the specified + portions of the two strings do not match, and likewise that the + last characters do not match. The caller must trim matching + characters from the beginning and end of the portions it is + going to specify. + + If we return the "wrong" partitions, the worst this can do is + cause suboptimal diff output. It cannot cause incorrect diff + output. */ + +static int diag PARAMS ((int, int, int, int, int, struct partition *)); + +static int +diag (xoff, xlim, yoff, ylim, minimal, part) + int xoff; + int xlim; + int yoff; + int ylim; + int minimal; + struct partition *part; +{ + int *const fd = fdiag; /* Give the compiler a chance. */ + int *const bd = bdiag; /* Additional help for the compiler. */ + const char *const xv = string[0].data; /* Still more help for the compiler. */ + const char *const yv = string[1].data; /* And more and more . . . */ + const int dmin = xoff - ylim; /* Minimum valid diagonal. */ + const int dmax = xlim - yoff; /* Maximum valid diagonal. */ + const int fmid = xoff - yoff; /* Center diagonal of top-down search. */ + const int bmid = xlim - ylim; /* Center diagonal of bottom-up search. */ + int fmin = fmid; + int fmax = fmid; /* Limits of top-down search. */ + int bmin = bmid; + int bmax = bmid; /* Limits of bottom-up search. */ + int c; /* Cost. */ + int odd = (fmid - bmid) & 1; + + /* + * True if southeast corner is on an odd diagonal with respect + * to the northwest. + */ + fd[fmid] = xoff; + bd[bmid] = xlim; + for (c = 1;; ++c) + { + int d; /* Active diagonal. */ + int big_snake; + + big_snake = 0; + /* Extend the top-down search by an edit step in each diagonal. */ + if (fmin > dmin) + fd[--fmin - 1] = -1; + else + ++fmin; + if (fmax < dmax) + fd[++fmax + 1] = -1; + else + --fmax; + for (d = fmax; d >= fmin; d -= 2) + { + int x; + int y; + int oldx; + int tlo; + int thi; + + tlo = fd[d - 1], + thi = fd[d + 1]; + + if (tlo >= thi) + x = tlo + 1; + else + x = thi; + oldx = x; + y = x - d; + while (x < xlim && y < ylim && xv[x] == yv[y]) + { + ++x; + ++y; + } + if (x - oldx > SNAKE_LIMIT) + big_snake = 1; + fd[d] = x; + if (odd && bmin <= d && d <= bmax && bd[d] <= x) + { + part->xmid = x; + part->ymid = y; + part->lo_minimal = part->hi_minimal = 1; + return 2 * c - 1; + } + } + /* Similarly extend the bottom-up search. */ + if (bmin > dmin) + bd[--bmin - 1] = INT_MAX; + else + ++bmin; + if (bmax < dmax) + bd[++bmax + 1] = INT_MAX; + else + --bmax; + for (d = bmax; d >= bmin; d -= 2) + { + int x; + int y; + int oldx; + int tlo; + int thi; + + tlo = bd[d - 1], + thi = bd[d + 1]; + if (tlo < thi) + x = tlo; + else + x = thi - 1; + oldx = x; + y = x - d; + while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) + { + --x; + --y; + } + if (oldx - x > SNAKE_LIMIT) + big_snake = 1; + bd[d] = x; + if (!odd && fmin <= d && d <= fmax && x <= fd[d]) + { + part->xmid = x; + part->ymid = y; + part->lo_minimal = part->hi_minimal = 1; + return 2 * c; + } + } + + if (minimal) + continue; + +#ifdef MINUS_H_FLAG + /* Heuristic: check occasionally for a diagonal that has made lots + of progress compared with the edit distance. If we have any + such, find the one that has made the most progress and return + it as if it had succeeded. + + With this heuristic, for strings with a constant small density + of changes, the algorithm is linear in the strings size. */ + if (c > 200 && big_snake && heuristic) + { + int best; + + best = 0; + for (d = fmax; d >= fmin; d -= 2) + { + int dd; + int x; + int y; + int v; + + dd = d - fmid; + x = fd[d]; + y = x - d; + v = (x - xoff) * 2 - dd; + + if (v > 12 * (c + (dd < 0 ? -dd : dd))) + { + if + ( + v > best + && + xoff + SNAKE_LIMIT <= x + && + x < xlim + && + yoff + SNAKE_LIMIT <= y + && + y < ylim + ) + { + /* We have a good enough best diagonal; now insist + that it end with a significant snake. */ + int k; + + for (k = 1; xv[x - k] == yv[y - k]; k++) + { + if (k == SNAKE_LIMIT) + { + best = v; + part->xmid = x; + part->ymid = y; + break; + } + } + } + } + } + if (best > 0) + { + part->lo_minimal = 1; + part->hi_minimal = 0; + return 2 * c - 1; + } + best = 0; + for (d = bmax; d >= bmin; d -= 2) + { + int dd; + int x; + int y; + int v; + + dd = d - bmid; + x = bd[d]; + y = x - d; + v = (xlim - x) * 2 + dd; + + if (v > 12 * (c + (dd < 0 ? -dd : dd))) + { + if (v > best && xoff < x && x <= xlim - SNAKE_LIMIT && + yoff < y && y <= ylim - SNAKE_LIMIT) + { + /* We have a good enough best diagonal; now insist + that it end with a significant snake. */ + int k; + + for (k = 0; xv[x + k] == yv[y + k]; k++) + { + if (k == SNAKE_LIMIT - 1) + { + best = v; + part->xmid = x; + part->ymid = y; + break; + } + } + } + } + } + if (best > 0) + { + part->lo_minimal = 0; + part->hi_minimal = 1; + return 2 * c - 1; + } + } +#endif /* MINUS_H_FLAG */ + + /* Heuristic: if we've gone well beyond the call of duty, give up + and report halfway between our best results so far. */ + if (c >= too_expensive) + { + int fxybest; + int fxbest; + int bxybest; + int bxbest; + + /* Pacify `gcc -Wall'. */ + fxbest = 0; + bxbest = 0; + + /* Find forward diagonal that maximizes X + Y. */ + fxybest = -1; + for (d = fmax; d >= fmin; d -= 2) + { + int x; + int y; + + x = fd[d] < xlim ? fd[d] : xlim; + y = x - d; + + if (ylim < y) + { + x = ylim + d; + y = ylim; + } + if (fxybest < x + y) + { + fxybest = x + y; + fxbest = x; + } + } + /* Find backward diagonal that minimizes X + Y. */ + bxybest = INT_MAX; + for (d = bmax; d >= bmin; d -= 2) + { + int x; + int y; + + x = xoff > bd[d] ? xoff : bd[d]; + y = x - d; + + if (y < yoff) + { + x = yoff + d; + y = yoff; + } + if (x + y < bxybest) + { + bxybest = x + y; + bxbest = x; + } + } + /* Use the better of the two diagonals. */ + if ((xlim + ylim) - bxybest < fxybest - (xoff + yoff)) + { + part->xmid = fxbest; + part->ymid = fxybest - fxbest; + part->lo_minimal = 1; + part->hi_minimal = 0; + } + else + { + part->xmid = bxbest; + part->ymid = bxybest - bxbest; + part->lo_minimal = 0; + part->hi_minimal = 1; + } + return 2 * c - 1; + } + } +} + + +/* NAME + compareseq - find edit sequence + + SYNOPSIS + void compareseq(int xoff, int xlim, int yoff, int ylim, int minimal); + + DESCRIPTION + Compare in detail contiguous subsequences of the two strings + which are known, as a whole, to match each other. + + The subsequence of string 0 is [XOFF, XLIM) and likewise for + string 1. + + Note that XLIM, YLIM are exclusive bounds. All character + numbers are origin-0. + + If MINIMAL is nonzero, find a minimal difference no matter how + expensive it is. */ + +static void compareseq PARAMS ((int, int, int, int, int)); + +static void +compareseq (xoff, xlim, yoff, ylim, minimal) + int xoff; + int xlim; + int yoff; + int ylim; + int minimal; +{ + const char *const xv = string[0].data; /* Help the compiler. */ + const char *const yv = string[1].data; + + /* Slide down the bottom initial diagonal. */ + while (xoff < xlim && yoff < ylim && xv[xoff] == yv[yoff]) + { + ++xoff; + ++yoff; + } + + /* Slide up the top initial diagonal. */ + while (xlim > xoff && ylim > yoff && xv[xlim - 1] == yv[ylim - 1]) + { + --xlim; + --ylim; + } + + /* Handle simple cases. */ + if (xoff == xlim) + { + while (yoff < ylim) + { + ++string[1].edit_count; + ++yoff; + } + } + else if (yoff == ylim) + { + while (xoff < xlim) + { + ++string[0].edit_count; + ++xoff; + } + } + else + { + int c; + struct partition part; + + /* Find a point of correspondence in the middle of the strings. */ + c = diag (xoff, xlim, yoff, ylim, minimal, &part); + if (c == 1) + { +#if 0 + /* This should be impossible, because it implies that one of + the two subsequences is empty, and that case was handled + above without calling `diag'. Let's verify that this is + true. */ + abort (); +#else + /* The two subsequences differ by a single insert or delete; + record it and we are done. */ + if (part.xmid - part.ymid < xoff - yoff) + ++string[1].edit_count; + else + ++string[0].edit_count; +#endif + } + else + { + /* Use the partitions to split this problem into subproblems. */ + compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal); + compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal); + } + } +} + + +/* NAME + fstrcmp - fuzzy string compare + + SYNOPSIS + double fstrcmp(const char *, const char *); + + DESCRIPTION + The fstrcmp function may be used to compare two string for + similarity. It is very useful in reducing "cascade" or + "secondary" errors in compilers or other situations where + symbol tables occur. + + RETURNS + double; 0 if the strings are entirly dissimilar, 1 if the + strings are identical, and a number in between if they are + similar. */ + +double +fstrcmp (string1, string2) + const char *string1; + const char *string2; +{ + int i; + + size_t fdiag_len; + static int *fdiag_buf; + static size_t fdiag_max; + + /* set the info for each string. */ + string[0].data = string1; + string[0].data_length = strlen (string1); + string[1].data = string2; + string[1].data_length = strlen (string2); + + /* short-circuit obvious comparisons */ + if (string[0].data_length == 0 && string[1].data_length == 0) + return 1.0; + if (string[0].data_length == 0 || string[1].data_length == 0) + return 0.0; + + /* Set TOO_EXPENSIVE to be approximate square root of input size, + bounded below by 256. */ + too_expensive = 1; + for (i = string[0].data_length + string[1].data_length; i != 0; i >>= 2) + too_expensive <<= 1; + if (too_expensive < 256) + too_expensive = 256; + + /* Because fstrcmp is typically called multiple times, while scanning + symbol tables, etc, attempt to minimize the number of memory + allocations performed. Thus, we use a static buffer for the + diagonal vectors, and never free them. */ + fdiag_len = string[0].data_length + string[1].data_length + 3; + if (fdiag_len > fdiag_max) + { + fdiag_max = fdiag_len; + fdiag_buf = xrealloc (fdiag_buf, fdiag_max * (2 * sizeof (int))); + } + fdiag = fdiag_buf + string[1].data_length + 1; + bdiag = fdiag + fdiag_len; + + /* Now do the main comparison algorithm */ + string[0].edit_count = 0; + string[1].edit_count = 0; + compareseq (0, string[0].data_length, 0, string[1].data_length, 0); + + /* The result is + ((number of chars in common) / (average length of the strings)). + This is admittedly biased towards finding that the strings are + similar, however it does produce meaningful results. */ + return ((double) (string[0].data_length + string[1].data_length - + string[1].edit_count - string[0].edit_count) / (string[0].data_length + + string[1].data_length)); +} diff --git a/tools/fstrcmp.h b/tools/fstrcmp.h new file mode 100644 index 000000000..04047171f --- /dev/null +++ b/tools/fstrcmp.h @@ -0,0 +1,25 @@ +/* GNU gettext - internationalization aids + Copyright (C) 1995 Free Software Foundation, Inc. + + This file was written by Peter Miller + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _FSTRCMP_H +#define _FSTRCMP_H + +double fstrcmp PARAMS ((const char *__s1, const char *__s2)); + +#endif diff --git a/tools/rpmgettext.c b/tools/rpmgettext.c index aaf9d29f3..0bc854f2d 100644 --- a/tools/rpmgettext.c +++ b/tools/rpmgettext.c @@ -207,7 +207,7 @@ static int poTags[] = { }; static int -gettextfile(int fd, const char *file, FILE *fp) +gettextfile(int fd, const char *file, FILE *fp, int *poTags) { struct rpmlead lead; Header h; @@ -278,6 +278,8 @@ gettextfile(int fd, const char *file, FILE *fp) #define xrealloc realloc #define PARAMS(_x) _x +#include "fstrcmp.c" + #include "str-list.c" #include "rpmpo.h" @@ -460,6 +462,74 @@ message_list_append (mlp, mp) mlp->item[mlp->nitems++] = mp; } +void +message_list_delete_nth (mlp, n) + message_list_ty *mlp; + size_t n; +{ + size_t j; + + if (n >= mlp->nitems) + return; + message_free (mlp->item[n]); + for (j = n + 1; j < mlp->nitems; ++j) + mlp->item[j - 1] = mlp->item[j]; + mlp->nitems--; +} + +message_ty * +message_list_search (mlp, msgid) + message_list_ty *mlp; + const char *msgid; +{ + size_t j; + + for (j = 0; j < mlp->nitems; ++j) + { + message_ty *mp; + + mp = mlp->item[j]; + if (0 == strcmp (msgid, mp->msgid)) + return mp; + } + return 0; +} + +message_ty * +message_list_search_fuzzy (mlp, msgid) + message_list_ty *mlp; + const char *msgid; +{ + size_t j; + double best_weight; + message_ty *best_mp; + + best_weight = 0.6; + best_mp = NULL; + for (j = 0; j < mlp->nitems; ++j) + { + size_t k; + double weight; + message_ty *mp; + + mp = mlp->item[j]; + + for (k = 0; k < mp->variant_count; ++k) + if (mp->variant[k].msgstr != NULL && mp->variant[k].msgstr[0] != '\0') + break; + if (k >= mp->variant_count) + continue; + + weight = fstrcmp (msgid, mp->msgid); + if (weight > best_weight) + { + best_weight = weight; + best_mp = mp; + } + } + return best_mp; +} + void message_list_free (mlp) message_list_ty *mlp; @@ -559,9 +629,10 @@ KW_t keywords[] = { #define NEXTLINE {state = 0; while ((c = *se) && c != '\n') se++; if (c == '\n') se++;} static int -parsepofile(const char *file, message_list_ty **mlpp) +parsepofile(const char *file, message_list_ty **mlpp, string_list_ty **flpp) { char tbuf[BUFSIZ]; + string_list_ty *flp; message_list_ty *mlp; message_ty *mp; KW_t *kw; @@ -576,6 +647,7 @@ fprintf(stderr, "================ %s\n", file); if ((rc = slurp(file, &buf, &nb)) != 0) return rc; + flp = string_list_alloc(); mlp = message_list_alloc(); mp = NULL; s = buf; @@ -614,6 +686,7 @@ fprintf(stderr, "%.*s\n", (int)(se-s), s); } *f++ = '\0'; message_comment_filepos(mp, s, -getTagVal(f)); + string_list_append_unique(flp, s); break; case '.': message_comment_dot_append(mp, xstrdup(s)); @@ -726,6 +799,11 @@ fprintf(stderr, "\n"); else message_list_free(mlp); + if (flpp) + *flpp = flp; + else + string_list_free(flp); + FREE(buf); return rc; } @@ -787,6 +865,48 @@ readRPM(char *fileName, Spec *specp, struct rpmlead *lead, Header *sigs, CSA_t * return 0; } +/* For all poTags in h, if msgid is in msg list, then substitute msgstr's */ +static int +headerInject(Header h, int *poTags, message_list_ty *mlp) +{ + message_ty *mp; + int *tp; + char **langs; + char buf[BUFSIZ]; + + if ((langs = headerGetLangs(h)) == NULL) + return 1; + + for (tp = poTags; *tp != 0; tp++) { + char **s, *e; + int i, type, count; + + if (!headerGetRawEntry(h, *tp, &type, (void **)&s, &count)) + continue; + + /* Search for the msgid */ + e = *s; + expandRpmPO(buf, e); + if ((mp = message_list_search(mlp, buf)) != NULL) { + +#if 0 + for (i = 1, e += strlen(e)+1; i < count && e != NULL; i++, e += strlen(e)+1) { + expandRpmPO(buf, e); + fprintf(fp, "msgstr(%s) %s\n", langs[i], buf); + } +#endif + + } + + if (type == RPM_STRING_ARRAY_TYPE || type == RPM_I18NSTRING_TYPE) + FREE(s) + } + + FREE(langs); + + return 0; +} + static int rewriteBinaryRPM(char *fni, char *fno, message_list_ty *mlp) { @@ -803,8 +923,11 @@ rewriteBinaryRPM(char *fni, char *fno, message_list_ty *mlp) csa->lead = &lead; /* XXX FIXME: exorcize lead/arch/os */ /* Read rpm and (partially) recreate spec/pkg control structures */ - rc = readRPM(fni, &spec, &lead, &sigs, csa); - if (rc) + if ((rc = readRPM(fni, &spec, &lead, &sigs, csa)) != 0) + return rc; + + /* Inject new strings into header tags */ + if ((rc = headerInject(spec->packages->header, poTags, mlp)) != 0) return rc; /* Rewrite the rpm */ @@ -817,6 +940,19 @@ rewriteBinaryRPM(char *fni, char *fno, message_list_ty *mlp) } } +static int +mlptoheader(message_list_ty **mlpp, Header *newhp) +{ + message_list_ty *mlp; + Header newh; + + if (mlpp) + *mlpp = mlp; + if (newhp) + *newhp = newh; + return 0; +} + /* ================================================================== */ #define STDINFN "" @@ -832,7 +968,7 @@ rpmgettext(int fd, const char *file, FILE *ofp) file = STDINFN; if (!strcmp(file, STDINFN)) - return gettextfile(fd, file, ofp); + return gettextfile(fd, file, ofp, poTags); fni[0] = '\0'; if (inputdir && *file != '/') { @@ -867,7 +1003,7 @@ rpmgettext(int fd, const char *file, FILE *ofp) return 2; } - if (gettextfile(fd, fni, ofp)) { + if (gettextfile(fd, fni, ofp, poTags)) { return 3; } @@ -879,30 +1015,77 @@ rpmgettext(int fd, const char *file, FILE *ofp) return 0; } +static char *archs[] = { + "noarch", + "i386", + "alpha", + "sparc", + NULL +}; + #define RPMPUTTEXT "rpmputtext" static int rpmputtext(int fd, const char *file, FILE *ofp) { + string_list_ty *flp; message_list_ty *mlp; - char fni[BUFSIZ], fno[BUFSIZ], fnp[BUFSIZ]; - int rc; + message_ty *mp; + lex_pos_ty *pp; + Header newh; + char fn[BUFSIZ], fni[BUFSIZ], fno[BUFSIZ]; + int j, rc; - /* XXX use po file with same basename as rpm. */ - strcpy(fnp, file); - - if ((rc = parsepofile(file, &mlp)) != 0) + if ((rc = parsepofile(file, &mlp, &flp)) != 0) return rc; - /* XXX hardwire dirnames for now */ - strcpy(fni, "/mnt/redhat/comps/dist/5.2/sparc"); - strcat(fni, "/"); - strcat(fni, basename(file)); - - strcpy(fno, "/tmp/OUT"); - strcat(fno, "/"); - strcat(fno, basename(file)); + for (j = 0; j < flp->nitems && rc == 0; j++) { + char *fne; - rc = rewriteBinaryRPM(fni, fno, mlp); + strcpy(fn, flp->item[j]); + + /* Find the text after the name-version-release */ + if ((fne = strrchr(fn, '-')) == NULL || + (fne = strchr(fne, '.')) == NULL) { + fprintf(stderr, "skipping malformed xref \"%s\"\n", fn); + continue; + } + fne++; /* skip . */ + + if ( !strcmp(fne, "src.rpm") ) { + } else { + char **a, *arch; + + for (a = archs; *a; a++) { + arch = *a; + /* Append ".arch.rpm" + *fne = '\0'; + strcat(fne, arch); + strcat(fne, ".rpm"); + + /* Build input "inputdir/arch/fn" */ + fni[0] = '\0'; + if (inputdir) { + strcat(fni, inputdir); + strcat(fni, "/"); + strcat(fni, arch); + strcat(fni, "/"); + } + strcat(fni, fn); + + /* Build output "outputdir/arch/fn" */ + fno[0] = '\0'; + if (outputdir) { + strcat(fno, outputdir); + strcat(fno, "/"); + strcat(fno, arch); + strcat(fno, "/"); + } + strcat(fno, fn); + + rc = rewriteBinaryRPM(fni, fno, mlp); + } + } + } if (mlp) message_list_free(mlp); @@ -914,7 +1097,7 @@ rpmputtext(int fd, const char *file, FILE *ofp) static int rpmchktext(int fd, const char *file, FILE *ofp) { - return parsepofile(file, NULL); + return parsepofile(file, NULL, NULL); } int