Commit 18f8cff7 authored by Richard P. Curnow's avatar Richard P. Curnow

Merge master

parents 9bc619a0 f91d723e
*.o
*.swp
*.report
.RELEASES
Makefile
RELEASES
config.log
datescan.c
datescan.h
fromcheck.c
fromcheck.h
mairix
mairix.dvi
mairix.html
mairix.info
mairix.pdf
mairix.txt
make.log
nvpscan.c
nvpscan.h
nvp.report
test
test_*
version.h
......@@ -49,7 +49,8 @@ docdir=$(DESTDIR)@docdir@
OBJ = mairix.o db.o rfc822.o tok.o hash.o dirscan.o writer.o \
reader.o search.o stats.o dates.o datescan.o mbox.o md5.o \
fromcheck.o glob.o dumper.o expandstr.o dotlock.o
fromcheck.o glob.o dumper.o expandstr.o dotlock.o \
nvp.o nvpscan.o
all : mairix
......@@ -65,10 +66,12 @@ datescan.c datescan.h : datescan.nfa ./dfasyn/dfasyn
fromcheck.c fromcheck.h : fromcheck.nfa ./dfasyn/dfasyn
./dfasyn/dfasyn -o fromcheck.c -ho fromcheck.h -r fromcheck.report -v -u fromcheck.nfa
dates.o : datescan.h
mbox.o : fromcheck.h
nvpscan.c nvpscan.h : nvp.nfa ./dfasyn/dfasyn
./dfasyn/dfasyn -o nvpscan.c -ho nvpscan.h -r nvpscan.report -v -u nvp.nfa
dates.o : datescan.h
mbox.o : fromcheck.h
nvp.o : nvpscan.h
version.h:
./mkversion
......@@ -79,7 +82,8 @@ version.h:
clean:
-rm -f *~ *.o mairix *.s core
-rm -f mairix.cp mairix.fn mairix.aux mairix.log mairix.ky mairix.pg mairix.toc mairix.tp mairix.vr
-rm -f fromcheck.c datescan.c
-rm -f fromcheck.[ch] datescan.[ch]
-rm -f nvpscan.[ch]
if [ -d dfasyn ]; then cd dfasyn ; make clean ; fi
distclean: clean
......
......@@ -333,6 +333,12 @@ int scan_date_string(char *in, time_t *start, int *has_start, time_t *end, int *
time(&now);
start_tm = end_tm = *localtime(&now);
start_tm.tm_hour = 0;
start_tm.tm_min = 0;
start_tm.tm_sec = 0;
end_tm.tm_hour = 23;
end_tm.tm_min = 59;
end_tm.tm_sec = 59;
hyphen = strchr(in, '-');
if (!hyphen) {
......
......@@ -182,6 +182,8 @@ void check_database_integrity(struct database *db)/*{{{*/
check_toktable_enc_integrity(db->n_msgs, db->subject);
if (verbose) fprintf(stderr, "Checking body\n");
check_toktable_enc_integrity(db->n_msgs, db->body);
if (verbose) fprintf(stderr, "Checking attachment_name\n");
check_toktable_enc_integrity(db->n_msgs, db->attachment_name);
}
/*}}}*/
struct database *new_database(void)/*{{{*/
......@@ -195,6 +197,7 @@ struct database *new_database(void)/*{{{*/
result->from = new_toktable();
result->subject = new_toktable();
result->body = new_toktable();
result->attachment_name = new_toktable();
result->msg_ids = new_toktable2();
......@@ -223,6 +226,7 @@ void free_database(struct database *db)/*{{{*/
free_toktable(db->from);
free_toktable(db->subject);
free_toktable(db->body);
free_toktable(db->attachment_name);
free_toktable2(db->msg_ids);
if (db->msgs) {
......@@ -451,7 +455,7 @@ struct database *new_database_from_file(char *db_filename, int do_integrity_chec
}
for (i=0; i<n; i++) {
switch (input->msg_type[i]) {
switch (rd_msg_type(input, i)) {
case DB_MSG_DEAD:
result->type[i] = MTY_DEAD;
break;
......@@ -480,6 +484,9 @@ struct database *new_database_from_file(char *db_filename, int do_integrity_chec
break;
}
result->msgs[i].seen = (input->msg_type_and_flags[i] & FLAG_SEEN) ? 1:0;
result->msgs[i].replied = (input->msg_type_and_flags[i] & FLAG_REPLIED) ? 1:0;
result->msgs[i].flagged = (input->msg_type_and_flags[i] & FLAG_FLAGGED) ? 1:0;
result->msgs[i].date = input->date_table[i];
result->msgs[i].tid = input->tid_table[i];
}
......@@ -489,6 +496,7 @@ struct database *new_database_from_file(char *db_filename, int do_integrity_chec
import_toktable(input->data, input->hash_key, result->n_msgs, &input->from, result->from);
import_toktable(input->data, input->hash_key, result->n_msgs, &input->subject, result->subject);
import_toktable(input->data, input->hash_key, result->n_msgs, &input->body, result->body);
import_toktable(input->data, input->hash_key, result->n_msgs, &input->attachment_name, result->body);
import_toktable2(input->data, input->hash_key, result->n_msgs, &input->msg_ids, result->msg_ids);
close_db(input);
......@@ -663,6 +671,10 @@ void tokenise_message(int file_index, struct database *db, struct rfc822 *msg)/*
break;
}
if (a->filename) {
add_token_in_file(file_index, db->hash_key, a->filename, db->attachment_name);
}
}
/* Deal with threading information */
......@@ -671,6 +683,32 @@ void tokenise_message(int file_index, struct database *db, struct rfc822 *msg)/*
add_angled_terms(file_index, db->hash_key, db->msg_ids, 0, msg->hdrs.references);
}
/*}}}*/
static void scan_maildir_flags(struct msgpath *m)/*{{{*/
{
const char *p, *start;
start = m->src.mpf.path;
m->seen = 0;
m->replied = 0;
m->flagged = 0;
for (p=start; *p; p++) {}
for (p--; (p >= start) && ((*p) != ':'); p--) {}
if (p >= start) {
if (!strncmp(p, ":2,", 3)) {
p += 3;
while (*p) {
switch (*p) {
case 'F': m->flagged = 1; break;
case 'R': m->replied = 1; break;
case 'S': m->seen = 1; break;
default: break;
}
p++;
}
}
}
}
/*}}}*/
static void scan_new_messages(struct database *db, int start_at)/*{{{*/
{
int i;
......@@ -691,6 +729,7 @@ static void scan_new_messages(struct database *db, int start_at)/*{{{*/
if(msg)
{
db->msgs[i].date = msg->hdrs.date;
scan_maildir_flags(&db->msgs[i]);
tokenise_message(i, db, msg);
free_rfc822(msg);
}
......@@ -838,7 +877,23 @@ static void add_msg_path(struct database *db, char *path, time_t mtime, size_t m
++db->n_msgs;
}
/*}}}*/
int update_database(struct database *db, struct msgpath *sorted_paths, int n_msgs)/*{{{*/
static int do_stat(struct msgpath *mp)/*{{{*/
{
struct stat sb;
int status;
status = stat(mp->src.mpf.path, &sb);
if ((status < 0) ||
!S_ISREG(sb.st_mode)) {
return 0;
} else {
mp->src.mpf.mtime = sb.st_mtime;
mp->src.mpf.size = sb.st_size;
return 1;
}
}
/*}}}*/
int update_database(struct database *db, struct msgpath *sorted_paths, int n_msgs, int do_fast_index)/*{{{*/
{
/* The incoming list must be sorted into order, to make binary searching
* possible. We search for each existing path in the incoming sorted array.
......@@ -853,6 +908,7 @@ int update_database(struct database *db, struct msgpath *sorted_paths, int n_msg
int matched_index;
int i, new_entries_start_at;
int any_new, n_newly_pruned, n_already_dead;
int status;
file_in_db = new_array(char, n_msgs);
file_in_new_list = new_array(char, db->n_msgs);
......@@ -866,11 +922,27 @@ int update_database(struct database *db, struct msgpath *sorted_paths, int n_msg
switch (db->type[i]) {
case MTY_FILE:
matched_index = lookup_msgpath(sorted_paths, n_msgs, db->msgs[i].src.mpf.path);
if ((matched_index >= 0) &&
(sorted_paths[matched_index].src.mpf.mtime == db->msgs[i].src.mpf.mtime)) {
/* Treat stale files as though the path has changed. */
file_in_db[matched_index] = 1;
file_in_new_list[i] = 1;
if (matched_index >= 0) {
if (do_fast_index) {
/* Assume the presence of a matching path is good enough without
* even bothering to stat the file that's there now. */
file_in_db[matched_index] = 1;
file_in_new_list[i] = 1;
} else {
status = do_stat(sorted_paths + matched_index);
if (status) {
if (sorted_paths[matched_index].src.mpf.mtime == db->msgs[i].src.mpf.mtime) {
/* Treat stale files as though the path has changed. */
file_in_db[matched_index] = 1;
file_in_new_list[i] = 1;
} else {
fprintf(stderr, "mtime failed for '%s'\n", sorted_paths[matched_index].src.mpf.path);
}
} else {
/* This path will get treated as dead, and be re-stated below.
* When that stat fails, the path won't get added to the db. */
}
}
}
break;
case MTY_MBOX:
......@@ -924,9 +996,17 @@ int update_database(struct database *db, struct msgpath *sorted_paths, int n_msg
any_new = 0;
for (i=0; i<n_msgs; i++) {
if (!file_in_db[i]) {
int status;
any_new = 1;
/* The 'sorted_paths' array is only used for file-per-message folders. */
add_msg_path(db, sorted_paths[i].src.mpf.path, sorted_paths[i].src.mpf.mtime, sorted_paths[i].src.mpf.size);
status = do_stat(sorted_paths + i);
if (status) {
/* We only add files that could be successfully stat()'d as regular
* files. */
add_msg_path(db, sorted_paths[i].src.mpf.path, sorted_paths[i].src.mpf.mtime, sorted_paths[i].src.mpf.size);
} else {
fprintf(stderr, "Cannot add '%s' to database; stat() failed\n", sorted_paths[i].src.mpf.path);
}
}
}
......@@ -1180,6 +1260,7 @@ int cull_dead_messages(struct database *db, int do_integrity_checks)/*{{{*/
recode_toktable(db->from, new_idx);
recode_toktable(db->subject, new_idx);
recode_toktable(db->body, new_idx);
recode_toktable(db->attachment_name, new_idx);
recode_toktable2(db->msg_ids, new_idx);
/* And crunch down the filename table */
......
./dfasyn rc@rc0.org.uk--2004-dfasyn/dfasyn--dev--0
......@@ -342,7 +342,11 @@ void print_charclass_mapping(FILE *out, FILE *header_out, const char *prefix_und
for (i=0; i<256; i++) {
if (i > 0) fputs(", ", out);
if ((i & 15) == 0) fputs("\n ", out);
fprintf(out, "%3d", mapping[i]);
if (mapping[i] >= 0) {
fprintf(out, "%3d", mapping[i] + ntokens);
} else {
fprintf(out, "%3d", mapping[i]);
}
}
fputs("\n};\n", out);
if (header_out) {
......
......@@ -242,6 +242,7 @@ attr_decl_seq : /* empty */
;
tag_decl : TAG STRING EQUAL expr { define_tag($2, $4); }
;
entrystruct_decl :
ENTRYSTRUCT STRING STRING { define_entrystruct($2, $3); }
......
......@@ -62,7 +62,7 @@ void free_msgpath_array(struct msgpath_array *x)/*{{{*/
free(x);
}
/*}}}*/
static void add_file_to_list(char *x, unsigned long mtime, size_t message_size, struct msgpath_array *arr) {/*{{{*/
static void add_file_to_list(char *x, struct msgpath_array *arr) {/*{{{*/
char *y = new_string(x);
if (arr->n == arr->max) {
arr->max += 1024;
......@@ -71,8 +71,6 @@ static void add_file_to_list(char *x, unsigned long mtime, size_t message_size,
}
arr->type[arr->n] = MTY_FILE;
arr->paths[arr->n].src.mpf.path = y;
arr->paths[arr->n].src.mpf.mtime = mtime;
arr->paths[arr->n].src.mpf.size = message_size;
++arr->n;
return;
}
......@@ -84,7 +82,6 @@ static void get_maildir_message_paths(char *folder, struct msgpath_array *arr)/*
static char *subdirs[] = {"new", "cur"};
DIR *d;
struct dirent *de;
struct stat sb;
int folder_len = strlen(folder);
/* FIXME : just store mdir-rooted paths in array and have common prefix elsewhere. */
......@@ -100,14 +97,14 @@ static void get_maildir_message_paths(char *folder, struct msgpath_array *arr)/*
while ((de = readdir(d))) {
/* TODO : Perhaps we ought to do some validation on the path here?
i.e. check that the filename looks valid for a maildir message. */
if (!strcmp(de->d_name, ".") ||
!strcmp(de->d_name, "..")) {
continue;
}
strcpy(fname, subdir);
strcat(fname, "/");
strcat(fname, de->d_name);
if (stat(fname, &sb) >= 0) {
if (S_ISREG(sb.st_mode)) {
add_file_to_list(fname, sb.st_mtime, sb.st_size, arr);
}
}
add_file_to_list(fname, arr);
}
closedir(d);
}
......@@ -140,7 +137,6 @@ static void get_mh_message_paths(char *folder, struct msgpath_array *arr)/*{{{*/
char *fname;
DIR *d;
struct dirent *de;
struct stat sb;
int folder_len = strlen(folder);
fname = new_array(char, folder_len + 8 + NAME_MAX);
......@@ -150,12 +146,8 @@ static void get_mh_message_paths(char *folder, struct msgpath_array *arr)/*{{{*/
strcpy(fname, folder);
strcat(fname, "/");
strcat(fname, de->d_name);
if (stat(fname, &sb) >= 0) {
if (S_ISREG(sb.st_mode)) {
if (valid_mh_filename_p(de->d_name)) {
add_file_to_list(fname, sb.st_mtime, sb.st_size, arr);
}
}
if (valid_mh_filename_p(de->d_name)) {
add_file_to_list(fname, arr);
}
}
closedir(d);
......
......@@ -76,7 +76,7 @@ void dump_database(char *filename)
printf("%d messages\n", db->n_msgs);
for (i=0; i<db->n_msgs; i++) {
printf("%6d: ", i);
switch (db->msg_type[i]) {
switch (rd_msg_type(db, i)) {
case DB_MSG_DEAD:
printf("DEAD");
break;
......@@ -94,6 +94,9 @@ void dump_database(char *filename)
}
break;
}
if (db->msg_type_and_flags[i] & FLAG_SEEN) printf(" seen");
if (db->msg_type_and_flags[i] & FLAG_REPLIED) printf(" replied");
if (db->msg_type_and_flags[i] & FLAG_FLAGGED) printf(" flagged");
printf("\n");
}
printf("\n");
......@@ -122,6 +125,8 @@ void dump_database(char *filename)
printf("--------------------------------\n");
dump_toktable(db, &db->body, "Body");
printf("--------------------------------\n");
dump_toktable(db, &db->attachment_name, "Attachment names");
printf("--------------------------------\n");
close_db(db);
return;
......
......@@ -37,6 +37,8 @@ mairix \- index and search mail folders
] [
.BR \-f | \-\-rcfile
.I mairixrc
] [
.BR \-F | \-\-fast-index
]
.SS Searching
......@@ -175,6 +177,24 @@ Cause stale (dead) messages to be purged from the database during an indexing
run. (Normally, stale messages are left in the database because of the
additional const of compacting away the storage that they take up.)
.TP
.B -F, --fast-index
.br
When processing maildir and MH folders,
.I mairix
normally compares the mtime and size of each message against the values stored
in the database. If they have changed, the message will be rescanned. This
check requires each message file to be stat'ed. For large numbers of messages
in these folder types, this can be a sizeable overhead.
This option tells
.I mairix
to assume that when a message currently on-disc has a name matching one already
in the database, it should assume the message is unchanged.
A later indexing run without using this option will fix up any rescans that
were missed due to its use.
.SS Search options
.TP
.B -a, --augment
......@@ -290,6 +310,47 @@ mairix z:10k-20k
The suffix 'k' on a number means multiply by 1024, and the suffix 'M' on a
number means multiply by 1024*1024.
.TP
.BI n: word
.br
Match
.I word
occurring as the name of an attachment in the message. Since attachment names
are usually long, this option would usually be used in the substring form. So
.Sy 1
mairix n:mairix=
.Ey
would match all messages which have attachments whose names contain the
substring
.IR mairix .
The attachment name is determined from the name=xxx or filename=xxx qualifiers
on the Content-Type: and Content-Disposition: headers respectively.
.TP
.BI F: flags
.br
Match messages with particular flag settings. The available flags are 's'
meaning seen, 'r' meaning replied, and 'f' meaning flagged. The flags are
case-insensitive. A flag letter may be prefixed by a '-' to negate its sense. Thus
.Sy 1
mairix F:-s d:1w-
.Ey
would match any unread message less than a week old, and
.Sy 1
mairix F:f-r d:-1m
.Ey
would match any flagged message older than a month which you haven't replied to yet.
Note that the flag characters and their meanings agree with those used as the
suffix letters on message filenames in maildir folders.
.SS Searching for a match amongst more than one part of a message
.PP
Multiple body parts may be grouped together, if a match in any of them is
sought. Common examples follow.
......
......@@ -391,7 +391,7 @@ static void usage(void)/*{{{*/
print_copyright();
printf("mairix [-h] : Show help\n"
"mairix [-f <rcfile>] [-v] [-p] : Build index\n"
"mairix [-f <rcfile>] [-v] [-p] [-F] : Build index\n"
"mairix [-f <rcfile>] [-a] [-t] expr1 ... exprN : Run search\n"
"mairix [-f <rcfile>] -d : Dump database to stdout\n"
"-h : show this help\n"
......@@ -399,6 +399,7 @@ static void usage(void)/*{{{*/
"-V : show version\n"
"-v : be verbose\n"
"-p : purge messages that no longer exist\n"
"-F : fast scan for maildir and MH folders (no mtime or size checks)\n"
"-a : add new matches to match folder (default : clear it first)\n"
"-t : include all messages in same threads as matching messages\n"
"-o <mfolder> : override setting of mfolder from mairixrc file\n"
......@@ -412,6 +413,8 @@ static void usage(void)/*{{{*/
" s:word : match word in Subject: header\n"
" b:word : match word in message body\n"
" m:word : match word in Message-ID: header\n"
" n:word : match name of attachment within message\n"
" F:flags : match on message flags (s=seen,r=replied,f=flagged,-=negate)\n"
" p:substring : match substring of path\n"
" d:start-end : match date range\n"
" z:low-high : match messages in size range\n"
......@@ -473,6 +476,7 @@ int main (int argc, char **argv)/*{{{*/
int do_dump = 0;
int do_integrity_checks = 1;
int do_forced_unlock = 0;
int do_fast_index = 0;
struct globber_array *omit_globs;
......@@ -507,6 +511,9 @@ int main (int argc, char **argv)/*{{{*/
do_integrity_checks = 0;
} else if (!strcmp(*argv, "--unlock")) {
do_forced_unlock = 1;
} else if (!strcmp(*argv, "-F") ||
!strcmp(*argv, "--fast-index")) {
do_fast_index = 1;
} else if (!strcmp(*argv, "-v") || !strcmp(*argv, "--verbose")) {
verbose = 1;
} else if (!strcmp(*argv, "-V") || !strcmp(*argv, "--version")) {
......@@ -701,7 +708,7 @@ int main (int argc, char **argv)/*{{{*/
build_mbox_lists(db, folder_base, mboxen, omit_globs);
any_updates = update_database(db, msgs->paths, msgs->n);
any_updates = update_database(db, msgs->paths, msgs->n, do_fast_index);
if (do_purge) {
any_purges = cull_dead_messages(db, do_integrity_checks);
}
......
......@@ -51,6 +51,12 @@ struct msgpath {/*{{{*/
/* Now fields that are common to both types of message. */
time_t date; /* representation of Date: header in message */
int tid; /* thread-id */
/* Message flags. */
unsigned int seen:1;
unsigned int replied:1;
unsigned int flagged:1;
/* + other stuff eventually */
};
/*}}}*/
......@@ -122,6 +128,7 @@ struct attachment {/*{{{*/
struct attachment *next;
struct attachment *prev;
enum content_type ct;
char *filename;
union attachment_body {
struct normal_attachment_body {
int len;
......@@ -142,6 +149,12 @@ struct headers {/*{{{*/
char *in_reply_to;
char *references;
struct {
unsigned int seen:1;
unsigned int replied:1;
unsigned int flagged:1;
} flags;
time_t date;
};
/*}}}*/
......@@ -220,6 +233,7 @@ struct database {/*{{{*/
struct toktable *from;
struct toktable *subject;
struct toktable *body;
struct toktable *attachment_name;
/* Encoding chain 0 stores all msgids appearing in the following message headers:
* Message-Id, In-Reply-To, References. Used for thread reconciliation.
......@@ -337,7 +351,7 @@ struct database *new_database_from_file(char *db_filename, int do_integrity_chec
void free_database(struct database *db);
void maybe_grow_message_arrays(struct database *db);
void tokenise_message(int file_index, struct database *db, struct rfc822 *msg);
int update_database(struct database *db, struct msgpath *sorted_paths, int n_paths);
int update_database(struct database *db, struct msgpath *sorted_paths, int n_paths, int do_fast_index);
void check_database_integrity(struct database *db);
int cull_dead_messages(struct database *db, int do_integrity_checks);
......
......@@ -945,6 +945,9 @@ int add_mbox_messages(struct database *db)/*{{{*/
printf("Scanning %s[%d] at [%d,%d)\n", mb->path, j, (int)start, (int)(start + len));
}
db->msgs[n].date = r8->hdrs.date;
db->msgs[n].seen = r8->hdrs.flags.seen;
db->msgs[n].replied = r8->hdrs.flags.replied;
db->msgs[n].flagged = r8->hdrs.flags.flagged;
tokenise_message(n, db, r8);
free_rfc822(r8);
} else {
......
/*
mairix - message index builder and finder for maildir folders.
**********************************************************************
* Copyright (C) Richard P. Curnow 2006
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
**********************************************************************
*/
/* Parse name/value pairs from mail headers into a lookup table. */
#include <stdio.h>
#include <ctype.h>
#include "mairix.h"
#include "nvptypes.h"
#include "nvpscan.h"
#include "nvp.h"
enum nvp_type {/*{{{*/
NVP_NAME,
NVP_MAJORMINOR,
NVP_NAMEVALUE
};
/*}}}*/
struct nvp_entry {/*{{{*/
struct nvp_entry *next;
struct nvp_entry *prev;
enum nvp_type type;
char *lhs;
char *rhs;
};
/*}}}*/
struct nvp {/*{{{*/
struct nvp_entry *first, *last;
};
/*}}}*/
static void append(struct nvp *nvp, struct nvp_entry *ne)/*{{{*/
{
ne->next = NULL;
ne->prev = nvp->last;
if (nvp->last) nvp->last->next = ne;
else nvp->first = ne;
nvp->last = ne;
}
/*}}}*/
static void append_name(struct nvp *nvp, char *name)/*{{{*/
{
struct nvp_entry *ne;
ne = new(struct nvp_entry);
ne->type = NVP_NAME;
ne->lhs = new_string(name);
append(nvp, ne);
}
/*}}}*/
static void append_majorminor(struct nvp *nvp, char *major, char *minor)/*{{{*/
{
struct nvp_entry *ne;
ne = new(struct nvp_entry);
ne->type = NVP_MAJORMINOR;
ne->lhs = new_string(major);
ne->rhs = new_string(minor);
append(nvp, ne);
}
/*}}}*/
static void append_namevalue(struct nvp *nvp, char *name, char *value)/*{{{*/
{
struct nvp_entry *ne;
ne = new(struct nvp_entry);
ne->type = NVP_NAMEVALUE;
ne->lhs = new_string(name);
ne->rhs = new_string(value);
append(nvp, ne);
}
/*}}}*/
struct nvp *make_nvp(char *s)/*{{{*/
{
int current_state;
unsigned int tok;
char *q;
char name[256];
char minor[256];
char value[256];
enum nvp_action last_action, current_action;
struct nvp *result;
char *nn, *mm, *vv;
result = new(struct nvp);
result->first = result->last = NULL;
current_state = nvp_in;
q = s;
nn = name;
mm = minor;
vv = value;
last_action = GOT_NOTHING;
do {
tok = *(unsigned char *) q;
if (tok) {
tok = nvp_char2tok[tok];
} else {
tok = nvp_EOS;
}
current_state = nvp_next_state(current_state, tok);
#if 0
printf("char %02x '%c' meta=%2d state'=%2d ",
*q,
(*q >= 32 && *q <= 126) ? *q : '.',
tok,
current_state
);
#endif
switch (nvp_copier[current_state]) {
case COPY_TO_NAME:
*nn++ = *q;
break;
case COPY_TO_MINOR:
*mm++ = *q;
break;
case COPY_TO_VALUE:
*vv++ = *q;
break;
case COPY_NOWHERE:
break;
}
current_action = nvp_action[current_state];
switch (current_action) {
case GOT_NAME:
case GOT_NAME_TRAILING_SPACE:
case GOT_MAJORMINOR:
case GOT_NAMEVALUE:
last_action = current_action;
break;
case GOT_TERMINATOR:
switch (last_action) {
case GOT_NAME:
*nn = 0;
append_name(result, name);
break;
case GOT_NAME_TRAILING_SPACE:
while (isspace(*--nn)) {}
*++nn = 0;
append_name(result, name);
break;
case GOT_MAJORMINOR:
*nn = 0;
*mm = 0;
append_majorminor(result, name, minor);
break;
case GOT_NAMEVALUE:
*nn = 0;
*vv = 0;
append_namevalue(result, name, value);
break;
default:
break;
}
nn = name;
mm = minor;
vv = value;
break;
case GOT_NOTHING: