Main Page Modules Data Structures File List Data Fields Globals Related Pages

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