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

Generated on Mon Aug 3 15:18:57 2009 for rpm by  doxygen 1.5.1