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;
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
00033 static int dateToTimet(const char * datestr, time_t * secs)
00034
00035 {
00036 struct tm time;
00037 char * p, * pe, * q, ** idx;
00038 char * date = strcpy(alloca(strlen(datestr) + 1), datestr);
00039 static char * days[] =
00040 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
00041 static char * months[] =
00042 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00043 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
00044 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
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
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
00069 p = pe; mySKIPSPACE(p);
00070 if (*p == '\0') return -1;
00071 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
00072
00073
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
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
00093 *secs += timezone;
00094
00095 return 0;
00096 }
00097
00098
00099
00100 extern time_t get_date(const char * p, void * now);
00101
00102
00109
00110 static int addChangelog(Header h, StringBuf sb)
00111
00112
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
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;
00132 } else {
00133
00134 res = get_date (t, NULL);
00135
00136
00137 if (res > 0) {
00138 last = res;
00139 }
00140 }
00141 }
00142 t = _free(t);
00143 }
00144
00145
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
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
00163 *s = '\0';
00164
00165 text = s + 1;
00166
00167
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
00187 mySKIPSPACE(s);
00188 if (! *s) {
00189 rpmError(RPMERR_BADSPEC, _("missing name in %%changelog\n"));
00190 return RPMERR_BADSPEC;
00191 }
00192
00193
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
00205 mySKIPSPACE(text);
00206 if (! *text) {
00207 rpmError(RPMERR_BADSPEC, _("no description in %%changelog\n"));
00208 return RPMERR_BADSPEC;
00209 }
00210
00211
00212 s = text;
00213 do {
00214 s++;
00215 } while (*s && (*(s-1) != '\n' || *s != '*'));
00216 se = s;
00217 s--;
00218
00219
00220 while ((s > text) && xisspace(*s))
00221 *s-- = '\0';
00222
00223
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
00238
00239 int parseChangelog(Spec spec)
00240 {
00241 int nextPart, res, rc;
00242 StringBuf sb = newStringBuf();
00243
00244
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 }