00001
00006 #include "system.h"
00007
00008 #include "rpmbuild.h"
00009 #include "debug.h"
00010
00011 #define CVS_RCSID "$""Log: "
00012 #define CVS_REVISION "Revision "
00013
00014 void addChangelogEntry(Header h, time_t time, const char *name, const char *text)
00015 {
00016 int_32 mytime = time;
00017 if (headerIsEntry(h, RPMTAG_CHANGELOGTIME)) {
00018 (void) headerAppendEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE,
00019 &mytime, 1);
00020 (void) headerAppendEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE,
00021 &name, 1);
00022 (void) headerAppendEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE,
00023 &text, 1);
00024 } else {
00025 (void) headerAddEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE,
00026 &mytime, 1);
00027 (void) headerAddEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE,
00028 &name, 1);
00029 (void) headerAddEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE,
00030 &text, 1);
00031 }
00032 }
00033
00040
00041 static int dateToTimet(const char * datestr, time_t * secs)
00042
00043 {
00044 struct tm time;
00045 char * p, * pe, * q, ** idx;
00046 char * date = strcpy(alloca(strlen(datestr) + 1), datestr);
00047 static char * days[] =
00048 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
00049 static char * months[] =
00050 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00051 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
00052 static char lengths[] =
00053 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00054
00055 memset(&time, 0, sizeof(time));
00056
00057 pe = date;
00058
00059
00060 p = pe; SKIPSPACE(p);
00061 if (*p == '\0') return -1;
00062 pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
00063 for (idx = days; *idx && strcmp(*idx, p); idx++)
00064 {};
00065 if (*idx == NULL) return -1;
00066
00067
00068 p = pe; SKIPSPACE(p);
00069 if (*p == '\0') return -1;
00070 pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
00071 for (idx = months; *idx && strcmp(*idx, p); idx++)
00072 {};
00073 if (*idx == NULL) return -1;
00074 time.tm_mon = idx - months;
00075
00076
00077 p = pe; SKIPSPACE(p);
00078 if (*p == '\0') return -1;
00079 pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
00080
00081
00082 time.tm_hour = 12;
00083
00084 time.tm_mday = strtol(p, &q, 10);
00085 if (!(q && *q == '\0')) return -1;
00086 if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) return -1;
00087
00088
00089 p = pe; SKIPSPACE(p);
00090 if (*p == '\0') return -1;
00091 pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
00092 time.tm_year = strtol(p, &q, 10);
00093 if (!(q && *q == '\0')) return -1;
00094 if (time.tm_year < 1990 || time.tm_year >= 3000) return -1;
00095 time.tm_year -= 1900;
00096
00097 *secs = mktime(&time);
00098 if (*secs == -1) return -1;
00099
00100
00101 *secs += timezone;
00102
00103 return 0;
00104 }
00105
00106
00113
00114 static int addChangelog(Header h, StringBuf sb)
00115
00116 {
00117 char *s;
00118 int i;
00119 time_t time;
00120 time_t lastTime = 0;
00121 char *date, *name, *text, *next;
00122 int numchangelog = rpmExpandNumeric("%{?_buildchangelogtruncate}");
00123
00124 s = getStringBuf(sb);
00125
00126
00127 SKIPSPACE(s);
00128
00129 while (*s != '\0') {
00130 if (*s != '*') {
00131 rpmError(RPMERR_BADSPEC,
00132 _("%%changelog entries must start with *\n"));
00133 return RPMERR_BADSPEC;
00134 }
00135
00136
00137 date = s;
00138 while(*s && *s != '\n') s++;
00139 if (! *s) {
00140 rpmError(RPMERR_BADSPEC, _("incomplete %%changelog entry\n"));
00141 return RPMERR_BADSPEC;
00142 }
00143
00144 *s = '\0';
00145
00146 text = s + 1;
00147
00148
00149 date++;
00150 s = date;
00151 for (i = 0; i < 4; i++) {
00152 SKIPSPACE(s);
00153 SKIPNONSPACE(s);
00154 }
00155 SKIPSPACE(date);
00156 if (dateToTimet(date, &time)) {
00157 rpmError(RPMERR_BADSPEC, _("bad date in %%changelog: %s\n"), date);
00158 return RPMERR_BADSPEC;
00159 }
00160 if (lastTime && lastTime < time) {
00161 rpmError(RPMERR_BADSPEC,
00162 _("%%changelog not in descending chronological order\n"));
00163 return RPMERR_BADSPEC;
00164 }
00165 lastTime = time;
00166
00167
00168 SKIPSPACE(s);
00169 if (! *s) {
00170 rpmError(RPMERR_BADSPEC, _("missing name in %%changelog\n"));
00171 return RPMERR_BADSPEC;
00172 }
00173
00174
00175 name = s;
00176 while (*s != '\0') s++;
00177 while (s > name && xisspace(*s)) {
00178 *s-- = '\0';
00179 }
00180 if (s == name) {
00181 rpmError(RPMERR_BADSPEC, _("missing name in %%changelog\n"));
00182 return RPMERR_BADSPEC;
00183 }
00184
00185
00186 SKIPSPACE(text);
00187 if (! *text) {
00188 rpmError(RPMERR_BADSPEC, _("no description in %%changelog\n"));
00189 return RPMERR_BADSPEC;
00190 }
00191
00192
00193 s = text;
00194 do {
00195 s++;
00196 } while (*s && (*(s-1) != '\n' || *s != '*'));
00197 next = s;
00198 s--;
00199
00200
00201 while ((s > text) && xisspace(*s)) {
00202 *s-- = '\0';
00203 }
00204
00205 if (numchangelog && (s = strstr(text, CVS_RCSID))) {
00206
00207 while(*s && *s != '\n') s++;
00208 if (!*s) {
00209 goto out;
00210 }
00211 s++;
00212 if (!*s) {
00213 goto out;
00214 }
00215
00216
00217 i = 0;
00218 while (1) {
00219 if (strncmp(s, CVS_REVISION, sizeof(CVS_REVISION) - 1) == 0) {
00220 if (i++ == numchangelog) {
00221 break;
00222 }
00223 }
00224 while(*s && *s != '\n') s++;
00225 if (!*s) {
00226 break;
00227 }
00228 s++;
00229 }
00230
00231 if (*s) {
00232 s--;
00233
00234 while ((s > text) && (*s == '\n' || xisspace(*s))) {
00235 *s-- = '\0';
00236 }
00237 }
00238 }
00239 out:
00240
00241 addChangelogEntry(h, time, name, text);
00242 s = next;
00243 }
00244
00245 return 0;
00246 }
00247
00248
00249 int parseChangelog(Spec spec)
00250 {
00251 int nextPart, res, rc;
00252 StringBuf sb = newStringBuf();
00253
00254
00255 if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
00256 sb = freeStringBuf(sb);
00257 return PART_NONE;
00258 }
00259 if (rc)
00260 return rc;
00261
00262 while (! (nextPart = isPart(spec->line))) {
00263 appendStringBuf(sb, spec->line);
00264 if ((rc = readLine(spec, STRIP_COMMENTS | STRIP_NOEXPAND)) > 0) {
00265 nextPart = PART_NONE;
00266 break;
00267 }
00268 if (rc)
00269 return rc;
00270 }
00271
00272 res = addChangelog(spec->packages->header, sb);
00273 sb = freeStringBuf(sb);
00274
00275 return (res) ? res : nextPart;
00276 }