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