• 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 }

Generated on Fri Dec 3 2010 20:53:15 for rpm by  doxygen 1.7.2