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 rpmMessage(RPMMESS_WARNING,
00185 _("%%changelog not in descending chronological order\n"));
00186 }
00187 lastTime = time;
00188
00189
00190 mySKIPSPACE(s);
00191 if (! *s) {
00192 rpmError(RPMERR_BADSPEC, _("missing name in %%changelog\n"));
00193 return RPMERR_BADSPEC;
00194 }
00195
00196
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
00208 mySKIPSPACE(text);
00209 if (! *text) {
00210 rpmError(RPMERR_BADSPEC, _("no description in %%changelog\n"));
00211 return RPMERR_BADSPEC;
00212 }
00213
00214
00215 s = text;
00216 do {
00217 s++;
00218 } while (*s && (*(s-1) != '\n' || *s != '*'));
00219 se = s;
00220 s--;
00221
00222
00223 while ((s > text) && xisspace(*s))
00224 *s-- = '\0';
00225
00226 if (numchangelog && (s = strstr(text, CVS_RCSID))) {
00227
00228 while(*s && *s != '\n') s++;
00229 if (!*s) {
00230 goto out;
00231 }
00232 s++;
00233 if (!*s) {
00234 goto out;
00235 }
00236
00237
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
00255 while ((s > text) && (*s == '\n' || xisspace(*s))) {
00256 *s-- = '\0';
00257 }
00258 }
00259 }
00260 out:
00261
00262
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
00277
00278 int parseChangelog(Spec spec)
00279 {
00280 int nextPart, res, rc;
00281 StringBuf sb = newStringBuf();
00282
00283
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 }