rpm
4.5
|
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 #define CVS_RCSID "$""Log: " 00015 #define CVS_REVISION "Revision " 00016 00017 void addChangelogEntry(Header h, time_t time, const char *name, const char *text) 00018 { 00019 int_32 mytime = time; /* XXX convert to int_32 in header */ 00020 00021 (void) headerAddOrAppendEntry(h, RPMTAG_CHANGELOGTIME, 00022 RPM_INT32_TYPE, &mytime, 1); 00023 (void) headerAddOrAppendEntry(h, RPMTAG_CHANGELOGNAME, 00024 RPM_STRING_ARRAY_TYPE, &name, 1); 00025 (void) headerAddOrAppendEntry(h, RPMTAG_CHANGELOGTEXT, 00026 RPM_STRING_ARRAY_TYPE, &text, 1); 00027 } 00028 00035 /*@-boundswrite@*/ 00036 static int dateToTimet(const char * datestr, /*@out@*/ time_t * secs) 00037 /*@modifies *secs @*/ 00038 { 00039 struct tm time; 00040 char * p, * pe, * q, ** idx; 00041 char * date = strcpy(alloca(strlen(datestr) + 1), datestr); 00042 /*@observer@*/ static char * days[] = 00043 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL }; 00044 /*@observer@*/ static char * months[] = 00045 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 00046 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; 00047 /*@observer@*/ static char lengths[] = 00048 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 00049 00050 memset(&time, 0, sizeof(time)); 00051 00052 pe = date; 00053 00054 /* day of week */ 00055 p = pe; mySKIPSPACE(p); 00056 if (*p == '\0') return -1; 00057 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; 00058 for (idx = days; *idx && strcmp(*idx, p); idx++) 00059 {}; 00060 if (*idx == NULL) return -1; 00061 00062 /* month */ 00063 p = pe; mySKIPSPACE(p); 00064 if (*p == '\0') return -1; 00065 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; 00066 for (idx = months; *idx && strcmp(*idx, p); idx++) 00067 {}; 00068 if (*idx == NULL) return -1; 00069 time.tm_mon = idx - months; 00070 00071 /* day */ 00072 p = pe; mySKIPSPACE(p); 00073 if (*p == '\0') return -1; 00074 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; 00075 00076 /* make this noon so the day is always right (as we make this UTC) */ 00077 time.tm_hour = 12; 00078 00079 time.tm_mday = strtol(p, &q, 10); 00080 if (!(q && *q == '\0')) return -1; 00081 if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) return -1; 00082 00083 /* year */ 00084 p = pe; mySKIPSPACE(p); 00085 if (*p == '\0') return -1; 00086 pe = p; mySKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; 00087 time.tm_year = strtol(p, &q, 10); 00088 if (!(q && *q == '\0')) return -1; 00089 if (time.tm_year < 1990 || time.tm_year >= 3000) return -1; 00090 time.tm_year -= 1900; 00091 00092 *secs = mktime(&time); 00093 if (*secs == -1) return -1; 00094 00095 /* adjust to GMT */ 00096 *secs += timezone; 00097 00098 return 0; 00099 } 00100 /*@=boundswrite@*/ 00101 00102 /*@-redecl@*/ 00103 extern time_t get_date(const char * p, void * now); /* XXX expedient lies */ 00104 /*@=redecl@*/ 00105 00112 /*@-boundswrite@*/ 00113 static int addChangelog(Header h, StringBuf sb) 00114 /*@globals rpmGlobalMacroContext, h_errno @*/ 00115 /*@modifies h, rpmGlobalMacroContext @*/ 00116 { 00117 char * s = getStringBuf(sb); 00118 char * se; 00119 char *date, *name, *text; 00120 int i; 00121 time_t time; 00122 time_t lastTime = 0; 00123 int nentries = 0; 00124 static time_t last = 0; 00125 static int oneshot = 0; 00126 int numchangelog = rpmExpandNumeric("%{?_buildchangelogtruncate}"); 00127 00128 /* Determine changelog truncation criteria. */ 00129 if (!oneshot++) { 00130 char * t = rpmExpand("%{?_changelog_truncate}", NULL); 00131 char *te = NULL; 00132 if (t && *t) { 00133 long res = strtol(t, &te, 0); 00134 if (res >= 0 && *te == '\0') { 00135 last = res; /* truncate to no. of entries. */ 00136 } else { 00137 /*@-moduncon@*/ 00138 res = get_date (t, NULL); 00139 /*@=moduncon@*/ 00140 /* XXX malformed date string silently ignored. */ 00141 if (res > 0) { 00142 last = res; /* truncate to date. */ 00143 } 00144 } 00145 } 00146 t = _free(t); 00147 } 00148 00149 /* skip space */ 00150 mySKIPSPACE(s); 00151 00152 while (*s != '\0') { 00153 if (*s != '*') { 00154 rpmError(RPMERR_BADSPEC, 00155 _("%%changelog entries must start with *\n")); 00156 return RPMERR_BADSPEC; 00157 } 00158 00159 /* find end of line */ 00160 date = s; 00161 while(*s && *s != '\n') s++; 00162 if (! *s) { 00163 rpmError(RPMERR_BADSPEC, _("incomplete %%changelog entry\n")); 00164 return RPMERR_BADSPEC; 00165 } 00166 /*@-modobserver@*/ 00167 *s = '\0'; 00168 /*@=modobserver@*/ 00169 text = s + 1; 00170 00171 /* 4 fields of date */ 00172 date++; 00173 s = date; 00174 for (i = 0; i < 4; i++) { 00175 mySKIPSPACE(s); 00176 mySKIPNONSPACE(s); 00177 } 00178 mySKIPSPACE(date); 00179 if (dateToTimet(date, &time)) { 00180 rpmError(RPMERR_BADSPEC, _("bad date in %%changelog: %s\n"), date); 00181 return RPMERR_BADSPEC; 00182 } 00183 if (lastTime && lastTime < time) { 00184 rpmError(RPMERR_BADSPEC, 00185 _("%%changelog not in descending chronological order\n")); 00186 return RPMERR_BADSPEC; 00187 } 00188 lastTime = time; 00189 00190 /* skip space to the name */ 00191 mySKIPSPACE(s); 00192 if (! *s) { 00193 rpmError(RPMERR_BADSPEC, _("missing name in %%changelog\n")); 00194 return RPMERR_BADSPEC; 00195 } 00196 00197 /* name */ 00198 name = s; 00199 while (*s != '\0') s++; 00200 while (s > name && isspace(*s)) 00201 *s-- = '\0'; 00202 00203 if (s == name) { 00204 rpmError(RPMERR_BADSPEC, _("missing name in %%changelog\n")); 00205 return RPMERR_BADSPEC; 00206 } 00207 00208 /* text */ 00209 mySKIPSPACE(text); 00210 if (! *text) { 00211 rpmError(RPMERR_BADSPEC, _("no description in %%changelog\n")); 00212 return RPMERR_BADSPEC; 00213 } 00214 00215 /* find the next leading '*' (or eos) */ 00216 s = text; 00217 do { 00218 s++; 00219 } while (*s && (*(s-1) != '\n' || *s != '*')); 00220 se = s; 00221 s--; 00222 00223 /* backup to end of description */ 00224 while ((s > text) && xisspace(*s)) 00225 *s-- = '\0'; 00226 00227 if (numchangelog && (s = strstr(text, CVS_RCSID))) { 00228 /* find end of line */ 00229 while(*s && *s != '\n') s++; 00230 if (!*s) { 00231 goto out; 00232 } 00233 s++; 00234 if (!*s) { 00235 goto out; 00236 } 00237 00238 /* we reached place where first Revisions should be */ 00239 i = 0; 00240 while (1) { 00241 if (strncmp(s, CVS_REVISION, sizeof(CVS_REVISION) - 1) == 0) { 00242 if (i++ == numchangelog) { 00243 break; 00244 } 00245 } 00246 while(*s && *s != '\n') s++; 00247 if (!*s) { 00248 break; 00249 } 00250 s++; 00251 } 00252 00253 if (*s) { 00254 s--; 00255 /* backup to the beginning of line */ 00256 while ((s > text) && (*s == '\n' || xisspace(*s))) { 00257 *s-- = '\0'; 00258 } 00259 } 00260 } 00261 out: 00262 00263 /* Add entry if not truncated. */ 00264 nentries++; 00265 00266 if (last <= 0 00267 || (last < 1000 && nentries < last) 00268 || (last > 1000 && time >= last)) 00269 addChangelogEntry(h, time, name, text); 00270 00271 s = se; 00272 00273 } 00274 00275 return 0; 00276 } 00277 /*@=boundswrite@*/ 00278 00279 int parseChangelog(Spec spec) 00280 { 00281 int nextPart, res, rc; 00282 StringBuf sb = newStringBuf(); 00283 00284 /* There are no options to %changelog */ 00285 if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) { 00286 sb = freeStringBuf(sb); 00287 return PART_NONE; 00288 } 00289 if (rc) 00290 return rc; 00291 00292 while (! (nextPart = isPart(spec->line))) { 00293 const char * line; 00294 line = xstrdup(spec->line); 00295 line = xstrtolocale(line); 00296 appendStringBuf(sb, spec->line); 00297 line = _free(line); 00298 if ((rc = readLine(spec, STRIP_COMMENTS | STRIP_NOEXPAND)) > 0) { 00299 nextPart = PART_NONE; 00300 break; 00301 } 00302 if (rc) 00303 return rc; 00304 } 00305 00306 res = addChangelog(spec->packages->header, sb); 00307 sb = freeStringBuf(sb); 00308 00309 return (res) ? res : nextPart; 00310 }