Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

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             rpmMessage(RPMMESS_WARNING,
00185                      _("%%changelog not in descending chronological order\n"));
00186         }
00187         lastTime = time;
00188 
00189         /* skip space to the name */
00190         mySKIPSPACE(s);
00191         if (! *s) {
00192             rpmError(RPMERR_BADSPEC, _("missing name in %%changelog\n"));
00193             return RPMERR_BADSPEC;
00194         }
00195 
00196         /* name */
00197         name = s;
00198         while (*s != '\0') s++;
00199         while (s > name && isspace(*s))
00200             *s-- = '\0';
00201 
00202         if (s == name) {
00203             rpmError(RPMERR_BADSPEC, _("missing name in %%changelog\n"));
00204             return RPMERR_BADSPEC;
00205         }
00206 
00207         /* text */
00208         mySKIPSPACE(text);
00209         if (! *text) {
00210             rpmError(RPMERR_BADSPEC, _("no description in %%changelog\n"));
00211             return RPMERR_BADSPEC;
00212         }
00213             
00214         /* find the next leading '*' (or eos) */
00215         s = text;
00216         do {
00217            s++;
00218         } while (*s && (*(s-1) != '\n' || *s != '*'));
00219         se = s;
00220         s--;
00221 
00222         /* backup to end of description */
00223         while ((s > text) && xisspace(*s))
00224             *s-- = '\0';
00225 
00226         if (numchangelog && (s = strstr(text, CVS_RCSID))) {
00227             /* find end of line */
00228             while(*s && *s != '\n') s++;
00229             if (!*s) {
00230                 goto out;
00231             }
00232             s++;
00233             if (!*s) {
00234                 goto out;
00235             }
00236 
00237             /* we reached place where first Revisions should be */
00238             i = 0;
00239             while (1) {
00240                 if (strncmp(s, CVS_REVISION, sizeof(CVS_REVISION) - 1) == 0) {
00241                     if (i++ == numchangelog) {
00242                         break;
00243                     }
00244                 }
00245                 while(*s && *s != '\n') s++;
00246                 if (!*s) {
00247                     break;
00248                 }
00249                 s++;
00250             }
00251 
00252             if (*s) {
00253                 s--;
00254                 /* backup to the beginning of line */
00255                 while ((s > text) && (*s == '\n' || xisspace(*s))) {
00256                     *s-- = '\0';
00257                 }
00258             }
00259         }
00260 out:
00261         
00262         /* Add entry if not truncated. */
00263         nentries++;
00264 
00265         if (last <= 0
00266          || (last < 1000 && nentries < last)
00267          || (last > 1000 && time >= last))
00268             addChangelogEntry(h, time, name, text);
00269 
00270         s = se;
00271 
00272     }
00273 
00274     return 0;
00275 }
00276 /*@=boundswrite@*/
00277 
00278 int parseChangelog(Spec spec)
00279 {
00280     int nextPart, res, rc;
00281     StringBuf sb = newStringBuf();
00282     
00283     /* There are no options to %changelog */
00284     if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
00285         sb = freeStringBuf(sb);
00286         return PART_NONE;
00287     }
00288     if (rc)
00289         return rc;
00290     
00291     while (! (nextPart = isPart(spec->line))) {
00292         const char * line;
00293         line = xstrdup(spec->line);
00294         line = xstrtolocale(line);
00295         appendStringBuf(sb, spec->line);
00296         line = _free(line);
00297         if ((rc = readLine(spec, STRIP_COMMENTS | STRIP_NOEXPAND)) > 0) {
00298             nextPart = PART_NONE;
00299             break;
00300         }
00301         if (rc)
00302             return rc;
00303     }
00304 
00305     res = addChangelog(spec->packages->header, sb);
00306     sb = freeStringBuf(sb);
00307 
00308     return (res) ? res : nextPart;
00309 }

Generated on Tue Dec 27 22:20:13 2016 for rpm by  doxygen 1.4.4