# build/parseChangelog.c

Go to the documentation of this file.

    00001
    00006 #include "system.h"
    00007
    00008 #include "rpmbuild.h"
    00009 #include "debug.h"
    00010
    00011 void addChangelogEntry(Header h, time_t time, const char *name, const char *text)
    00012 {
    00013     int_32 mytime = time;       /* XXX convert to header representation */
    00014     if (headerIsEntry(h, RPMTAG_CHANGELOGTIME)) {
    00015         (void) headerAppendEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE,
    00016                           &mytime, 1);
    00017         (void) headerAppendEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE,
    00018                           &name, 1);
    00019         (void) headerAppendEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE,
    00020                          &text, 1);
    00021     } else {
    00022         (void) headerAddEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE,
    00023                        &mytime, 1);
    00024         (void) headerAddEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE,
    00025                        &name, 1);
    00026         (void) headerAddEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE,
    00027                        &text, 1);
    00028     }
    00029 }
    00030
    00037 static int dateToTimet(const char * datestr, /*@out@*/ time_t * secs)
    00038         /*@modifies *secs @*/
    00039 {
    00040     struct tm time;
    00041     char * p, * pe, * q, ** idx;
    00042     char * date = strcpy(alloca(strlen(datestr) + 1), datestr);
    00043 /*@observer@*/ static char * days[] =
    00044         { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
    00045 /*@observer@*/ static char * months[] =
    00046         { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    00047           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
    00048 /*@observer@*/ static char lengths[] =
    00049         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    00050
    00051     memset(&time, 0, sizeof(time));
    00052
    00053     pe = date;
    00054
    00055     /* day of week */
    00056     p = pe; SKIPSPACE(p);
    00057     if (*p == '\0') return -1;
    00058     pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
    00059     for (idx = days; *idx && strcmp(*idx, p); idx++)
    00060         {};
    00061     if (*idx == NULL) return -1;
    00062
    00063     /* month */
    00064     p = pe; SKIPSPACE(p);
    00065     if (*p == '\0') return -1;
    00066     pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
    00067     for (idx = months; *idx && strcmp(*idx, p); idx++)
    00068         {};
    00069     if (*idx == NULL) return -1;
    00070     time.tm_mon = idx - months;
    00071
    00072     /* day */
    00073     p = pe; SKIPSPACE(p);
    00074     if (*p == '\0') return -1;
    00075     pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
    00076
    00077     /* make this noon so the day is always right (as we make this UTC) */
    00078     time.tm_hour = 12;
    00079
    00080     time.tm_mday = strtol(p, &q, 10);
    00081     if (!(q && *q == '\0')) return -1;
    00082     if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) return -1;
    00083
    00084     /* year */
    00085     p = pe; SKIPSPACE(p);
    00086     if (*p == '\0') return -1;
    00087     pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
    00088     time.tm_year = strtol(p, &q, 10);
    00089     if (!(q && *q == '\0')) return -1;
    00090     if (time.tm_year < 1997 || time.tm_year >= 3000) return -1;
    00091     time.tm_year -= 1900;
    00092
    00093     *secs = mktime(&time);
    00094     if (*secs == -1) return -1;
    00095
    00096     /* adjust to GMT */
    00097     *secs += timezone;
    00098
    00099     return 0;
    00100 }
    00101
    00108 static int addChangelog(Header h, StringBuf sb)
    00109         /*@modifies h @*/
    00110 {
    00111     char *s;
    00112     int i;
    00113     time_t time;
    00114     time_t lastTime = 0;
    00115     char *date, *name, *text, *next;
    00116
    00117     s = getStringBuf(sb);
    00118
    00119     /* skip space */
    00120     SKIPSPACE(s);
    00121
    00122     while (*s != '\0') {
    00123         if (*s != '*') {
    00124             rpmError(RPMERR_BADSPEC,
    00125                         _("%%changelog entries must start with *\n"));
    00126             return RPMERR_BADSPEC;
    00127         }
    00128
    00129         /* find end of line */
    00130         date = s;
    00131         while(*s && *s != '\n') s++;
    00132         if (! *s) {
    00133             rpmError(RPMERR_BADSPEC, _("incomplete %%changelog entry\n"));
    00134             return RPMERR_BADSPEC;
    00135         }
    00136         /*@-modobserver@*/
    00137         *s = '\0';
    00138         /*@=modobserver@*/
    00139         text = s + 1;
    00140
    00141         /* 4 fields of date */
    00142         date++;
    00143         s = date;
    00144         for (i = 0; i < 4; i++) {
    00145             SKIPSPACE(s);
    00146             SKIPNONSPACE(s);
    00147         }
    00148         SKIPSPACE(date);
    00149         if (dateToTimet(date, &time)) {
    00150             rpmError(RPMERR_BADSPEC, _("bad date in %%changelog: %s\n"), date);
    00151             return RPMERR_BADSPEC;
    00152         }
    00153         if (lastTime && lastTime < time) {
    00154             rpmError(RPMERR_BADSPEC,
    00155                      _("%%changelog not in descending chronological order\n"));
    00156             return RPMERR_BADSPEC;
    00157         }
    00158         lastTime = time;
    00159
    00160         /* skip space to the name */
    00161         SKIPSPACE(s);
    00162         if (! *s) {
    00163             rpmError(RPMERR_BADSPEC, _("missing name in %%changelog\n"));
    00164             return RPMERR_BADSPEC;
    00165         }
    00166
    00167         /* name */
    00168         name = s;
    00169         while (*s != '\0') s++;
    00170         while (s > name && xisspace(*s)) {
    00171             *s-- = '\0';
    00172         }
    00173         if (s == name) {
    00174             rpmError(RPMERR_BADSPEC, _("missing name in %%changelog\n"));
    00175             return RPMERR_BADSPEC;
    00176         }
    00177
    00178         /* text */
    00179         SKIPSPACE(text);
    00180         if (! *text) {
    00181             rpmError(RPMERR_BADSPEC, _("no description in %%changelog\n"));
    00182             return RPMERR_BADSPEC;
    00183         }
    00184
    00185         /* find the next leading '*' (or eos) */
    00186         s = text;
    00187         do {
    00188            s++;
    00189         } while (*s && (*(s-1) != '\n' || *s != '*'));
    00190         next = s;
    00191         s--;
    00192
    00193         /* backup to end of description */
    00194         while ((s > text) && xisspace(*s)) {
    00195             *s-- = '\0';
    00196         }
    00197
    00198         addChangelogEntry(h, time, name, text);
    00199         s = next;
    00200     }
    00201
    00202     return 0;
    00203 }
    00204
    00205 int parseChangelog(Spec spec)
    00206 {
    00207     int nextPart, res, rc;
    00208     StringBuf sb = newStringBuf();
    00209
    00210     /* There are no options to %changelog */
    00211     if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
    00212         sb = freeStringBuf(sb);
    00213         return PART_NONE;
    00214     }
    00215     if (rc)
    00216         return rc;
    00217
    00218     while (! (nextPart = isPart(spec->line))) {
    00219         appendStringBuf(sb, spec->line);
    00220         if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
    00221             nextPart = PART_NONE;
    00222             break;
    00223         }
    00224         if (rc)
    00225             return rc;
    00226     }
    00227
    00228     res = addChangelog(spec->packages->header, sb);
    00229     sb = freeStringBuf(sb);
    00230
    00231     return (res) ? res : nextPart;
    00232 }