* spec.c - routines for parsing a spec file
*/
+/*****************************
+TODO:
+
+. multiline descriptions (general backslash processing)
+. real arch/os checking
+. %exclude
+. %doc
+. %config
+. %setup
+. %patch
+. %dir and real directory handling
+. root: option
+
+******************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+
#include "header.h"
#include "spec.h"
#include "rpmerr.h"
#include "messages.h"
-#include <stdlib.h>
-#include <string.h>
-#include <regex.h>
+#include "rpmlib.h"
#define LINE_BUF_SIZE 1024
+#define FREE(x) { if (x) free(x); }
struct SpecRec {
+ char *name; /* package base name */
char *prep;
char *build;
char *install;
};
struct PackageRec {
+ char *subname; /* If both of these are NULL, then this is */
+ char *newname; /* the main package. subname concats with name */
Header header;
char *filelist;
struct PackageRec *next;
static int match_arch(char *s);
static int match_os(char *s);
static void free_packagerec(struct PackageRec *p);
-static void init_spec(void);
+static void reset_spec(void);
+static int find_preamble_line(char *line, char **s);
+static int check_part(char *line, char **s);
void free_packagerec(struct PackageRec *p)
{
freeHeader(p->header);
- free(p->filelist);
+ FREE(p->filelist);
+ FREE(p->subname);
+ FREE(p->newname);
if (p->next) {
free_packagerec(p->next);
}
void freeSpec(Spec s)
{
- free(s->prep);
- free(s->build);
- free(s->install);
- free(s->clean);
+ FREE(s->name);
+ FREE(s->prep);
+ FREE(s->build);
+ FREE(s->install);
+ FREE(s->clean);
free_packagerec(s->packages);
free(s);
}
}
}
-static int reading = 0;
-static int iflevels = 0;
-static int skiplevels = 0;
-static int skip = 0;
+static struct read_level_entry {
+ int reading; /* 1 if we are reading at this level */
+ struct read_level_entry *next;
+} *read_level = NULL;
static int read_line(FILE *f, char *line)
{
- char *r = fgets(line, LINE_BUF_SIZE, f);
+ static struct read_level_entry *rl;
+ int gotline;
+ char *r;
- if (! r) {
- /* the end */
- if (iflevels) return RPMERR_UNMATCHEDIF;
- return 0;
+ do {
+ gotline = 0;
+ if (! fgets(line, LINE_BUF_SIZE, f)) {
+ /* the end */
+ if (read_level->next) {
+ return RPMERR_UNMATCHEDIF;
+ } else {
+ return 0;
+ }
+ }
+ if (! strncmp("%ifarch", line, 7)) {
+ rl = malloc(sizeof(struct read_level_entry));
+ rl->next = read_level;
+ rl->reading = read_level->reading && match_arch(line);
+ read_level = rl;
+ } else if (! strncmp("%ifos", line, 5)) {
+ rl = malloc(sizeof(struct read_level_entry));
+ rl->next = read_level;
+ rl->reading = read_level->reading && match_os(line);
+ read_level = rl;
+ } else if (! strncmp("%else", line, 5)) {
+ if (! read_level->next) {
+ /* Got an else with no %if ! */
+ return RPMERR_UNMATCHEDIF;
+ }
+ read_level->reading =
+ read_level->next->reading && ! read_level->reading;
+ } else if (! strncmp("%endif", line, 6)) {
+ rl = read_level;
+ read_level = rl->next;
+ free(rl);
+ } else {
+ gotline = 1;
+ }
+ } while (! (gotline && read_level->reading));
+
+ r = line + (strlen(line)) - 1;
+ if (*r == '\n') {
+ *r = '\0';
}
+ return 1;
+}
- skip = 0;
+struct preamble_line {
+ int tag;
+ int len;
+ char *token;
+} preamble_spec[] = {
+ {RPMTAG_NAME, 0, "name"},
+ {RPMTAG_VERSION, 0, "version"},
+ {RPMTAG_RELEASE, 0, "release"},
+ {RPMTAG_SERIAL, 0, "serial"},
+ {RPMTAG_DESCRIPTION, 0, "description"},
+ {RPMTAG_SUMMARY, 0, "summary"},
+ {RPMTAG_COPYRIGHT, 0, "copyright"},
+ {RPMTAG_DISTRIBUTION, 0, "distribution"},
+ {RPMTAG_VENDOR, 0, "vendor"},
+ {RPMTAG_GROUP, 0, "group"},
+ {RPMTAG_PACKAGER, 0, "packager"},
+ {0, 0, 0}
+};
- if (! strncmp("%ifarch", line, 7)) {
- iflevels++;
- skip = 1;
- if (! match_arch(line)) {
- reading = 0;
- skiplevels++;
- }
- }
- if (! strncmp("%ifos", line, 5)) {
- iflevels++;
- skip = 1;
- if (! match_os(line)) {
- reading = 0;
- skiplevels++;
- }
- }
+static int find_preamble_line(char *line, char **s)
+{
+ struct preamble_line *p = preamble_spec;
- if (! strncmp("%endif", line, 6)) {
- iflevels--;
- skip = 1;
- if (skiplevels) {
- if (! --skiplevels) reading = 1;
- }
+ while (p->token && strncasecmp(line, p->token, p->len)) {
+ p++;
}
-
- return 1;
+ if (!p) return 0;
+ *s = line + p->len;
+ *s += strspn(*s, ": \t");
+ return p->tag;
}
-static regex_t name_regex;
-static regex_t description_regex;
-static regex_t package_regex;
-static regex_t version_regex;
-static regex_t release_regex;
-static regex_t copyright_regex;
-static regex_t icon_regex;
-static regex_t group_regex;
-
-struct regentry {
- regex_t *p;
+/* None of these can be 0 !! */
+#define PREAMBLE_PART 1
+#define PREP_PART 2
+#define BUILD_PART 3
+#define INSTALL_PART 4
+#define CLEAN_PART 5
+#define PREIN_PART 6
+#define POSTIN_PART 7
+#define PREUN_PART 8
+#define POSTUN_PART 9
+#define FILES_PART 10
+
+static struct part_rec {
+ int part;
+ int len;
char *s;
-} regexps[] = {
- {&package_regex, "^package[[:space:]]*:[[:space:]]*"},
- {&name_regex, "^name[[:space:]]*:[[:space:]]*"},
- {&description_regex, "^description[[:space:]]*:[[:space:]]*"},
- {&version_regex, "^version[[:space:]]*:[[:space:]]*"},
- {&release_regex, "^release[[:space:]]*:[[:space:]]*"},
- {©right_regex, "^copyright[[:space:]]*:[[:space:]]*"},
- {&group_regex, "^group[[:space:]]*:[[:space:]]*"},
- {&icon_regex, "^icon[[:space:]]*:[[:space:]]*"},
- {0, 0}
+} part_list[] = {
+ {PREAMBLE_PART, 0, "%package"},
+ {PREP_PART, 0, "%prep"},
+ {BUILD_PART, 0, "%build"},
+ {INSTALL_PART, 0, "%install"},
+ {CLEAN_PART, 0, "%clean"},
+ {PREIN_PART, 0, "%prein"},
+ {POSTIN_PART, 0, "%postin"},
+ {PREUN_PART, 0, "%preun"},
+ {POSTUN_PART, 0, "%postun"},
+ {FILES_PART, 0, "%files"},
+ {0, 0, 0}
};
-static void init_spec()
+static int check_part(char *line, char **s)
{
- static done = 0;
- struct regentry *r = regexps;
- int opts = REG_ICASE | REG_EXTENDED;
-
- if (! done) {
- while(r->p) {
- regcomp(r->p, r->s, opts);
- r++;
- }
- done = 1;
+ struct part_rec *p = part_list;
+
+ while (p->s && strncasecmp(line, p->s, p->len)) {
+ p++;
+ }
+ if (!p) return 0;
+ *s = line + p->len;
+ *s += strspn(*s, " \t");
+ if (**s == '\0') {
+ *s = NULL;
}
+ return p->part;
}
-#define PACKAGE_PART 0
-#define PREP_PART 1
-#define BUILD_PART 2
-#define INSTALL_PART 3
-#define CLEAN_PART 4
-#define PREIN_PART 5
-#define POSTIN_PART 6
-#define PREUN_PART 7
-#define POSTUN_PART 8
-#define FILES_PART 9
-
Spec parseSpec(FILE *f)
{
char line[LINE_BUF_SIZE];
- Spec s = (struct SpecRec *) malloc(sizeof(struct SpecRec));
- int part = PACKAGE_PART;
+ char *s;
+ int cur_part = PREAMBLE_PART;
+ struct PackageRec *cur_package = NULL;
+
+ int x, tag;
- int x;
- regmatch_t match;
+ Spec spec = (struct SpecRec *) malloc(sizeof(struct SpecRec));
+ spec->name = NULL;
- init_spec();
+ reset_spec();
- reading = 1;
- while ((x = read_line(f, line))) {
- if (!reading) continue;
- if (skip) continue;
- /* If we get here, this line is for us */
- printf(line);
- if (! regexec(&description_regex, line, 1, &match, 0)) {
- message(MESS_DEBUG, "description: %s", line + match.rm_eo);
- } else if (! regexec(&name_regex, line, 1, &match, 0)) {
- message(MESS_DEBUG, "name : %s", line + match.rm_eo);
+ while ((x = read_line(f, line)) > 0) {
+ if ((tag = check_part(line, &s))) {
+ cur_part = tag;
+ printf("Switching to: %d\n", cur_part);
+ if (s) {
+ printf("Subname: %s\n", s);
+ }
+ continue;
+ }
+
+ switch (cur_part) {
+ case PREAMBLE_PART:
+ if ((tag = find_preamble_line(line, &s))) {
+ switch (tag) {
+ case RPMTAG_NAME:
+ case RPMTAG_VERSION:
+ case RPMTAG_RELEASE:
+ case RPMTAG_SERIAL:
+ case RPMTAG_SUMMARY:
+ case RPMTAG_DESCRIPTION:
+ case RPMTAG_INSTALLTIME:
+ case RPMTAG_DISTRIBUTION:
+ case RPMTAG_VENDOR:
+ case RPMTAG_COPYRIGHT:
+ case RPMTAG_PACKAGER:
+ case RPMTAG_GROUP:
+ case RPMTAG_URL:
+ printf("%d: %s\n", tag, s);
+ break;
+ default:
+ printf("Skipping: %s\n", line);
+ }
+ } else {
+ /* Not a recognized preamble part */
+ printf("Unknown: %s\n", line);
+ }
+ break;
+ case PREP_PART:
+ case BUILD_PART:
+ case INSTALL_PART:
+ case CLEAN_PART:
+ break;
+ case PREIN_PART:
+ case POSTIN_PART:
+ case PREUN_PART:
+ case POSTUN_PART:
+ break;
+ case FILES_PART:
+ break;
+ default:
+ /* error(RPMERR_INTERNALBADPART, "Internal error"); */
+ printf("%s\n", line);
}
}
if (x < 0) {
return NULL;
}
- return s;
+ return spec;
+}
+
+static void reset_spec()
+{
+ static done = 0;
+ struct read_level_entry *rl;
+ struct preamble_line *p = preamble_spec;
+ struct part_rec *p1 = part_list;
+
+ while (read_level) {
+ rl = read_level;
+ read_level = read_level->next;
+ free(rl);
+ }
+ read_level = malloc(sizeof(struct read_level_entry));
+ read_level->next = NULL;
+ read_level->reading = 1;
+
+ if (! done) {
+ /* Put one time only things in here */
+ while (p->tag) {
+ p->len = strlen(p->token);
+ p++;
+ }
+ while (p1->part) {
+ p1->len = strlen(p1->s);
+ p1++;
+ }
+
+ done = 1;
+ }
}