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

Generated on Fri May 25 21:18:11 2007 for rpm by  doxygen 1.5.2