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

Generated on Mon Mar 5 14:30:57 2007 for rpm by  doxygen 1.5.1