00001
00006 #include "system.h"
00007
00008 #include <rpmio.h>
00009 #include "rpmbuild.h"
00010 #include "debug.h"
00011
00012 #define mySKIPSPACE(s) { while (*(s) && isspace(*(s))) (s)++; }
00013 #define mySKIPNONSPACE(s) { while (*(s) && !isspace(*(s))) (s)++; }
00014
00015 void addChangelogEntry(Header h, time_t time, const char *name, const char *text)
00016 {
00017 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00018 uint32_t mytime = time;
00019 int xx;
00020
00021 he->tag = RPMTAG_CHANGELOGTIME;
00022 he->t = RPM_UINT32_TYPE;
00023 he->p.ui32p = &mytime;
00024 he->c = 1;
00025 he->append = 1;
00026 xx = headerPut(h, he, 0);
00027 he->append = 0;
00028
00029 he->tag = RPMTAG_CHANGELOGNAME;
00030 he->t = RPM_STRING_ARRAY_TYPE;
00031 he->p.argv = &name;
00032 he->c = 1;
00033 he->append = 1;
00034 xx = headerPut(h, he, 0);
00035 he->append = 0;
00036
00037 he->tag = RPMTAG_CHANGELOGTEXT;
00038 he->t = RPM_STRING_ARRAY_TYPE;
00039 he->p.argv = &text;
00040 he->c = 1;
00041 he->append = 1;
00042 xx = headerPut(h, he, 0);
00043 he->append = 0;
00044 }
00045
00052 static int dateToTimet(const char * datestr, time_t * secs)
00053
00054 {
00055 struct tm time;
00056 time_t timezone_offset;
00057 char * p, * pe, * q, ** idx;
00058 char * date = strcpy(alloca(strlen(datestr) + 1), datestr);
00059 static char * days[] =
00060 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
00061 static char * months[] =
00062 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00063 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
00064 static char lengths[] =
00065 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00066
00067 memset(&time, 0, sizeof(time));
00068
00069 pe = date;
00070
00071
00072 p = pe; mySKIPSPACE(p);
00073 if (*p == '\0') return -1;
00074 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
00075 for (idx = days; *idx && strcmp(*idx, p); idx++)
00076 {};
00077 if (*idx == NULL) return -1;
00078
00079
00080 p = pe; mySKIPSPACE(p);
00081 if (*p == '\0') return -1;
00082 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
00083 for (idx = months; *idx && strcmp(*idx, p); idx++)
00084 {};
00085 if (*idx == NULL) return -1;
00086 time.tm_mon = idx - months;
00087
00088
00089 p = pe; mySKIPSPACE(p);
00090 if (*p == '\0') return -1;
00091 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
00092
00093
00094 time.tm_hour = 12;
00095
00096 time.tm_mday = strtol(p, &q, 10);
00097 if (!(q && *q == '\0')) return -1;
00098 if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) return -1;
00099
00100
00101 p = pe; mySKIPSPACE(p);
00102 if (*p == '\0') return -1;
00103 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
00104 time.tm_year = strtol(p, &q, 10);
00105 if (!(q && *q == '\0')) return -1;
00106 if (time.tm_year < 1990 || time.tm_year >= 3000) return -1;
00107 time.tm_year -= 1900;
00108
00109 *secs = mktime(&time);
00110 if (*secs == -1) return -1;
00111
00112
00113
00114 timezone_offset = mktime(gmtime(secs)) - *secs;
00115
00116
00117
00118 *secs += timezone_offset;
00119
00120 return 0;
00121 }
00122
00123
00124 extern time_t get_date(const char * p, void * now);
00125
00126
00133 static rpmRC addChangelog(Header h, StringBuf sb)
00134
00135
00136 {
00137 char * s = getStringBuf(sb);
00138 char * se;
00139 char *date, *name, *text;
00140 int i;
00141 time_t time;
00142 time_t lastTime = 0;
00143 int nentries = 0;
00144 static time_t last = 0;
00145 static int oneshot = 0;
00146
00147
00148 if (!oneshot++) {
00149 char * t = rpmExpand("%{?_changelog_truncate}", NULL);
00150 char *te = NULL;
00151 if (t && *t) {
00152 long res = strtol(t, &te, 0);
00153 if (res >= 0 && *te == '\0') {
00154 last = res;
00155 } else {
00156
00157 res = get_date (t, NULL);
00158
00159
00160 if (res > 0) {
00161 last = res;
00162 }
00163 }
00164 }
00165 t = _free(t);
00166 }
00167
00168
00169 mySKIPSPACE(s);
00170
00171 while (*s != '\0') {
00172 if (*s != '*') {
00173 rpmlog(RPMLOG_ERR,
00174 _("%%changelog entries must start with *\n"));
00175 return RPMRC_FAIL;
00176 }
00177
00178
00179 date = s;
00180 while(*s && *s != '\n') s++;
00181 if (! *s) {
00182 rpmlog(RPMLOG_ERR, _("incomplete %%changelog entry\n"));
00183 return RPMRC_FAIL;
00184 }
00185
00186 *s = '\0';
00187
00188 text = s + 1;
00189
00190
00191 date++;
00192 s = date;
00193 for (i = 0; i < 4; i++) {
00194 mySKIPSPACE(s);
00195 mySKIPNONSPACE(s);
00196 }
00197 mySKIPSPACE(date);
00198 if (dateToTimet(date, &time)) {
00199 rpmlog(RPMLOG_ERR, _("bad date in %%changelog: %s\n"), date);
00200 return RPMRC_FAIL;
00201 }
00202 if (lastTime && lastTime < time) {
00203 rpmlog(RPMLOG_ERR,
00204 _("%%changelog not in descending chronological order\n"));
00205 return RPMRC_FAIL;
00206 }
00207 lastTime = time;
00208
00209
00210 mySKIPSPACE(s);
00211 if (! *s) {
00212 rpmlog(RPMLOG_ERR, _("missing name in %%changelog\n"));
00213 return RPMRC_FAIL;
00214 }
00215
00216
00217 name = s;
00218 while (*s != '\0') s++;
00219 while (s > name && isspace(*s))
00220 *s-- = '\0';
00221
00222 if (s == name) {
00223 rpmlog(RPMLOG_ERR, _("missing name in %%changelog\n"));
00224 return RPMRC_FAIL;
00225 }
00226
00227
00228 mySKIPSPACE(text);
00229 if (! *text) {
00230 rpmlog(RPMLOG_ERR, _("no description in %%changelog\n"));
00231 return RPMRC_FAIL;
00232 }
00233
00234
00235 s = text;
00236 do {
00237 s++;
00238 } while (*s && (*(s-1) != '\n' || *s != '*'));
00239 se = s;
00240 s--;
00241
00242
00243 while ((s > text) && xisspace(*s))
00244 *s-- = '\0';
00245
00246
00247 nentries++;
00248
00249 if (last <= 0
00250 || (last < 1000 && nentries < last)
00251 || (last > 1000 && time >= last))
00252 addChangelogEntry(h, time, name, text);
00253
00254 s = se;
00255
00256 }
00257
00258 return 0;
00259 }
00260
00261 int parseChangelog(Spec spec)
00262 {
00263 rpmParseState nextPart;
00264 StringBuf sb = newStringBuf();
00265 rpmRC rc;
00266
00267
00268 if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
00269 sb = freeStringBuf(sb);
00270 return PART_NONE;
00271 }
00272 if (rc != RPMRC_OK)
00273 return rc;
00274
00275 while ((nextPart = isPart(spec)) == PART_NONE) {
00276 const char * line;
00277 line = xstrdup(spec->line);
00278 line = xstrtolocale(line);
00279 appendStringBuf(sb, spec->line);
00280 line = _free(line);
00281 if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
00282 nextPart = PART_NONE;
00283 break;
00284 }
00285 if (rc != RPMRC_OK)
00286 return rc;
00287 }
00288
00289 rc = addChangelog(spec->packages->header, sb);
00290 sb = freeStringBuf(sb);
00291
00292 return (rc != RPMRC_OK ? rc : nextPart);
00293 }