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

Generated on Mon Nov 29 2010 05:18:41 for rpm by  doxygen 1.7.2