rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

build/parseChangelog.c
Go to the documentation of this file.

    00001
    00006 #include "system.h"
    00007
    00008 #include <rpmio.h>
    00009 #include <rpmiotypes.h>
    00010 #include <rpmlog.h>
    00011 #include "rpmbuild.h"
    00012 #include "debug.h"
    00013
    00014 #define mySKIPSPACE(s) { while (*(s) && isspace(*(s))) (s)++; }
    00015 #define mySKIPNONSPACE(s) { while (*(s) && !isspace(*(s))) (s)++; }
    00016
    00017 void addChangelogEntry(Header h, time_t time, const char *name, const char *text)
    00018 {
    00019     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00020     rpmuint32_t mytime = (rpmuint32_t)time;     /* XXX convert to rpmuint32_t for header */
    00021     int xx;
    00022
    00023     he->tag = RPMTAG_CHANGELOGTIME;
    00024     he->t = RPM_UINT32_TYPE;
    00025     he->p.ui32p = &mytime;
    00026     he->c = 1;
    00027     he->append = 1;
    00028     xx = headerPut(h, he, 0);
    00029     he->append = 0;
    00030
    00031     he->tag = RPMTAG_CHANGELOGNAME;
    00032     he->t = RPM_STRING_ARRAY_TYPE;
    00033     he->p.argv = &name;
    00034     he->c = 1;
    00035     he->append = 1;
    00036     xx = headerPut(h, he, 0);
    00037     he->append = 0;
    00038
    00039     he->tag = RPMTAG_CHANGELOGTEXT;
    00040     he->t = RPM_STRING_ARRAY_TYPE;
    00041     he->p.argv = &text;
    00042     he->c = 1;
    00043     he->append = 1;
    00044     xx = headerPut(h, he, 0);
    00045     he->append = 0;
    00046 }
    00047
    00054 static int dateToTimet(const char * datestr, /*@out@*/ time_t * secs)
    00055         /*@modifies *secs @*/
    00056 {
    00057     struct tm time;
    00058     time_t timezone_offset;
    00059     char * p, * pe, * q, ** idx;
    00060     char * date = strcpy(alloca(strlen(datestr) + 1), datestr);
    00061 /*@observer@*/ static char * days[] =
    00062         { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
    00063 /*@observer@*/ static char * months[] =
    00064         { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    00065           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
    00066 /*@observer@*/ static char lengths[] =
    00067         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    00068
    00069     memset(&time, 0, sizeof(time));
    00070
    00071     pe = date;
    00072
    00073     /* day of week */
    00074     p = pe; mySKIPSPACE(p);
    00075     if (*p == '\0') return -1;
    00076     pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
    00077     for (idx = days; *idx && strcmp(*idx, p); idx++)
    00078         {};
    00079     if (*idx == NULL) return -1;
    00080
    00081     /* month */
    00082     p = pe; mySKIPSPACE(p);
    00083     if (*p == '\0') return -1;
    00084     pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
    00085     for (idx = months; *idx && strcmp(*idx, p); idx++)
    00086         {};
    00087     if (*idx == NULL) return -1;
    00088     time.tm_mon = idx - months;
    00089
    00090     /* day */
    00091     p = pe; mySKIPSPACE(p);
    00092     if (*p == '\0') return -1;
    00093     pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
    00094
    00095     /* make this noon so the day is always right (as we make this UTC) */
    00096     time.tm_hour = 12;
    00097
    00098     time.tm_mday = strtol(p, &q, 10);
    00099     if (!(q && *q == '\0')) return -1;
    00100     if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) return -1;
    00101
    00102     /* year */
    00103     p = pe; mySKIPSPACE(p);
    00104     if (*p == '\0') return -1;
    00105     pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
    00106     time.tm_year = strtol(p, &q, 10);
    00107     if (!(q && *q == '\0')) return -1;
    00108     if (time.tm_year < 1990 || time.tm_year >= 3000) return -1;
    00109     time.tm_year -= 1900;
    00110
    00111     *secs = mktime(&time);
    00112     if (*secs == -1) return -1;
    00113
    00114     /* determine timezone offset */
    00115 /*@-nullpass@*/         /* gmtime(3) unlikely to return NULL soon. */
    00116     timezone_offset = mktime(gmtime(secs)) - *secs;
    00117 /*@=nullpass@*/
    00118
    00119     /* adjust to UTC */
    00120     *secs += timezone_offset;
    00121
    00122     return 0;
    00123 }
    00124
    00125 /*@-redecl@*/
    00126 extern time_t get_date(const char * p, void * now);     /* XXX expedient lies */
    00127 /*@=redecl@*/
    00128
    00135 static rpmRC addChangelog(Header h, rpmiob iob)
    00136         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    00137         /*@modifies h, rpmGlobalMacroContext, internalState @*/
    00138 {
    00139     char * s = rpmiobStr(iob);
    00140     char * se;
    00141     char *date, *name, *text;
    00142     int i;
    00143     time_t time;
    00144     time_t lastTime = 0;
    00145     int nentries = 0;
    00146     static time_t last = 0;
    00147     static int oneshot = 0;
    00148
    00149     /* Determine changelog truncation criteria. */
    00150     if (!oneshot++) {
    00151         char * t = rpmExpand("%{?_changelog_truncate}", NULL);
    00152         char *te = NULL;
    00153         if (t && *t) {
    00154             long res = strtol(t, &te, 0);
    00155             if (res >= 0 && *te == '\0') {
    00156                 last = res;             /* truncate to no. of entries. */
    00157             } else {
    00158 /*@-moduncon@*/
    00159                 res = (long)get_date (t, NULL);
    00160 /*@=moduncon@*/
    00161                 /* XXX malformed date string silently ignored. */
    00162                 if (res > 0) {
    00163                     last = res;         /* truncate to date. */
    00164                 }
    00165             }
    00166         }
    00167         t = _free(t);
    00168     }
    00169
    00170     /* skip space */
    00171     mySKIPSPACE(s);
    00172
    00173     while (*s != '\0') {
    00174         if (*s != '*') {
    00175             rpmlog(RPMLOG_ERR,
    00176                         _("%%changelog entries must start with *\n"));
    00177             return RPMRC_FAIL;
    00178         }
    00179
    00180         /* find end of line */
    00181         date = s;
    00182         while(*s && *s != '\n') s++;
    00183         if (! *s) {
    00184             rpmlog(RPMLOG_ERR, _("incomplete %%changelog entry\n"));
    00185             return RPMRC_FAIL;
    00186         }
    00187 /*@-modobserver@*/
    00188         *s = '\0';
    00189 /*@=modobserver@*/
    00190         text = s + 1;
    00191
    00192         /* 4 fields of date */
    00193         date++;
    00194         s = date;
    00195         for (i = 0; i < 4; i++) {
    00196             mySKIPSPACE(s);
    00197             mySKIPNONSPACE(s);
    00198         }
    00199         mySKIPSPACE(date);
    00200         if (dateToTimet(date, &time)) {
    00201             rpmlog(RPMLOG_ERR, _("bad date in %%changelog: %s\n"), date);
    00202             return RPMRC_FAIL;
    00203         }
    00204         if (lastTime && lastTime < time) {
    00205             rpmlog(RPMLOG_ERR,
    00206                      _("%%changelog not in descending chronological order\n"));
    00207             return RPMRC_FAIL;
    00208         }
    00209         lastTime = time;
    00210
    00211         /* skip space to the name */
    00212         mySKIPSPACE(s);
    00213         if (! *s) {
    00214             rpmlog(RPMLOG_ERR, _("missing name in %%changelog\n"));
    00215             return RPMRC_FAIL;
    00216         }
    00217
    00218         /* name */
    00219         name = s;
    00220         while (*s != '\0') s++;
    00221         while (s > name && isspace(*s))
    00222             *s-- = '\0';
    00223
    00224         if (s == name) {
    00225             rpmlog(RPMLOG_ERR, _("missing name in %%changelog\n"));
    00226             return RPMRC_FAIL;
    00227         }
    00228
    00229         /* text */
    00230         mySKIPSPACE(text);
    00231         if (! *text) {
    00232             rpmlog(RPMLOG_ERR, _("no description in %%changelog\n"));
    00233             return RPMRC_FAIL;
    00234         }
    00235
    00236         /* find the next leading '*' (or eos) */
    00237         s = text;
    00238         do {
    00239            s++;
    00240         } while (*s && (*(s-1) != '\n' || *s != '*'));
    00241         se = s;
    00242         s--;
    00243
    00244         /* backup to end of description */
    00245         while ((s > text) && xisspace(*s))
    00246             *s-- = '\0';
    00247
    00248         /* Add entry if not truncated. */
    00249         nentries++;
    00250
    00251         if (last <= 0
    00252          || (last < 1000 && nentries < (int)last)
    00253          || (last > 1000 && time >= last))
    00254             addChangelogEntry(h, time, name, text);
    00255
    00256         s = se;
    00257
    00258     }
    00259
    00260     return 0;
    00261 }
    00262
    00263 int parseChangelog(Spec spec)
    00264 {
    00265     rpmParseState nextPart;
    00266     rpmiob iob = rpmiobNew(0);
    00267     rpmRC rc;
    00268
    00269     /* There are no options to %changelog */
    00270     if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
    00271         iob = rpmiobFree(iob);
    00272         return PART_NONE;
    00273     }
    00274     if (rc != RPMRC_OK)
    00275         return rc;
    00276
    00277     while ((nextPart = isPart(spec)) == PART_NONE) {
    00278         const char * line;
    00279         line = xstrdup(spec->line);
    00280         line = xstrtolocale(line);
    00281         iob = rpmiobAppend(iob, spec->line, 0);
    00282         line = _free(line);
    00283         if ((rc = readLine(spec, STRIP_COMMENTS | STRIP_NOEXPAND)) > 0) {
    00284             nextPart = PART_NONE;
    00285             break;
    00286         }
    00287         if (rc != RPMRC_OK)
    00288             return rc;
    00289     }
    00290
    00291     rc = addChangelog(spec->packages->header, iob);
    00292     iob = rpmiobFree(iob);
    00293
    00294     return (rc != RPMRC_OK ? rc : (rpmRC)nextPart);
    00295 }