18 struct { void * state; ldropt fun; } opt;
19 struct { void * state; ldrheader fun; } header;
20 struct { void * state; ldradd fun; } add;
28 static void * ldrstdalloc (void * mem, size_t bytes) {
30 return malloc (bytes);
33 static void ldrstdealloc (void * mem, void * ptr, size_t bytes) {
39 static void * ldrstdrealloc (void * mem, void * ptr, size_t ob, size_t nb) {
42 return realloc (ptr, nb);
46 return ldrminit (0, ldrstdalloc, ldrstdrealloc, ldrstdealloc);
49 LDR * ldrminit (void * state,
50 ldralloc alloc, ldrealloc realloc, ldrdealloc dealloc) {
51 LDR * res = alloc (state, sizeof *res);
53 memset (res, 0, sizeof *res);
54 res->mem.state = state;
55 res->mem.alloc = alloc;
56 res->mem.dealloc = dealloc;
60 static void ldrdelstr (LDR * ldr, char * str) {
61 if (str) ldr->mem.dealloc (ldr->mem.state, str, strlen (str) + 1);
64 static char * ldrstrdup (LDR * ldr, const char* str) {
65 size_t bytes = strlen (str) + 1;
66 char * res = ldr->mem.alloc (ldr->mem.state, bytes);
67 return strcpy (res, str);
70 void ldrelease (LDR * ldr) {
72 if (ldr->closefile == 1) fclose (ldr->file);
73 if (ldr->closefile == 2) pclose (ldr->file);
75 ldrdelstr (ldr, ldr->errmsg);
76 ldrdelstr (ldr, ldr->path);
77 ldr->mem.dealloc (ldr->mem.state, ldr, sizeof *ldr);
80 void ldrsetopt (LDR * ldr, void * state, ldropt fun) {
82 ldr->opt.state = state;
85 void ldrsetheader (LDR * ldr, void * state, ldrheader fun) {
86 ldr->header.fun = fun;
87 ldr->header.state = state;
90 void ldrsetadd (LDR * ldr, void * state, ldradd fun) {
92 ldr->add.state = state;
95 static int ldrfilexists (const char * path) {
97 return !stat (path, &buf);
100 static int ldrperr (LDR * ldr, const char * msg) {
103 assert (!ldr->errmsg);
105 bytes = strlen (msg) + strlen (ldr->path) + 20;
106 str = ldr->mem.alloc (ldr->mem.state, bytes);
107 sprintf (str, "%s:%d: %s", ldr->path, ldr->lineno, msg);
108 len = strlen (str) + 1;
109 ldr->errmsg = strcpy (ldr->mem.alloc (ldr->mem.state, len), str);
110 ldr->mem.dealloc (ldr->mem.state, str, bytes);
114 static int ldrhas (const char * str, const char * suffix) {
115 int l = strlen (str), k = strlen (suffix);
117 return !strcmp (str + l - k, suffix);
120 static FILE * ldrcmd (LDR * ldr, const char * fmt, const char * name) {
122 int len = strlen (fmt) + strlen (name) + 1;
123 char * s = ldr->mem.alloc (ldr->mem.state, len);
124 sprintf (s, fmt, name);
125 res = popen (s, "r");
126 ldr->mem.dealloc (ldr->mem.state, s, len);
130 void ldrsetpath (LDR * ldr, const char * path) {
133 assert (!ldr->closefile);
134 ldr->path = ldrstrdup (ldr, path);
135 if (!ldrfilexists (path))
136 return (void) ldrperr (ldr, "file does not exist");
138 if (ldrhas (path, ".gz"))
139 ldr->file = ldrcmd (ldr, "gunzip -c %s", path);
140 else if (ldrhas (path, ".bz2"))
141 ldr->file = ldrcmd (ldr, "bzcat %s", path);
142 else if (ldrhas (path, ".7z"))
143 ldr->file = ldrcmd (ldr, "7z x -so %s 2>/dev/null", path);
144 else if (ldrhas (path, ".lzma"))
145 ldr->file = ldrcmd (ldr, "lzcat %s", path);
146 else ldr->file = fopen (path, "r"), ldr->closefile = 1;
147 if (!ldr->file) return (void) ldrperr (ldr, "can not open file");
150 void ldrsetfile (LDR * ldr, FILE * file) {
153 assert (!ldr->closefile);
155 ldr->path = ldrstrdup (ldr, "<unspecified-path>");
158 void ldrsetnamedfile (LDR * ldr, FILE * file, const char * path) {
161 assert (!ldr->closefile);
163 ldr->path = ldrstrdup (ldr, path);
166 const char * ldrerr (LDR * ldr) { return ldr->errmsg; }
168 static int ldrnext (LDR * ldr) {
172 ch = getc (ldr->file);
173 if (ch == '\n') ldr->lineno++;
177 int ldrparse (LDR * ldr) {
178 struct { int parsed, specified; } vars, clauses;
179 int ch, sign, lit, digit;
180 if (ldr->errmsg) return 0;
181 while ((ch = ldrnext (ldr)) == 'c') {
182 // TODO parse embedded options
183 while ((ch = ldrnext (ldr)) != '\n')
185 return ldrperr (ldr, "end-of-file in comment before header");
187 if (ch != 'p') return ldrperr (ldr, "expected 'p' or 'c'");
188 if (ldrnext (ldr) != ' ') return ldrperr (ldr, "expected space after 'p'");
189 if (ldrnext (ldr) != 'c') return ldrperr (ldr, "expected 'c' after 'p '");
190 if (ldrnext (ldr) != 'n') return ldrperr (ldr, "expected 'n' after 'p c'");
191 if (ldrnext (ldr) != 'f') return ldrperr (ldr, "expected 'f' after 'p cn'");
192 if (ldrnext (ldr) != ' ')
193 return ldrperr (ldr, "expected space after 'p cnf'");
195 if (!isdigit (ch)) return ldrperr (ldr, "expected digit after 'p cnf '");
196 vars.specified = ch - '0';
197 while (isdigit (ch = ldrnext (ldr))) {
198 if (INT_MAX/10 < vars.specified)
200 return ldrperr (ldr, "number too large");
201 vars.specified *= 10;
203 if (INT_MAX - digit < vars.specified) goto NUMBER_TOO_LARGE;
204 vars.specified += digit;
207 return ldrperr (ldr, "expected space after maximum variable index");
208 if (!isdigit (ch = ldrnext (ldr)))
209 return ldrperr (ldr, "expected digit after space after variable index");
210 clauses.specified = ch - '0';
211 while (isdigit (ch = ldrnext (ldr))) {
212 if (INT_MAX/10 < clauses.specified) goto NUMBER_TOO_LARGE;
213 clauses.specified *= 10;
215 if (INT_MAX - digit < clauses.specified) goto NUMBER_TOO_LARGE;
216 clauses.specified += digit;
218 while (ch == ' ' || ch == '\t' || ch == '\r')
220 if (ch != '\n') return ldrperr (ldr, "expected new line after header");
222 ldr->header.fun (ldr->header.state, vars.specified, clauses.specified);
223 vars.parsed = clauses.parsed = 0;
227 if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') continue;
229 while ((ch = ldrnext (ldr)) != '\n') {
231 return ldrperr (ldr, "end-of-file in comment after header");
236 if (lit) return ldrperr (ldr, "zero sentinel missing at end-of-file");
237 assert (clauses.parsed <= clauses.specified);
238 if (clauses.parsed + 1 == clauses.specified)
239 return ldrperr (ldr, "one clause is missing");
240 if (clauses.parsed < clauses.specified)
241 return ldrperr (ldr, "clauses are missing");
246 if (!isdigit (ch)) return ldrperr (ldr, "expected digit after '-'");
248 } else if (!isdigit (ch)) return ldrperr (ldr, "expected digit or '-'");
250 assert (clauses.parsed <= clauses.specified);
251 if (clauses.specified == clauses.parsed)
252 return ldrperr (ldr, "too many clauses");
254 while (isdigit (ch = ldrnext (ldr))) {
255 if (INT_MAX/10 < lit) goto NUMBER_TOO_LARGE;
258 if (INT_MAX - digit < lit) goto NUMBER_TOO_LARGE;
262 if (lit > vars.specified)
263 return ldrperr (ldr, "maximum variable index exceeded");
265 assert ((sign < 0) == (lit < 0));
266 if (ldr->add.fun) ldr->add.fun (ldr->add.state, lit);
269 assert (clauses.parsed <= clauses.specified);