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;
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
00036 static int dateToTimet(const char * datestr, time_t * secs)
00037
00038 {
00039 struct tm time;
00040 char * p, * pe, * q, ** idx;
00041 char * date = strcpy(alloca(strlen(datestr) + 1), datestr);
00042 static char * days[] =
00043 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
00044 static char * months[] =
00045 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00046 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
00047 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
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
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
00072 p = pe; mySKIPSPACE(p);
00073 if (*p == '\0') return -1;
00074 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
00075
00076
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
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
00096 *secs += timezone;
00097
00098 return 0;
00099 }
00100
00101
00102
00103 extern time_t get_date(const char * p, void * now);
00104
00105
00112
00113 static int addChangelog(Header h, StringBuf sb)
00114
00115
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
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;
00136 } else {
00137
00138 res = get_date (t, NULL);
00139
00140
00141 if (res > 0) {
00142 last = res;
00143 }
00144 }
00145 }
00146 t = _free(t);
00147 }
00148
00149
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
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
00167 *s = '\0';
00168
00169 text = s + 1;
00170
00171
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
00191 mySKIPSPACE(s);
00192 if (! *s) {
00193 rpmError(RPMERR_BADSPEC, _("missing name in %%changelog\n"));
00194 return RPMERR_BADSPEC;
00195 }
00196
00197
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
00209 mySKIPSPACE(text);
00210 if (! *text) {
00211 rpmError(RPMERR_BADSPEC, _("no description in %%changelog\n"));
00212 return RPMERR_BADSPEC;
00213 }
00214
00215
00216 s = text;
00217 do {
00218 s++;
00219 } while (*s && (*(s-1) != '\n' || *s != '*'));
00220 se = s;
00221 s--;
00222
00223
00224 while ((s > text) && xisspace(*s))
00225 *s-- = '\0';
00226
00227 if (numchangelog && (s = strstr(text, CVS_RCSID))) {
00228
00229 while(*s && *s != '\n') s++;
00230 if (!*s) {
00231 goto out;
00232 }
00233 s++;
00234 if (!*s) {
00235 goto out;
00236 }
00237
00238
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
00256 while ((s > text) && (*s == '\n' || xisspace(*s))) {
00257 *s-- = '\0';
00258 }
00259 }
00260 }
00261 out:
00262
00263
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
00278
00279 int parseChangelog(Spec spec)
00280 {
00281 int nextPart, res, rc;
00282 StringBuf sb = newStringBuf();
00283
00284
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 }