+/* --- @hfparse@ --- *
+ *
+ * Arguments: @hfpctx *hfp@ = pointer to the context structure
+ *
+ * Returns: A code indicating what happened.
+ *
+ * Use: Parses a line from the input file.
+ */
+
+int hfparse(hfpctx *hfp)
+{
+ char *p, *q;
+ const gchash *gch;
+ const encodeops *ee;
+ dstr *d = hfp->dline;
+ size_t hsz;
+
+ /* --- Fetch the input line and get ready to parse --- */
+
+ DRESET(d);
+ if (dstr_putline(d, hfp->fp) == EOF) return (HF_EOF);
+ p = d->buf;
+
+ /* --- Parse magic comments --- */
+
+ if (*p == '#') {
+ p++;
+ if ((q = str_getword(&p)) == 0) return (HF_BAD);
+ if (strcmp(q, "hash") == 0) {
+ if ((q = str_getword(&p)) == 0) return (HF_BAD);
+ if ((gch = gethash(q)) == 0) return (HF_BAD);
+ hfp->gch = gch;
+ return (HF_HASH);
+ } else if (strcmp(q, "encoding") == 0) {
+ if ((q = str_getword(&p)) == 0) return (HF_BAD);
+ if ((ee = getencoding(q)) == 0) return (HF_BAD);
+ hfp->ee = ee;
+ return (HF_ENC);
+ } else if (strcmp(q, "escape") == 0) {
+ hfp->f |= HFF_ESCAPE;
+ return (HF_ESC);
+ }
+ return (HF_BAD);
+ }
+
+ /* --- Otherwise it's a file line --- */
+
+ q = p;
+ while (*p && *p != ' ') p++;
+ if (!*p) return (HF_BAD);
+ *p++ = 0;
+ hsz = hfp->gch->hashsz;
+ if (hfp->ee->get(q, hfp->hbuf, hsz, 0) < hsz) return (HF_BAD);
+ switch (*p) {
+ case '*': hfp->f |= FHF_BINARY; break;
+ case ' ': hfp->f &= ~FHF_BINARY; break;
+ default: return (HF_BAD);
+ }
+ p++;
+
+ DRESET(hfp->dfile);
+ if (hfp->f & HFF_ESCAPE)
+ getstring(&p, hfp->dfile, GSF_STRING);
+ else {
+ dstr_putm(hfp->dfile, p, d->len - (p - d->buf));
+ dstr_putz(hfp->dfile);
+ }
+
+ return (HF_FILE);
+}
+