2000-08-28 03:18:25 +08:00
|
|
|
/** \ingroup rpmbuild
|
|
|
|
* \file build/parseChangelog.c
|
2000-01-25 04:02:32 +08:00
|
|
|
* Parse %changelog section from spec file.
|
|
|
|
*/
|
|
|
|
|
1998-07-26 05:00:26 +08:00
|
|
|
#include "system.h"
|
1998-03-05 00:51:06 +08:00
|
|
|
|
1998-07-31 06:09:42 +08:00
|
|
|
#include "rpmbuild.h"
|
2000-12-13 04:03:45 +08:00
|
|
|
#include "debug.h"
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1999-09-24 05:46:48 +08:00
|
|
|
void addChangelogEntry(Header h, time_t time, const char *name, const char *text)
|
1998-07-31 06:09:42 +08:00
|
|
|
{
|
1999-07-07 01:32:49 +08:00
|
|
|
int_32 mytime = time; /* XXX convert to header representation */
|
1998-07-31 06:09:42 +08:00
|
|
|
if (headerIsEntry(h, RPMTAG_CHANGELOGTIME)) {
|
2001-05-01 06:32:22 +08:00
|
|
|
(void) headerAppendEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE,
|
1999-07-07 01:32:49 +08:00
|
|
|
&mytime, 1);
|
2001-05-01 06:32:22 +08:00
|
|
|
(void) headerAppendEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE,
|
1998-07-31 06:09:42 +08:00
|
|
|
&name, 1);
|
2001-05-01 06:32:22 +08:00
|
|
|
(void) headerAppendEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE,
|
1998-07-31 06:09:42 +08:00
|
|
|
&text, 1);
|
|
|
|
} else {
|
2001-05-01 06:32:22 +08:00
|
|
|
(void) headerAddEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE,
|
1999-07-07 01:32:49 +08:00
|
|
|
&mytime, 1);
|
2001-05-01 06:32:22 +08:00
|
|
|
(void) headerAddEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE,
|
1998-07-31 06:09:42 +08:00
|
|
|
&name, 1);
|
2001-05-01 06:32:22 +08:00
|
|
|
(void) headerAddEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE,
|
1998-07-31 06:09:42 +08:00
|
|
|
&text, 1);
|
1998-05-21 01:05:26 +08:00
|
|
|
}
|
1998-07-31 06:09:42 +08:00
|
|
|
}
|
|
|
|
|
2001-01-11 22:13:04 +08:00
|
|
|
/**
|
|
|
|
* Parse date string to seconds.
|
|
|
|
* @param datestr date string (e.g. 'Wed Jan 1 1997')
|
|
|
|
* @retval secs secs since the unix epoch
|
|
|
|
* @return 0 on success, -1 on error
|
|
|
|
*/
|
2007-09-12 05:03:27 +08:00
|
|
|
static int dateToTimet(const char * datestr, time_t * secs)
|
1998-07-31 06:09:42 +08:00
|
|
|
{
|
|
|
|
struct tm time;
|
2001-06-06 03:26:22 +08:00
|
|
|
char * p, * pe, * q, ** idx;
|
1998-07-31 06:09:42 +08:00
|
|
|
char * date = strcpy(alloca(strlen(datestr) + 1), datestr);
|
2007-09-12 05:03:27 +08:00
|
|
|
static char * days[] =
|
2001-06-06 03:26:22 +08:00
|
|
|
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
|
2007-09-12 05:03:27 +08:00
|
|
|
static char * months[] =
|
2001-06-06 03:26:22 +08:00
|
|
|
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
|
2007-09-12 05:03:27 +08:00
|
|
|
static char lengths[] =
|
2001-06-06 03:26:22 +08:00
|
|
|
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1998-07-31 06:09:42 +08:00
|
|
|
memset(&time, 0, sizeof(time));
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1999-07-04 06:58:08 +08:00
|
|
|
pe = date;
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1998-07-31 06:09:42 +08:00
|
|
|
/* day of week */
|
1999-07-04 06:58:08 +08:00
|
|
|
p = pe; SKIPSPACE(p);
|
|
|
|
if (*p == '\0') return -1;
|
2001-05-01 06:32:22 +08:00
|
|
|
pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
|
1999-07-04 06:58:08 +08:00
|
|
|
for (idx = days; *idx && strcmp(*idx, p); idx++)
|
2001-06-06 03:26:22 +08:00
|
|
|
{};
|
1999-07-04 06:58:08 +08:00
|
|
|
if (*idx == NULL) return -1;
|
1998-07-31 06:09:42 +08:00
|
|
|
|
|
|
|
/* month */
|
1999-07-04 06:58:08 +08:00
|
|
|
p = pe; SKIPSPACE(p);
|
|
|
|
if (*p == '\0') return -1;
|
2001-05-01 06:32:22 +08:00
|
|
|
pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
|
1999-07-04 06:58:08 +08:00
|
|
|
for (idx = months; *idx && strcmp(*idx, p); idx++)
|
2001-06-06 03:26:22 +08:00
|
|
|
{};
|
1999-07-04 06:58:08 +08:00
|
|
|
if (*idx == NULL) return -1;
|
1998-07-31 06:09:42 +08:00
|
|
|
time.tm_mon = idx - months;
|
|
|
|
|
|
|
|
/* day */
|
1999-07-04 06:58:08 +08:00
|
|
|
p = pe; SKIPSPACE(p);
|
|
|
|
if (*p == '\0') return -1;
|
2001-05-01 06:32:22 +08:00
|
|
|
pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
|
1998-07-31 06:09:42 +08:00
|
|
|
|
|
|
|
/* make this noon so the day is always right (as we make this UTC) */
|
|
|
|
time.tm_hour = 12;
|
|
|
|
|
1999-07-04 06:58:08 +08:00
|
|
|
time.tm_mday = strtol(p, &q, 10);
|
|
|
|
if (!(q && *q == '\0')) return -1;
|
1998-07-31 06:09:42 +08:00
|
|
|
if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) return -1;
|
|
|
|
|
|
|
|
/* year */
|
1999-07-04 06:58:08 +08:00
|
|
|
p = pe; SKIPSPACE(p);
|
|
|
|
if (*p == '\0') return -1;
|
2001-05-01 06:32:22 +08:00
|
|
|
pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0';
|
1999-07-04 06:58:08 +08:00
|
|
|
time.tm_year = strtol(p, &q, 10);
|
|
|
|
if (!(q && *q == '\0')) return -1;
|
2005-03-03 19:47:52 +08:00
|
|
|
if (time.tm_year < 1990 || time.tm_year >= 3000) return -1;
|
1998-07-31 06:09:42 +08:00
|
|
|
time.tm_year -= 1900;
|
|
|
|
|
|
|
|
*secs = mktime(&time);
|
|
|
|
if (*secs == -1) return -1;
|
|
|
|
|
|
|
|
/* adjust to GMT */
|
|
|
|
*secs += timezone;
|
|
|
|
|
|
|
|
return 0;
|
1998-01-13 05:31:29 +08:00
|
|
|
}
|
|
|
|
|
2001-01-11 22:13:04 +08:00
|
|
|
/**
|
|
|
|
* Add %changelog section to header.
|
|
|
|
* @param h header
|
|
|
|
* @param sb changelog strings
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
1998-01-13 05:31:29 +08:00
|
|
|
static int addChangelog(Header h, StringBuf sb)
|
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
int i;
|
1999-07-07 01:32:49 +08:00
|
|
|
time_t time;
|
|
|
|
time_t lastTime = 0;
|
1998-01-13 05:31:29 +08:00
|
|
|
char *date, *name, *text, *next;
|
|
|
|
|
|
|
|
s = getStringBuf(sb);
|
|
|
|
|
|
|
|
/* skip space */
|
|
|
|
SKIPSPACE(s);
|
|
|
|
|
2001-05-01 06:32:22 +08:00
|
|
|
while (*s != '\0') {
|
1998-01-13 05:31:29 +08:00
|
|
|
if (*s != '*') {
|
2007-10-09 19:06:06 +08:00
|
|
|
rpmlog(RPMERR_BADSPEC,
|
2001-01-16 07:09:42 +08:00
|
|
|
_("%%changelog entries must start with *\n"));
|
1998-01-13 05:31:29 +08:00
|
|
|
return RPMERR_BADSPEC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find end of line */
|
|
|
|
date = s;
|
1999-07-04 06:58:08 +08:00
|
|
|
while(*s && *s != '\n') s++;
|
1998-01-13 05:31:29 +08:00
|
|
|
if (! *s) {
|
2007-10-09 19:06:06 +08:00
|
|
|
rpmlog(RPMERR_BADSPEC, _("incomplete %%changelog entry\n"));
|
1998-01-13 05:31:29 +08:00
|
|
|
return RPMERR_BADSPEC;
|
|
|
|
}
|
|
|
|
*s = '\0';
|
|
|
|
text = s + 1;
|
|
|
|
|
|
|
|
/* 4 fields of date */
|
|
|
|
date++;
|
|
|
|
s = date;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
SKIPSPACE(s);
|
|
|
|
SKIPNONSPACE(s);
|
|
|
|
}
|
|
|
|
SKIPSPACE(date);
|
1999-07-07 01:32:49 +08:00
|
|
|
if (dateToTimet(date, &time)) {
|
2007-10-09 19:06:06 +08:00
|
|
|
rpmlog(RPMERR_BADSPEC, _("bad date in %%changelog: %s\n"), date);
|
1998-01-13 05:31:29 +08:00
|
|
|
return RPMERR_BADSPEC;
|
|
|
|
}
|
|
|
|
if (lastTime && lastTime < time) {
|
2007-10-09 19:06:06 +08:00
|
|
|
rpmlog(RPMERR_BADSPEC,
|
2002-01-06 02:41:05 +08:00
|
|
|
_("%%changelog not in descending chronological order\n"));
|
1998-01-13 05:31:29 +08:00
|
|
|
return RPMERR_BADSPEC;
|
|
|
|
}
|
|
|
|
lastTime = time;
|
|
|
|
|
|
|
|
/* skip space to the name */
|
|
|
|
SKIPSPACE(s);
|
|
|
|
if (! *s) {
|
2007-10-09 19:06:06 +08:00
|
|
|
rpmlog(RPMERR_BADSPEC, _("missing name in %%changelog\n"));
|
1998-01-13 05:31:29 +08:00
|
|
|
return RPMERR_BADSPEC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* name */
|
|
|
|
name = s;
|
2001-05-01 06:32:22 +08:00
|
|
|
while (*s != '\0') s++;
|
2001-04-29 09:05:43 +08:00
|
|
|
while (s > name && xisspace(*s)) {
|
1998-01-13 05:31:29 +08:00
|
|
|
*s-- = '\0';
|
|
|
|
}
|
|
|
|
if (s == name) {
|
2007-10-09 19:06:06 +08:00
|
|
|
rpmlog(RPMERR_BADSPEC, _("missing name in %%changelog\n"));
|
1998-01-13 05:31:29 +08:00
|
|
|
return RPMERR_BADSPEC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* text */
|
|
|
|
SKIPSPACE(text);
|
|
|
|
if (! *text) {
|
2007-10-09 19:06:06 +08:00
|
|
|
rpmlog(RPMERR_BADSPEC, _("no description in %%changelog\n"));
|
1998-01-13 05:31:29 +08:00
|
|
|
return RPMERR_BADSPEC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find the next leading '*' (or eos) */
|
|
|
|
s = text;
|
|
|
|
do {
|
|
|
|
s++;
|
|
|
|
} while (*s && (*(s-1) != '\n' || *s != '*'));
|
|
|
|
next = s;
|
|
|
|
s--;
|
|
|
|
|
|
|
|
/* backup to end of description */
|
2001-04-29 09:05:43 +08:00
|
|
|
while ((s > text) && xisspace(*s)) {
|
1998-01-13 05:31:29 +08:00
|
|
|
*s-- = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
addChangelogEntry(h, time, name, text);
|
|
|
|
s = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-21 20:23:02 +08:00
|
|
|
int parseChangelog(rpmSpec spec)
|
1998-01-13 05:31:29 +08:00
|
|
|
{
|
1998-07-31 06:09:42 +08:00
|
|
|
int nextPart, res, rc;
|
2001-05-06 03:28:32 +08:00
|
|
|
StringBuf sb = newStringBuf();
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1998-07-31 06:09:42 +08:00
|
|
|
/* There are no options to %changelog */
|
|
|
|
if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
|
2001-05-06 03:28:32 +08:00
|
|
|
sb = freeStringBuf(sb);
|
1998-07-31 06:09:42 +08:00
|
|
|
return PART_NONE;
|
|
|
|
}
|
1999-07-04 06:58:08 +08:00
|
|
|
if (rc)
|
1998-07-31 06:09:42 +08:00
|
|
|
return rc;
|
|
|
|
|
|
|
|
while (! (nextPart = isPart(spec->line))) {
|
|
|
|
appendStringBuf(sb, spec->line);
|
|
|
|
if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
|
|
|
|
nextPart = PART_NONE;
|
|
|
|
break;
|
|
|
|
}
|
1999-07-04 06:58:08 +08:00
|
|
|
if (rc)
|
1998-07-31 06:09:42 +08:00
|
|
|
return rc;
|
|
|
|
}
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1998-07-31 06:09:42 +08:00
|
|
|
res = addChangelog(spec->packages->header, sb);
|
2001-05-06 03:28:32 +08:00
|
|
|
sb = freeStringBuf(sb);
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1998-07-31 06:09:42 +08:00
|
|
|
return (res) ? res : nextPart;
|
1998-01-13 05:31:29 +08:00
|
|
|
}
|