jaromail

a commandline tool to easily and privately handle your e-mail
git clone git://parazyd.org/jaromail.git
Log | Files | Refs | Submodules | README

commit 47db8fc58175f1404a24b7dd4ce73fd95e83f018
parent 178c5e4636f5d2168423f2d51115a615609e4952
Author: Jaromil <jaromil@dyne.org>
Date:   Tue,  6 Jan 2015 19:13:12 +0100

removed mairix from codebase

Diffstat:
Dsrc/fetchdate.c | 152-------------------------------------------------------------------------------
Dsrc/mairix.h | 403-------------------------------------------------------------------------------
Dsrc/mairix/ACKNOWLEDGEMENTS | 60------------------------------------------------------------
Dsrc/mairix/COPYING | 339-------------------------------------------------------------------------------
Dsrc/mairix/INSTALL | 22----------------------
Dsrc/mairix/Makefile.in | 114-------------------------------------------------------------------------------
Dsrc/mairix/NEWS | 317-------------------------------------------------------------------------------
Dsrc/mairix/README | 63---------------------------------------------------------------
Dsrc/mairix/configure | 337-------------------------------------------------------------------------------
Dsrc/mairix/dates.c | 404-------------------------------------------------------------------------------
Dsrc/mairix/dates.h | 45---------------------------------------------
Dsrc/mairix/datescan.nfa | 112-------------------------------------------------------------------------------
Dsrc/mairix/datescan.report | 3303-------------------------------------------------------------------------------
Dsrc/mairix/db.c | 1297-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/COPYING | 339-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/INSTALL | 19-------------------
Dsrc/mairix/dfasyn/Makefile | 62--------------------------------------------------------------
Dsrc/mairix/dfasyn/NEWS | 5-----
Dsrc/mairix/dfasyn/README | 8--------
Dsrc/mairix/dfasyn/abbrevs.c | 67-------------------------------------------------------------------
Dsrc/mairix/dfasyn/blocks.c | 168-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/charclass.c | 364-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/compdfa.c | 479-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/configure | 4----
Dsrc/mairix/dfasyn/dfasyn.1 | 154-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/dfasyn.5 | 650-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/dfasyn.c | 690-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/dfasyn.h | 365-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/dfasyn.texi | 85-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/evaluator.c | 248-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/expr.c | 243-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/n2d.c | 696-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/n2d.h | 226-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/parse.y | 262-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/scan.l | 111-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/states.c | 303-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/stimulus.c | 87-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/tabcompr.c | 181-------------------------------------------------------------------------------
Dsrc/mairix/dfasyn/tokens.c | 85-------------------------------------------------------------------------------
Dsrc/mairix/dirscan.c | 420-------------------------------------------------------------------------------
Dsrc/mairix/dotlock.c | 116-------------------------------------------------------------------------------
Dsrc/mairix/dotmairixrc.eg | 41-----------------------------------------
Dsrc/mairix/dumper.c | 151------------------------------------------------------------------------------
Dsrc/mairix/expandstr.c | 196-------------------------------------------------------------------------------
Dsrc/mairix/from.h | 32--------------------------------
Dsrc/mairix/fromcheck.nfa | 218-------------------------------------------------------------------------------
Dsrc/mairix/fromcheck.report | 3222-------------------------------------------------------------------------------
Dsrc/mairix/glob.c | 393-------------------------------------------------------------------------------
Dsrc/mairix/hash.c | 143-------------------------------------------------------------------------------
Dsrc/mairix/mairix.1 | 673-------------------------------------------------------------------------------
Dsrc/mairix/mairix.c | 778-------------------------------------------------------------------------------
Dsrc/mairix/mairix.h | 403-------------------------------------------------------------------------------
Dsrc/mairix/mairix.spec | 45---------------------------------------------
Dsrc/mairix/mairixrc.5 | 405-------------------------------------------------------------------------------
Dsrc/mairix/mbox.c | 1060-------------------------------------------------------------------------------
Dsrc/mairix/md5.c | 322-------------------------------------------------------------------------------
Dsrc/mairix/md5.h | 62--------------------------------------------------------------
Dsrc/mairix/memmac.h | 72------------------------------------------------------------------------
Dsrc/mairix/mkversion | 15---------------
Dsrc/mairix/nvp.c | 416-------------------------------------------------------------------------------
Dsrc/mairix/nvp.h | 38--------------------------------------
Dsrc/mairix/nvp.nfa | 197-------------------------------------------------------------------------------
Dsrc/mairix/nvpscan.report | 6352-------------------------------------------------------------------------------
Dsrc/mairix/nvptypes.h | 43-------------------------------------------
Dsrc/mairix/old_docs/mairix.texi | 885-------------------------------------------------------------------------------
Dsrc/mairix/reader.c | 212-------------------------------------------------------------------------------
Dsrc/mairix/reader.h | 182-------------------------------------------------------------------------------
Dsrc/mairix/rfc822.c | 1536-------------------------------------------------------------------------------
Dsrc/mairix/search.c | 1445-------------------------------------------------------------------------------
Dsrc/mairix/stats.c | 128-------------------------------------------------------------------------------
Dsrc/mairix/tok.c | 344-------------------------------------------------------------------------------
Dsrc/mairix/version.h | 4----
Dsrc/mairix/version.txt | 1-
Dsrc/mairix/writer.c | 614-------------------------------------------------------------------------------
Dsrc/nvp.c | 416-------------------------------------------------------------------------------
Dsrc/nvp.h | 38--------------------------------------
Dsrc/nvp.nfa | 197-------------------------------------------------------------------------------
Dsrc/nvptypes.h | 43-------------------------------------------
Dsrc/rfc822_mairix.c | 1536-------------------------------------------------------------------------------
79 files changed, 0 insertions(+), 36263 deletions(-)

diff --git a/src/fetchdate.c b/src/fetchdate.c @@ -1,152 +0,0 @@ -/* Jaro Mail - * - * (C) Copyright 2012 Denis Roio <jaromil@dyne.org> - * - * This is just a simple use of Mairix API to extract formatted dates - * - * This source code is free software; you can redistribute it and/or - * modify it under the terms of the GNU Public License as published - * by the Free Software Foundation; either version 3 of the License, - * or (at your option) any later version. - * - * This source code 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. - * Please refer to the GNU Public License for more details. - * - * You should have received a copy of the GNU Public License along with - * this source code; if not, write to: - * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdio.h> -#include <mairix.h> - -#define TEST 1 - -int verbose = 0; -int do_hardlinks = 0; -int do_movefiles = 0; -char dateformat[256]; - -void out_of_mem(char *file, int line, size_t size); -void report_error(const char *str, const char *filename); -void emit_int(int x); - -static struct rfc822 *parsed; - -int main (int argc, char **argv) { - if( argc < 2 ) { - printf("usage: fetchdate filename strftime_format\n"); - printf("see man strftime(5) for format options"); - exit(1); - } - - if(argc>2) - snprintf(dateformat, 255, "%s", argv[2]); - else // default date format - strcpy(dateformat, "%a, %d %b %Y"); - - // printf("Parsing email: %s\n",argv[1]); - parsed = make_rfc822(argv[1]); - - if (parsed) { - char datebuf[64]; - struct tm *thetm; -#ifdef TEST - if (parsed->hdrs.to) printf(" To: %s\n", parsed->hdrs.to); - if (parsed->hdrs.cc) printf(" Cc: %s\n", parsed->hdrs.cc); - if (parsed->hdrs.from) printf(" From: %s\n", parsed->hdrs.from); - if (parsed->hdrs.subject) printf(" Subject: %s\n", parsed->hdrs.subject); - if (parsed->hdrs.message_id) - printf(" Message-ID: %s\n", parsed->hdrs.message_id); - thetm = gmtime(&parsed->hdrs.date); - strftime(datebuf, sizeof(datebuf), dateformat, thetm); - printf(" Date: %s\n", datebuf); -#else - thetm = gmtime(&parsed->hdrs.date); - strftime(datebuf, sizeof(datebuf), dateformat, thetm); - - /* needed by timecloud: - - [["YYYY-MM-DD",[["TAG1","WEIGHT1"], - ["TAG2","WEIGHT2"], - ... - ] - ], - ["YYYY-MM-DD",[....]] - ] - - */ - - printf("%s\n",datebuf); - -#endif - free_rfc822(parsed); - } - - exit(0); -} - -void out_of_mem(char *file, int line, size_t size)/*{{{*/ -{ - /* Hairy coding ahead - can't use any [s]printf, itoa etc because - * those might try to use the heap! */ - - int filelen; - char *p; - - static char msg1[] = "Out of memory (at "; - static char msg2[] = " bytes)\n"; - /* Perhaps even strlen is unsafe in this situation? */ - p = file; - while (*p) p++; - filelen = p - file; - write(2, msg1, sizeof(msg1)); - write(2, file, filelen); - write(2, ":", 1); - emit_int(line); - write(2, ", ", 2); - emit_int(size); - write(2, msg2, sizeof(msg2)); - exit(2); -} -/*}}}*/ -void report_error(const char *str, const char *filename)/*{{{*/ -{ - if (filename) { - int len = strlen(str) + strlen(filename) + 4; - char *t; - t = new_array(char, len); - sprintf(t, "%s '%s'", str, filename); - perror(t); - free(t); - } else { - perror(str); - } -} -void emit_int(int x)/*{{{*/ -{ - char buf1[20], buf2[20]; - char *p, *q; - int neg=0; - p = buf1; - *p = '0'; /* In case x is zero */ - if (x < 0) { - neg = 1; - x = -x; - } - while (x) { - *p++ = '0' + (x % 10); - x /= 10; - } - p--; - q = buf2; - if (neg) *q++ = '-'; - while (p >= buf1) { - *q++ = *p--; - } - write(2, buf2, q-buf2); - return; -} diff --git a/src/mairix.h b/src/mairix.h @@ -1,403 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002,2003,2004,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - - -#ifndef MAIRIX_H -#define MAIRIX_H - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "memmac.h" - -struct msgpath {/*{{{*/ - /* The 'selector' for this union is the corresponding entry of type 'enum - * message_type' */ - union { - struct { - char *path; - size_t size; /* size of the message in bytes */ - time_t mtime; /* mtime of message file on disc */ - } mpf; /* message per file */ - struct { - int file_index; /* index into table of mbox files */ - int msg_index; /* index of message within the file */ - } mbox; /* for messages in mbox format folders */ - } src; - - /* 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 */ -}; -/*}}}*/ - -enum message_type {/*{{{*/ - MTY_DEAD, /* msg no longer exists, i.e. don't report in searches, - prune it on a '-p' run. */ - MTY_FILE, /* msg <-> file in 1-1 correspondence e.g. maildir, MH */ - MTY_MBOX /* multiple msgs per file : MBOX format file */ -}; -/*}}}*/ -struct msgpath_array {/*{{{*/ - enum message_type *type; - struct msgpath *paths; - int n; - int max; -}; -/*}}}*/ - -struct matches {/*{{{*/ - unsigned char *msginfo; - int n; /* bytes in use */ - int max; /* bytes allocated */ - unsigned long highest; -}; -/*}}}*/ -struct token {/*{{{*/ - char *text; - unsigned long hashval; - /* to store delta-compressed info of which msgpaths match the token */ - struct matches match0; -}; -/*}}}*/ -struct token2 {/*{{{*/ - char *text; - unsigned long hashval; - /* to store delta-compressed info of which msgpaths match the token */ - struct matches match0; - struct matches match1; -}; -/*}}}*/ -struct toktable {/*{{{*/ - struct token **tokens; - int n; /* # in use */ - int size; /* # allocated */ - unsigned int mask; /* for masking down hash values */ - int hwm; /* number to have before expanding */ -}; -/*}}}*/ -struct toktable2 {/*{{{*/ - struct token2 **tokens; - int n; /* # in use */ - int size; /* # allocated */ - unsigned int mask; /* for masking down hash values */ - int hwm; /* number to have before expanding */ -}; -/*}}}*/ - -enum content_type {/*{{{*/ - CT_TEXT_PLAIN, - CT_TEXT_HTML, - CT_TEXT_OTHER, - CT_MESSAGE_RFC822, - CT_OTHER -}; -/*}}}*/ -struct rfc822; -struct attachment {/*{{{*/ - struct attachment *next; - struct attachment *prev; - enum content_type ct; - char *filename; - union attachment_body { - struct normal_attachment_body { - int len; - char *bytes; - } normal; - struct rfc822 *rfc822; - } data; -}; -/*}}}*/ -struct headers {/*{{{*/ - char *to; - char *cc; - char *from; - char *subject; - - /* The following are needed to support threading */ - char *message_id; - char *in_reply_to; - char *references; - - struct { - unsigned int seen:1; - unsigned int replied:1; - unsigned int flagged:1; - } flags; - - time_t date; -}; -/*}}}*/ -struct rfc822 {/*{{{*/ - struct headers hdrs; - struct attachment atts; -}; -/*}}}*/ - -typedef char checksum_t[16]; - -struct message_list {/*{{{*/ - struct message_list *next; - off_t start; - size_t len; -}; -/*}}}*/ -struct mbox {/*{{{*/ - /* If path==NULL, this indicates that the mbox is dead, i.e. no longer - * exists. */ - char *path; - /* As read in from database (i.e. current last time mairix scan was run.) */ - time_t file_mtime; - size_t file_size; - /* As found in the filesystem now. */ - time_t current_mtime; - size_t current_size; - /* After reconciling a loaded database with what's on the disc, this entry - stores how many of the msgs that used to be there last time are still - present at the head of the file. Thus, all messages beyond that are - treated as dead, and scanning starts at that point to find 'new' messages - (whch may actually be old ones that have moved, but they're treated as - new.) */ - int n_old_msgs_valid; - - /* Hold list of new messages and their number. Number is temporary - - * eventually just list walking in case >=2 have to be reattached. */ - struct message_list *new_msgs; - int n_new_msgs; - - int n_so_far; /* Used during database load. */ - - int n_msgs; /* Number of entries in 'start' and 'len' */ - int max_msgs; /* Allocated size of 'start' and 'len' */ - /* File offset to the start of each message (first line of real header, not to mbox 'From ' line) */ - off_t *start; - /* Length of each message */ - size_t *len; - /* Checksums on whole messages. */ - checksum_t *check_all; - -}; -/*}}}*/ -struct database {/*{{{*/ - /* Used to hold an entire mapping between an array of filenames, each - containing a single message, and the sets of tokens that occur in various - parts of those messages */ - - enum message_type *type; - struct msgpath *msgs; /* Paths to messages */ - int n_msgs; /* Number in use */ - int max_msgs; /* Space allocated */ - - struct mbox *mboxen; - int n_mboxen; /* number in use. */ - int max_mboxen; /* space allocated */ - - /* Seed for hashing in the token tables. Randomly created for - * each new database - avoid DoS attacks through carefully - * crafted messages. */ - unsigned int hash_key; - - /* Token tables */ - struct toktable *to; - struct toktable *cc; - 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. - * Encoding chain 1 stores just the Message-Id. Used for search by message ID. - */ - struct toktable2 *msg_ids; -}; -/*}}}*/ - -enum folder_type {/*{{{*/ - FT_MAILDIR, - FT_MH, - FT_MBOX, - FT_RAW, - FT_EXCERPT -}; -/*}}}*/ - -struct string_list {/*{{{*/ - struct string_list *next; - struct string_list *prev; - char *data; -}; -/*}}}*/ - -struct msg_src { - enum {MS_FILE, MS_MBOX} type; - char *filename; - off_t start; - size_t len; -}; - -/* Outcomes of checking a filename/dirname to see whether to keep on looking - * at filenames within this dir. */ -enum traverse_check { - TRAV_PROCESS, /* Continue looking at this entry */ - TRAV_IGNORE, /* Ignore just this dir entry */ - TRAV_FINISH /* Ignore this dir entry and don't bother looking at the rest of the directory */ -}; - -struct traverse_methods { - int (*filter)(const char *, const struct stat *); - enum traverse_check (*scrutinize)(int, const char *); -}; - -extern struct traverse_methods maildir_traverse_methods; -extern struct traverse_methods mh_traverse_methods; -extern struct traverse_methods mbox_traverse_methods; - -extern int verbose; /* cmd line -v switch */ -extern int do_hardlinks; /* cmd line -H switch */ -extern int do_movefiles; /* cmd line -M switch */ - -/* Lame fix for systems where NAME_MAX isn't defined after including the above - * set of .h files (Solaris, FreeBSD so far). Probably grossly oversized but - * it'll do. */ - -#if !defined(NAME_MAX) -#define NAME_MAX 4096 -#endif - -/* In glob.c */ -struct globber; -struct globber_array; - -struct globber *make_globber(const char *wildstring); -void free_globber(struct globber *old); -int is_glob_match(struct globber *g, const char *s); -struct globber_array *colon_sep_string_to_globber_array(const char *in); -int is_globber_array_match(struct globber_array *ga, const char *s); -void free_globber_array(struct globber_array *in); - -/* In hash.c */ -unsigned int hashfn( unsigned char *k, unsigned int length, unsigned int initval); - -/* In dirscan.c */ -struct msgpath_array *new_msgpath_array(void); -int valid_mh_filename_p(const char *x); -void free_msgpath_array(struct msgpath_array *x); -void string_list_to_array(struct string_list *list, int *n, char ***arr); -void split_on_colons(const char *str, int *n, char ***arr); -void build_message_list(char *folder_base, char *folders, enum folder_type ft, - struct msgpath_array *msgs, struct globber_array *omit_globs); - -/* In rfc822.c */ -struct rfc822 *make_rfc822(char *filename); -void free_rfc822(struct rfc822 *msg); -enum data_to_rfc822_error { - DTR8_OK, - DTR8_MISSING_END, /* missing endpoint marker. */ - DTR8_MULTIPART_SANS_BOUNDARY, /* multipart with no boundary string defined */ - DTR8_BAD_HEADERS, /* corrupt headers */ - DTR8_BAD_ATTACHMENT /* corrupt attachment (e.g. no body part) */ -}; -struct rfc822 *data_to_rfc822(struct msg_src *src, char *data, int length, enum data_to_rfc822_error *error); -void create_ro_mapping(const char *filename, unsigned char **data, int *len); -void free_ro_mapping(unsigned char *data, int len); -char *format_msg_src(struct msg_src *src); - -/* In tok.c */ -struct toktable *new_toktable(void); -struct toktable2 *new_toktable2(void); -void free_token(struct token *x); -void free_token2(struct token2 *x); -void free_toktable(struct toktable *x); -void free_toktable2(struct toktable2 *x); -void add_token_in_file(int file_index, unsigned int hash_key, char *tok_text, struct toktable *table); -void check_and_enlarge_encoding(struct matches *m); -void insert_index_on_encoding(struct matches *m, int idx); -void add_token2_in_file(int file_index, unsigned int hash_key, char *tok_text, struct toktable2 *table, int add_to_chain1); - -/* In db.c */ -#define CREATE_RANDOM_DATABASE_HASH 0 -struct database *new_database(unsigned int hash_key); -struct database *new_database_from_file(char *db_filename, int do_integrity_checks); -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 do_fast_index); -void check_database_integrity(struct database *db); -int cull_dead_messages(struct database *db, int do_integrity_checks); - -/* In mbox.c */ -void build_mbox_lists(struct database *db, const char *folder_base, - const char *mboxen_paths, struct globber_array *omit_globs); -int add_mbox_messages(struct database *db); -void compute_checksum(const char *data, size_t len, checksum_t *csum); -void cull_dead_mboxen(struct database *db); -unsigned int encode_mbox_indices(unsigned int mb, unsigned int msg); -void decode_mbox_indices(unsigned int index, unsigned int *mb, unsigned int *msg); -int verify_mbox_size_constraints(struct database *db); -void glob_and_expand_paths(const char *folder_base, char **paths_in, int n_in, char ***paths_out, int *n_out, const struct traverse_methods *methods, struct globber_array *omit_globs); - -/* In glob.c */ -struct globber; - -struct globber *make_globber(const char *wildstring); -void free_globber(struct globber *old); -int is_glob_match(struct globber *g, const char *s); - -/* In writer.c */ -void write_database(struct database *db, char *filename, int do_integrity_checks); - -/* In search.c */ -int search_top(int do_threads, int do_augment, char *database_path, char *complete_mfolder, char **argv, enum folder_type ft, int verbose); - -/* In stats.c */ -void get_db_stats(struct database *db); - -/* In dates.c */ -int scan_date_string(char *in, time_t *start, int *has_start, time_t *end, int *has_end); - -/* In dumper.c */ -void dump_database(char *filename); - -/* In strexpand.c */ -char *expand_string(const char *p); - -/* In dotlock.c */ -void lock_database(char *path, int forced_unlock); -void unlock_database(void); -void unlock_and_exit(int code); - -/* In mairix.c */ -void report_error(const char *str, const char *filename); - -#endif /* MAIRIX_H */ diff --git a/src/mairix/ACKNOWLEDGEMENTS b/src/mairix/ACKNOWLEDGEMENTS @@ -1,60 +0,0 @@ -These people have contributed useful patches, ideas and suggestions: - -Anand Kumria -André Costa -Andreas Amann -Andre Costa -Aredridel -Balázs Szabó -Bardur Arantsson -Benj. Mako Hill -Chris Mason -Christoph Dworzak -Christopher Rosado -Chung-chieh Shan -Claus Alboege -Corrin Lakeland -Dan Egnor -Daniel Jacobowitz -Dirk Huebner -Ed Blackman -Emil Sit -Felipe Gustavo de Almeida -Ico Doornekamp -Jaime Velasco Juan -James Leifer -Jerry Jorgenson -Joerg Desch -Johannes Schindelin -Johannes Weißl -John Arthur Kane -John Keener -Jonathan Kamens -Josh Purinton -Karsten Petersen -Kevin Rosenberg -Mark Hills -Martin Danielsson -Matthias Teege -Mikael Ylikoski -Mika Fischer -Oliver Braun -Paramjit Oberoi -Paul Fox -Peter Chines -Peter Jeremy -Robert Hofer -Roberto Boati -Samuel Tardieu -Sanjoy Mahajan -Satyaki Das -Steven Lumos -Tim Harder -Tom Doherty -Vincent Lefevre -Vladimir V. Kisil -Will Yardley -Wolfgang Weisselberg - -I apologise to any contributors who have been omitted from this list! - diff --git a/src/mairix/COPYING b/src/mairix/COPYING @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/src/mairix/INSTALL b/src/mairix/INSTALL @@ -1,22 +0,0 @@ -Installation of mairix goes as follows: - -./configure -make -make install - -You need to be root to run the final step unless you're installing under your -own home directory somewhere. - -However, you might want to tune the options further. The configure script -shares its common options with the usual autoconf-generated scripts, even -though it's not autoconf-generated itself. For example, a fuller build could -use - -CC=gcc CFLAGS="-O2 -Wall" ./configure \ - --prefix=/opt/mairix \ - --infodir=/usr/share/info -make -make install - -The final step is to create a ~/.mairixrc file. An example is included in the -file dotmairixrc.eg. Just copy that to ~/.mairixrc and edit it. diff --git a/src/mairix/Makefile.in b/src/mairix/Makefile.in @@ -1,114 +0,0 @@ -######################################################################### -# -# mairix - message index builder and finder for maildir folders. -# -# Copyright (C) Richard P. Curnow 2002-2004,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., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# ======================================================================= - -######################################################################### -# Edit the following variables as required -CC=@cc@ -CFLAGS=@cflags@ @defs@ -CPPFLAGS=@CPPFLAGS@ -LDFLAGS=@LDFLAGS@ -LIBS=@LIBS@ - -####################################################################### -# If you're generating a package, you may want to use -# make DESTDIR=temporary_dir install -# to get the software installed to a directory where you can create -# a tdl.tar.gz from it -DESTDIR= - -####################################################################### - -prefix=$(DESTDIR)@prefix@ -bindir=$(DESTDIR)@bindir@ -mandir=$(DESTDIR)@mandir@ -man1dir=$(mandir)/man1 -man5dir=$(mandir)/man5 -infodir=$(DESTDIR)@infodir@ -docdir=$(DESTDIR)@docdir@ - -######################################################################### -# Things below this point shouldn't need to be edited. - -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 \ - nvp.o nvpscan.o - -all : mairix - -mairix : $(OBJ) - $(CC) -o mairix $(CFLAGS) $(LDFLAGS) $(OBJ) $(LIBS) - -%.o : %.c memmac.h mairix.h reader.h Makefile - $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< - -datescan.c datescan.h : datescan.nfa ./dfasyn/dfasyn - ./dfasyn/dfasyn -o datescan.c -ho datescan.h -r datescan.report -u datescan.nfa - -fromcheck.c fromcheck.h : fromcheck.nfa ./dfasyn/dfasyn - ./dfasyn/dfasyn -o fromcheck.c -ho fromcheck.h -r fromcheck.report -u fromcheck.nfa - -nvpscan.c nvpscan.h : nvp.nfa ./dfasyn/dfasyn - ./dfasyn/dfasyn -o nvpscan.c -ho nvpscan.h -r nvpscan.report -u nvp.nfa - -dates.o : datescan.h -mbox.o : fromcheck.h -nvp.o : nvpscan.h - -version.h: - ./mkversion - -./dfasyn/dfasyn: - if [ -d dfasyn ]; then cd dfasyn ; $(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS)" ; else echo "No dfasyn subdirectory?" ; exit 1 ; fi - -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.[ch] datescan.[ch] - -rm -f nvpscan.[ch] - if [ -d dfasyn ]; then cd dfasyn ; $(MAKE) clean ; fi - if [ -d test ]; then cd test ; $(MAKE) clean ; fi - -distclean: clean - if [ -d test ]; then cd test ; $(MAKE) distclean ; fi - -rm -f Makefile config.log - -install: - [ -d $(prefix) ] || mkdir -p $(prefix) - [ -d $(bindir) ] || mkdir -p $(bindir) - [ -d $(mandir) ] || mkdir -p $(mandir) - [ -d $(man1dir) ] || mkdir -p $(man1dir) - [ -d $(man5dir) ] || mkdir -p $(man5dir) - cp -f mairix $(bindir) - chmod 555 $(bindir)/mairix - cp -f mairix.1 $(man1dir) - chmod 444 $(man1dir)/mairix.1 - cp -f mairixrc.5 $(man5dir) - chmod 444 $(man5dir)/mairixrc.5 - -check: mairix - if [ -d test ]; then cd test ; $(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS)" check ; else echo "No test subdirectory?" ; exit 1 ; fi - -.PHONY : all install clean distclean check - -mairix.o : version.h - - diff --git a/src/mairix/NEWS b/src/mairix/NEWS @@ -1,317 +0,0 @@ -NEW IN VERSION 0.23 -=================== -* Allow '=' in message-id search for RFC2822 conformance -* Add the option -H to force hardlinks -* Skip .gitignore files -* Do not interpret special characters [~,/=^] in Message-ID queries -* Fix faultly mbox message separators -* Improve reporting of unparsed MIME headers & remove code duplication -* Allow empty sections in MIME headers -* Add support for uuencoded attachments -* Improve the parsing of MIME boundaries -* Fix SEGV if mbox shrinks -* Add test suite -* Fix building in parallel - -NEW IN VERSION 0.22 -=================== - -* Skip symlinks when using mbox (R A Lichtensteiger) -* Update copyright year info throughout -* Update ACKNOWLEDGEMENTS and copyright headers where more credit was due -* Update FSF address in file headers -* Update COPYING to latest gpl-2.0.txt -* Improve error message if home directory cannot be determined -* Honour HOME environment variable (Andreas Amann) -* MIME types are allowed to have "+" characters in them. (Jonathan Kamens) -* Fix deficiencies in the parsing of mbox From lines (Jonathan Kamens) -* Include the existing -x flag in the help message (Mark Hills) -* Fix documentation nits (Tom Doherty) -* Remove spurious message when the mtime of a message file has changed -* Do not export functions already exported through a callback structure. (Samuel Tardieu) -* Fix two manpages buglets. (Samuel Tardieu) -* When freeing a struct nvp, do not forget to free the struct nvp_entry. (Samuel Tardieu) -* Do not leak memory if duplicate fields are present. (Samuel Tardieu) -* Initialize the date header with a known value. (Samuel Tardieu) -* Merge two conflicting solutions for bad MIME encoding -* Fix segfault when last char is not a newline (Mika Fischer) -* fix for MIME-related crash (Paramjit Oberoi) -* Add support claws-mail (Anand Kumria) -* Add MH sub-type support for ezmlm-archives (Claus Alboege) -* Detect a trailing -f or -o with no following argument -* Allow lines starting "From" to occur part-way through the header.o -* Display message-ID in search -x mode -* Remove execute permission from source files -* Handle mbox from separators where email address is in angle brackets -* Fix a bug in rfc822.c: Some headers weren't correctly parsed. (Jaime Velasco Juan) - -NEW IN VERSION 0.21 -=================== - -* Fix make clean target in dfasyn/ (Benj. Mako Hill) -* Limit number of messages that are examined when an end boundary is missing in - an mbox (Chung-chieh Shan) -* Avoid examining . and .. when traversing MH folder hierarchy (Steven Lumos) -* Fix various bugs in the name/value parser -* Add some RFC2231 support to the name/value parser (continuations) -* Fix indexing when existing database only contains 1 message - -NEW IN VERSION 0.20 -=================== - -* Cache uncompressed mbox data (Chris Mason, further work by me) -* Fix gaps in date ranges for search -* Unlock database if mairix is interrupted (Paul Fox) -* Add fast index option (-F) -* Fix conditional compilation errors for compressed mbox -* Reimplement MIME header parsing -* Add capability to search on names of attachments -* Add capability to search on state of message flags -* Create maildir-format mfolder filenames correctly with regard to flags -* Various bug fixes (Oliver Braun, Matthias Teege) - - -NEW IN VERSION 0.19 -=================== -* mairix.spec fixes (André Costa) -* bug fix: freeing of message structures (Karsten Petersen) -* Add new -x (--excerpt-output) option, an alternative mode for searching. - This displays the key headers from the matching messages on stdout. -* Add notes about the mairix-users mailing list and the SourceForge page to - README. -* Fix configuration + compilation to allow building with gzip support but - without bzlib support. -* Rename internal functions like zopen() to avoid name conflicts on MacOS X. - (Vincent Lefevre) -* Remove a spurious ; in bison input file (Vincent Lefevre) -* Improve output given in various error conditions (based on patch by Karsten - Petersen) - -NEW IN VERSION 0.18 -=================== - -* Support bzip2'd mbox folders -* Fix bugs in parsing mbox folders containing unquoted 'From ' lines inside - MIME body parts -* Fix bug in parsing content-type data containing quotes with whitespace - before -* Clone the message flags (when both the source folder and mfolder are both - of maildir type) -* New manpages mairix.1 and mairixrc.5 are included, and the old texinfo-based - documentation is deprecated into the old_docs/ directory. -* Upgrade scanners to new version of dfasyn -* Support Mew's MH folder subtype - - -NEW IN VERSION 0.17.1 -===================== - -* Fix detection of MH folder subtype used by nnml (Gnus) -* Fix filename format generated in the /cur/ directory for maildir mfolders. -* Syntax fix in configure script - -NEW IN VERSION 0.17 -=================== - -* Support gzipped mbox folders (any file matched by a mbox= line in the config - file is considered as a gzipped mbox if its name ends in .gz) -* Rework directory traversal for the '...' construct to speed up indexing and - the check that mfolder isn't going to overwrite a real folder when searching. -* Check whether database exists before attempting to do searching. -* Matched new maildir messages go in /new/ subdirectory of maildir mfolder. -* Fix lots of compiler warnings generated by gcc4.x -* Don't create and immediately scrub database entries for empty mbox folders. -* Fix usage() info for bare word in searching -* Allow '.' on the ends of numeric filenames in MH folders (to work - with Evolution) -* Update .PHONY target so that 'make install' etc are more reliable. -* Add X-source-folder header to indicate the original folder of a match found - in an mbox. -* Migration to git for revision control. - -NEW IN VERSION 0.16.1 -===================== - -* Remove the lockfile if the program terminates for any reason. - -NEW IN VERSION 0.16 -=================== - -* Home directory (~) and environment variable ($foo / ${foo}) expansion in the - .mairixrc file -* Add -Q flag to skip database integrity checks during indexing (equivalently - the nochecks option in .mairixrc file). This speeds up indexing but loses - some robustness. -* Add ^ word prefix to require substring search to be left-anchored -* Split 'make clean' into separate clean and clean_docs -* Improve some error messages -* Add online help entries for -o and -d -* Don't write out the database if there are no changes found during indexing. -* Fix stale information about the 'and' and 'or' delimiters in the online help. -* Add the capability to omit particular folders from indexing (omit keyword in - .mairixrc file.) This allows broad wildcards to be used with selected - folders removed from the wildcard which is much more convenient in many - set-ups. -* Avoid writing matches to any folder on the list of folders to be indexed - (affects both mfolder option and argument of -o command line switch.) This - prevents disasterous loss of messages in the event of trying to overwrite an - wanted folder with the matches. -* Implement dot-locking on the database file to prevent corruption due to - concurrent updates. Add --unlock file to forcibly remove a stray lockfile. -* Display message path in warning messages from rfc822 parsing. - -NEW IN VERSION 0.15 -=================== - -* Migrate to GNU Arch for hosting the development archive -* In mbox parsing, handle return path in 'From ' line only being a local part - (reported by several people) -* Don't output number of matched messages in raw mode (to make output more - useful to scripts etc) (Samuel Tardieu) -* Fix vfolder->mfolder in dotmairixrc.eg (reported by several people) -* Handle spaces in multipart message boundary strings (Chung-chieh Shan) -* Be more tolerant of bad multipart message boundary separators (Chung-chieh - Shan) -* Add rudimentary database dump command (-d/--dump) -* Fix bug in handling of per-database hash key -* Improve standards-compliance of maildir output file names (Jeff King) -* Remove most compiler warnings - -NEW IN VERSION 0.14.1 -===================== - -* Bug fix : splitting of messages in mboxes was too strict regarding whitespace - -NEW IN VERSION 0.14 -=================== - -* Fix error in path (p:) searching for messages in mboxes. -* Improve usage() function - -NEW IN VERSION 0.13 -=================== - -* Fixes to support the mbox format used by Mozilla mail -* When creating vfolder directories for maildir/mh, remove existing - non-directory at the same path, if present. When creating mbox vfolder file, - complain if there's already a directory at the same path and exit. -* Switch from the term "virtual folder" to "match folder" -* Fix bug in path matches (p:) containing upper-case letters - previously they - matched on corresponding all lower-case paths. - -NEW IN VERSION 0.12 -=================== - -! Change in database file format - existing databases need to be destroyed and - recreated. - -* Indexing of mbox folders in addition to the existing maildir & MH support -* Output to mbox format vfolder -* Return exit status 1 if no messages are matched in search mode, and exit - status 2 for all error conditions. -* Allow wildcards to be used in specifying maildir and mh folder paths. -* Searching on messages having a particular Message-ID (m:msgid expression in - search mode). -* When indexing whole email addresses, '+' is now considered a valid character. -* Use ',' instead of '+' in search expressions, and '/' instead of ','. This - is to allow '+' to be used inside email addresses that are being searched - for. The '/' character is traditionally associated with meaning 'or', so it - made more sense to move ',' to mean 'and'. (Unfortunately, there were very - few metacharacters left which don't have some special meaning to shells, and - I wanted to avoid the need to quote or escape the search expressions.) -* Bug fix checking return status of mmap. -* Handle ">From " at the start of the message headers -* Handle mis-formatted encoding strings "7 bit" and "8 bit" -* Make every database use a random seed for the token hash function (to prevent - denial of service attacks against mairix through carefully crafted messages.) -* Rename some options in the mairixrc file, to put the folder formats on an - equal footing. -* Properly handle the case where a maildir vfolder exists but one or more of - the new,tmp,cur subdirectories is missing. -* Add configure script (not autoconf-based) - -NEW IN VERSION 0.11 -=================== - -* Detect failed malloc (out of memory) conditions properly and report it. -* Improved date specification syntax for d: option -* Allow vfolder to be an absolute path or relative to current directory, - instead of just relative to base directory. - -NEW IN VERSION 0.10 -=================== - -* Add 'raw' mode for searching. -* When purging, only print the pass[12] message in verbose mode -* Add an ACKNOWLEDGEMENTS file. -* Hack to handle missing NAME_MAX on various non-Linux systems -* Improve mairix.spec file for RPM building -* Change default value for prefix in Makefile to make it more standard. - -NEW IN VERSION 0.9 -================== - -* Fix problem with auditing headers if a uucp/mbox-style "from " header is - present at the start. -* Allow \: sequence in folder names to specify a : - -NEW IN VERSION 0.8 -================== - -* Fix bug : mairix used to crash if a message had corrupted RFC822 header lines - -NEW IN VERSION 0.7 -================== - -* Fix bug : mairix likely to crash if a non-existant folder is listed in the - conf file. -* Allow multiple folders and mh_folders lines in the conf file for people who - have many separate folders. -* Print an extra 'comfort' message in verbose mode before starting to scan the - directory tree. - -NEW IN VERSION 0.6 -================== - -* When an unrecognized encoding is found, ignore the body part instead of - aborting the run. - -NEW IN VERSION 0.5 -================== - -* When -a option is used for search, avoid symlinking the same message twice if - it matches more than one query. -* Fixes to rpm spec file. -* Fix handling of = in base64-encoded attachments. -* Support non POSIX locales. -* Support rfc2047 encoding in headers. -* Create vfolder if it doesn't already exist. -* Allow searching on complete email addresses as well as individual words in - to, cc and from fields. -* New -o option to allow vfolder name to be given on the command line. - -NEW IN VERSION 0.4 -================== - -* Support for MH folders -* Create database with mode 0600 instead of 0644 (better security). -* Add Makefile target to install whichever forms of the documentation have been - built. - -NEW IN VERSION 0.3 -================== - -* Various bug fixes - -NEW IN VERSION 0.2 -================== - -* Substrings of message paths can be used as search expressions (p:substring - option) -* = now used instead of / as the delimiter for number of errors in an - approximate match (to help with path search) -* Bug fix when using -t mode for search with unpurged dead messages still in - the database. - -================== -# vim:comments-=mb\:*:comments+=fb\:* diff --git a/src/mairix/README b/src/mairix/README @@ -1,63 +0,0 @@ -mairix is a program for indexing and searching email messages stored in -Maildir, MH or mbox folders. - -* Indexing is fast. It runs incrementally on new messages - any particular - message only gets scanned once in the lifetime of the index file. - -* The search mode populates a "virtual" folder with symlinks(*) which - point to the real messages. This folder can be opened as usual in your mail - program. - -* The search mode is very fast. - -* Indexing and searching works on the basis of words. The index file tabulates - which words occur in which parts (particular headers + body) of which - messages. - -The program is a very useful complement to mail programs like mutt -(http://www.mutt.org/, which supports Maildir, MH and mbox folders) and -Sylpheed (which supports MH folders). - -[(*) where the input or output folder is an mbox, a copy of the message is made -instead of symlinking.] - -See also the mairix.txt file. - -********************************************************************* - Copyright (C) Richard P. Curnow 2002-2004 - - 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -********************************************************************* - -Suggestions, bug reports, experiences, praise, complaints etc to the author -please, at <rc@rc0.org.uk> - -Since July 2006, there is a mairix-users mailing list. To subscribe or to view -the archives, visit - - https://lists.sourceforge.net/lists/listinfo/mairix-users - -The main website for mairix is - - http://www.rc0.org.uk/mairix - -The SourceForge project page is - - http://www.sf.net/projects/mairix - -ACKNOWLEDGEMENTS -================ - -See the ACKNOWLEDGEMENTS file diff --git a/src/mairix/configure b/src/mairix/configure @@ -1,337 +0,0 @@ -#!/bin/sh -######################################################################### -# -# mairix - message index builder and finder for maildir folders. -# -# Copyright (C) Richard P. Curnow 2003,2004,2005 -# Copyright (C) Paramjit Oberoi 2005 -# -# 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., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# ======================================================================= - -if [ -f config.log ]; then rm -f config.log ; fi -exec 5>config.log - -MYCC=${CC:-gcc} -MYCFLAGS=${CFLAGS:--O2 -Wall} -MYCPPFLAGS=${CPPFLAGS:-} -MYLDFLAGS=${LDFLAGS:-} - -# ======================================================================= -# Functions - -#{{{ cleanup -cleanup () { - if [ -f docheck.c ]; then rm -f docheck.c ; fi - if [ -f docheck.o ]; then rm -f docheck.o ; fi - if [ -f docheck ]; then rm -f docheck ; fi - rm -rf docheck.c docheck.o docheck -} -#}}} - -#{{{ test_cc : basic compiler sanity check -test_cc () { - printf "Testing whether your compiler \"$MYCC $MYCFLAGS\" works : " - cat >docheck.c <<EOF; -#include <stdio.h> -int main (int argc, char **argv) -{ - return 0; -} -EOF - ${MYCC} ${MYCFLAGS} -o docheck docheck.c 1>&5 2>&5 - if [ $? -eq 0 ] - then - printf "it works\n" - else - printf "it doesn't work\n" - printf "Failed program was\n" 1>&5 - cat docheck.c 1>&5 - rm -f docheck.c docheck - exit 1 - fi - cleanup -} -#}}} - -#{{{ test_for_stdint_h -test_for_stdint_h () { - cat >docheck.c <<EOF; -#include <stdint.h> -int main(int argc, char **argv) { - return 0; -} -EOF - - ${MYCC} ${MYCFLAGS} -c -o docheck.o docheck.c >/dev/null 2>&1 - if [ $? -eq 0 ] - then - result=0 - else - result=1 - fi - - rm -f docheck.c docheck.o - echo $result -} -#}}} -#{{{ test_for_inttypes_h -test_for_inttypes_h () { - cat >docheck.c <<EOF; -#include <inttypes.h> -int main(int argc, char **argv) { - return 0; -} -EOF - - ${MYCC} ${MYCFLAGS} -c -o docheck.o docheck.c >/dev/null 2>&1 - if [ $? -eq 0 ] - then - result=0 - else - result=1 - fi - - rm -f docheck.c docheck.o - echo $result -} -#}}} -#{{{ test_for_zlib -test_for_zlib () { - cat > docheck.c <<EOF; -#include <zlib.h> -int main () { - const char *foo; - foo = zlibVersion(); - return 0; -} -EOF - echo "Test program is" 1>&5 - cat docheck.c 1>&5 - ${MYCC} ${MYCPPFLAGS} ${MYCFLAGS} ${MYLDFLAGS} -o docheck docheck.c -lz 1>&5 2>&1 - if [ $? -eq 0 ] - then - result=0 - else - result=1 - fi - rm -f docheck.c docheck - echo $result -} -#}}} -#{{{ test_for_bzlib -test_for_bzlib () { - cat > docheck.c <<EOF; -#include <bzlib.h> -int main () { - const char *foo; - foo = BZ2_bzlibVersion(); - return 0; -} -EOF - echo "Test program is" 1>&5 - cat docheck.c 1>&5 - ${MYCC} ${MYCPPFLAGS} ${MYCFLAGS} ${MYLDFLAGS} -o docheck docheck.c -lbz2 1>&5 2>&1 - if [ $? -eq 0 ] - then - result=0 - else - result=1 - fi - rm -f docheck.c docheck - echo $result -} -#}}} -#{{{ usage -usage () { - cat <<EOF; -\`configure' configures tdl to adapt to many kinds of systems. - -Usage: ./configure [OPTION]... - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [/usr/local] - -By default, \`make install' will install all the files in -\`/usr/local/bin', \`/usr/local/lib' etc. You can specify -an installation prefix other than \`/usr/local' using \`--prefix', -for instance \`--prefix=$HOME'. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --infodir=DIR info documentation [PREFIX/info] - --mandir=DIR man documentation [PREFIX/man] - --docdir=DIR other documentation [PREFIX/doc/mairix-\$version] - -Other options: - --enable-gzip-mbox attempt to support gzipped mboxes (requires zlib) - --disable-gzip-mbox don't attempt to support gzipped mboxes - --enable-bzip-mbox attempt to support bzip2ed mboxes (requires bzlib) - --disable-bzip-mbox don't attempt to support bzip2ed mboxes - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - CPPFLAGS Extra C preprocessor flags, e.g. -I<include dir> if you - have header files in a nonstandard directory <include dir> - LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a - nonstandard directory <lib dir> - -Use these variables to override the choices made by \`configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to <rc@rc0.org.uk>. -EOF -} -#}}} -# ======================================================================= - -# Defaults for variables -PREFIX=/usr/local - -use_readline=yes -bad_options=no -use_gzip_mbox=yes -use_bzip_mbox=yes - -# Parse options to configure -for option -do - case "$option" in - - --prefix=* | --install-prefix=* ) - PREFIX=`echo $option | sed -e 's/[^=]*=//;'` - ;; - --bindir=* ) - BINDIR=`echo $option | sed -e 's/[^=]*=//;'` - ;; - --mandir=* ) - MANDIR=`echo $option | sed -e 's/[^=]*=//;'` - ;; - --infodir=* ) - INFODIR=`echo $option | sed -e 's/[^=]*=//;'` - ;; - --docdir=* ) - DOCDIR=`echo $option | sed -e 's/[^=]*=//;'` - ;; - --enable-gzip-mbox ) - use_gzip_mbox=yes - ;; - --disable-gzip-mbox ) - use_gzip_mbox=no - ;; - --enable-bzip-mbox ) - use_bzip_mbox=yes - ;; - --disable-bzip-mbox ) - use_bzip_mbox=no - ;; - -h | --help ) - usage - exit 1 - ;; - * ) - printf "Unrecognized option : $option\n" - bad_options=yes - ;; - esac -done - -if [ ${bad_options} = yes ]; then - exit 1 -fi - -DEFS="" -test_cc - -printf "Checking for <stdint.h> : " -if [ `test_for_stdint_h` -eq 0 ]; then - printf "Yes\n" - DEFS="${DEFS} -DHAS_STDINT_H" -else - printf "No\n" -fi - -printf "Checking for <inttypes.h> : " -if [ `test_for_inttypes_h` -eq 0 ]; then - printf "Yes\n" - DEFS="${DEFS} -DHAS_INTTYPES_H" -else - printf "No\n" -fi - -if [ $use_gzip_mbox = "yes" ]; then - printf "Checking for zlib : " - if [ `test_for_zlib` -eq 0 ]; then - printf "Yes\n"; - DEFS="${DEFS} -DUSE_GZIP_MBOX" - LIBS="-lz" - else - printf "No (disabled gzipped mbox support)\n"; - fi -fi - -if [ $use_bzip_mbox = "yes" ]; then - printf "Checking for bzlib : " - if [ `test_for_bzlib` -eq 0 ]; then - printf "Yes\n"; - DEFS="${DEFS} -DUSE_BZIP_MBOX" - LIBS="${LIBS} -lbz2" - else - printf "No (disabled bzip2ed mbox support)\n"; - fi -fi - -#{{{ Determine version number of the program. -if [ -f version.txt ]; then - revision=`cat version.txt` -else - revision="DEVELOPMENT" -fi - -#}}} -if [ "x" = "x${BINDIR}" ]; then BINDIR=${PREFIX}/bin ; fi -if [ "x" = "x${MANDIR}" ]; then MANDIR=${PREFIX}/man ; fi -if [ "x" = "x${INFODIR}" ]; then INFODIR=${PREFIX}/info ; fi -if [ "x" = "x${DOCDIR}" ]; then DOCDIR=${PREFIX}/doc/mairix-${revision} ; fi - -echo "Generating Makefile" - -rm -f Makefile -sed -e "s%@cc@%${MYCC}%; \ - s%@defs@%${DEFS}%; \ - s%@cflags@%${MYCFLAGS}%; \ - s%@prefix@%${PREFIX}%; \ - s%@bindir@%${BINDIR}%; \ - s%@mandir@%${MANDIR}%; \ - s%@infodir@%${INFODIR}%; \ - s%@docdir@%${DOCDIR}%; \ - s%@LIBS@%${LIBS}%; \ - s%@CPPFLAGS@%${MYCPPFLAGS}%; \ - s%@LDFLAGS@%${MYLDFLAGS}%; \ - " < Makefile.in > Makefile - -# Avoid editing Makefile instead of Makefile.in -chmod ugo-w Makefile - -# ======================================================================= -# vim:et:sw=2:ht=2:sts=2:fdm=marker:cms=#%s - diff --git a/src/mairix/dates.c b/src/mairix/dates.c @@ -1,404 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002-2004,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <ctype.h> -#include <assert.h> -#include "mairix.h" -#include "dates.h" -#include "datescan.h" - -static enum DATESCAN_TYPE discover_type(char *first, char *last)/*{{{*/ -{ - int current_state = 0; - int token; - char *p; - p = first; - while (p < last) { - token = datescan_char2tok[(int)*(unsigned char*)p]; - current_state = datescan_next_state(current_state, token); - if (current_state < 0) break; - p++; - } - - if (current_state < 0) { - return DS_FAILURE; - } else { - return datescan_attr[current_state]; - } -} -/*}}}*/ -static int match_month(char *p)/*{{{*/ -{ - if (!strncasecmp(p, "jan", 3)) return 1; - if (!strncasecmp(p, "feb", 3)) return 2; - if (!strncasecmp(p, "mar", 3)) return 3; - if (!strncasecmp(p, "apr", 3)) return 4; - if (!strncasecmp(p, "may", 3)) return 5; - if (!strncasecmp(p, "jun", 3)) return 6; - if (!strncasecmp(p, "jul", 3)) return 7; - if (!strncasecmp(p, "aug", 3)) return 8; - if (!strncasecmp(p, "sep", 3)) return 9; - if (!strncasecmp(p, "oct", 3)) return 10; - if (!strncasecmp(p, "nov", 3)) return 11; - if (!strncasecmp(p, "dec", 3)) return 12; - return 0; -} -/*}}}*/ -static int year_fix(int y)/*{{{*/ -{ - if (y>100) { - return y-1900; - } else if (y < 70) { - /* 2000-2069 */ - return y+100; - } else { - /* 1970-1999 */ - return y; - } -} -/*}}}*/ -static int last_day(int mon, int y) {/*{{{*/ - /* mon in [0,11], y=year-1900 */ - - static unsigned char days[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; - if (mon != 1) { - return days[mon]; - } else { - /* Because 2000 was a leap year, we don't have to bother about the %100 - * rule, at least not in this range of dates. */ - if ((y % 4) == 0) { - return 29; - } else { - return 28; - } - } -} -/*}}}*/ -static void set_day(struct tm *x, int y)/*{{{*/ -{ - if (y > x->tm_mday) { - /* Shorthand for that day in previous month */ - if (x->tm_mon == 0) { - x->tm_mon = 11; - --x->tm_year; - } else { - --x->tm_mon; - } - } - x->tm_mday = y; /* Always */ -} -/*}}}*/ -static int is_later_dm(struct tm *x, int m, int d)/*{{{*/ -{ - int m1 = m-1; - return ((x->tm_mon < m1) || ((x->tm_mon == m1) && (x->tm_mday < d))); -} -/*}}}*/ -static int scan_date_expr(char *first, char *last, struct tm *start, struct tm *end)/*{{{*/ -{ - enum DATESCAN_TYPE type; - time_t now; - - time(&now); - type = discover_type(first, last); - - if (type == DS_SCALED) {/*{{{*/ - int v; - char *p; - time_t then; - - p = first; - v = 0; - while (isdigit(*p)) { - v = (v*10) + (*p - '0'); - p++; - } - switch(*p) { - case 'd': v *= 86400; break; - case 'w': v *= 7*86400; break; - case 'm': v *= 30*86400; break; - case 'y': v *= 365*86400; break; - default: - fprintf(stderr, "Unrecognized relative date scaling '%c'\n", *p); - return -1; - } - then = now - v; - if (start) { - *start = *localtime(&then); - } - if (end) { - *end = *localtime(&then); - }/*}}}*/ - } else if (type == DS_FAILURE) { - fputs("Cannot parse date expression [", stderr); - fwrite(first, sizeof(char), last-first, stderr); - fputs("]\n", stderr); - return -1; - } else { - /* something else */ - int v1, v3; - int m2; /* decoded month */ - char *p; - - v1 = v3 = m2 = 0; - p = first; - while (p < last && isdigit(*p)) { - v1 = (v1*10) + (*p - '0'); - p++; - } - if (p < last) { - m2 = match_month(p); - p += 3; - if (m2 == 0) { - return -1; /* failure */ - } - - } - while (p < last && isdigit(*p)) { - v3 = (v3*10) + (*p - '0'); - p++; - } - assert(p==last); /* should be true in all cases. */ - - switch (type) { - case DS_D:/*{{{*/ - if (start) set_day(start, v1); - if (end) set_day(end, v1); - break; -/*}}}*/ - case DS_Y:/*{{{*/ - if (start) { - start->tm_mday = 1; - start->tm_mon = 0; /* january */ - start->tm_year = year_fix(v1); - } - if (end) { - end->tm_mday = 31; - end->tm_mon = 11; - end->tm_year = year_fix(v1); - } - break; -/*}}}*/ - case DS_YYMMDD:/*{{{*/ - if (start) { - start->tm_mday = v1 % 100; - start->tm_mon = ((v1 / 100) % 100) - 1; - start->tm_year = year_fix(v1/10000); - } - if (end) { - end->tm_mday = v1 % 100; - end->tm_mon = ((v1 / 100) % 100) - 1; - end->tm_year = year_fix(v1/10000); - } - break; -/*}}}*/ - case DS_M:/*{{{*/ - if (start) { - if (m2-1 > start->tm_mon) --start->tm_year; /* shorthand for previous year */ - start->tm_mon = m2-1; - start->tm_mday = 1; - } - if (end) { - if (m2-1 > end->tm_mon) --end->tm_year; /* shorthand for previous year */ - end->tm_mon = m2-1; - end->tm_mday = last_day(m2-1, end->tm_year); - } - break; -/*}}}*/ - case DS_DM:/*{{{*/ - if (start) { - if (is_later_dm(start, m2, v1)) --start->tm_year; /* shorthand for previous year. */ - start->tm_mon = m2-1; - start->tm_mday = v1; - } - if (end) { - if (is_later_dm(end, m2, v1)) --end->tm_year; /* shorthand for previous year. */ - end->tm_mon = m2-1; - end->tm_mday = v1; - } - break; -/*}}}*/ - case DS_MD:/*{{{*/ - if (start) { - if (is_later_dm(start, m2, v3)) --start->tm_year; /* shorthand for previous year. */ - start->tm_mon = m2-1; - start->tm_mday = v3; - } - if (end) { - if (is_later_dm(end, m2, v3)) --end->tm_year; /* shorthand for previous year. */ - end->tm_mon = m2-1; - end->tm_mday = v3; - } - break; -/*}}}*/ - case DS_DMY:/*{{{*/ - if (start) { - start->tm_mon = m2-1; - start->tm_mday = v1; - start->tm_year = year_fix(v3); - } - if (end) { - end->tm_mon = m2-1; - end->tm_mday = v1; - end->tm_year = year_fix(v3); - } - break; -/*}}}*/ - case DS_YMD:/*{{{*/ - if (start) { - start->tm_mon = m2-1; - start->tm_mday = v3; - start->tm_year = year_fix(v1); - } - if (end) { - end->tm_mon = m2-1; - end->tm_mday = v3; - end->tm_year = year_fix(v1); - } - break; -/*}}}*/ - case DS_MY:/*{{{*/ - if (start) { - start->tm_year = year_fix(v3); - start->tm_mon = m2 - 1; - start->tm_mday = 1; - } - if (end) { - end->tm_year = year_fix(v3); - end->tm_mon = m2 - 1; - end->tm_mday = last_day(end->tm_mon, end->tm_year); - } - break; -/*}}}*/ - case DS_YM:/*{{{*/ - if (start) { - start->tm_year = year_fix(v1); - start->tm_mon = m2 - 1; - start->tm_mday = 1; - } - if (end) { - end->tm_year = year_fix(v1); - end->tm_mon = m2 - 1; - end->tm_mday = last_day(end->tm_mon, end->tm_year); - } - break;/*}}}*/ - case DS_FAILURE: - return -1; - break; - - case DS_SCALED: - assert(0); - break; - - } - } - return 0; -} -/*}}}*/ - -int scan_date_string(char *in, time_t *start, int *has_start, time_t *end, int *has_end)/*{{{*/ -{ - char *hyphen; - time_t now; - struct tm start_tm, end_tm; - char *nullchar; - int status; - - *has_start = *has_end = 0; - - nullchar = in; - while (*nullchar) nullchar++; - - 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) { - /* Start and end are the same. */ - *has_start = *has_end = 1; - status = scan_date_expr(in, nullchar, &start_tm, &end_tm); - if (status) return status; - *start = mktime(&start_tm); - *end = mktime(&end_tm); - return 0; - } else { - if (hyphen+1 < nullchar) { - *has_end = 1; - status = scan_date_expr(hyphen+1, nullchar, NULL, &end_tm); - if (status) return status; - *end = mktime(&end_tm); - start_tm = end_tm; - } - if (hyphen > in) { - *has_start = 1; - status = scan_date_expr(in, hyphen, &start_tm, NULL); - if (status) return status; - *start = mktime(&start_tm); - } - } - return 0; -} -/*}}}*/ - -#ifdef TEST -static void check(char *in)/*{{{*/ -{ - struct tm start, end; - int result; - result = scan_date_string(in, &start, &end); - if (result) printf("Conversion for <%s> failed\n", in); - else { - char buf1[128], buf2[128]; - strftime(buf1, 128, "%d-%b-%Y", &start); - strftime(buf2, 128, "%d-%b-%Y", &end); - printf("Computed range for <%s> : %s - %s\n", in, buf1, buf2); - } - -} -/*}}}*/ -int main (int argc, char **argv)/*{{{*/ -{ - - check("2w-1w"); - check("4m-1w"); - check("2002-2003"); - check("may2002-2003"); - check("2002may-2003"); - check("feb98-15may99"); - check("feb98-15may1999"); - check("2feb98-1y"); - check("02feb98-1y"); - check("970617-20010618"); - - return 0; -} -/*}}}*/ -#endif diff --git a/src/mairix/dates.h b/src/mairix/dates.h @@ -1,45 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002-2004 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#ifndef DATES_H -#define DATES_H - -enum DATESCAN_TYPE { - DS_FAILURE, - DS_D, - DS_Y, - DS_YYMMDD, - DS_SCALED, - DS_M, - DS_DM, - DS_MD, - DS_YM, - DS_MY, - DS_YMD, - DS_DMY, -}; - -extern int datescan_next_state(int current_state, int next_token); -extern enum DATESCAN_TYPE datescan_exitval[]; - - -#endif /* DATES_H */ diff --git a/src/mairix/datescan.nfa b/src/mairix/datescan.nfa @@ -1,112 +0,0 @@ -######################################################################### -# -# mairix - message index builder and finder for maildir folders. -# -# Copyright (C) Richard P. Curnow 2002-2004,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., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# ======================================================================= - -# NFA description for parsing dates - -# Stuff to pass through verbatim -%{ -#include "dates.h" -%} - -Abbrev A = [a-zA-Z] - -BLOCK day { - State in - [12] ; [0-9] -> out - [3] ; [01] -> out -} - -# Match 2 digit year -BLOCK year { - State in - [04-9] ; [0-9] -> out - [3] ; [2-9] -> out -} - -BLOCK month { - State in - A ; A ; A -> out -} - -BLOCK scaled { - State in - [0-9] -> in, after_value - - State after_value - A -> out -} - -BLOCK ccyy { - State in - [1-9] ; [0-9] ; [0-9] ; [0-9] -> out -} - -BLOCK main { - State in - [1-9] = DS_D - <day:in->out> = DS_D - <year:in->out> = DS_Y - <ccyy:in->out> = DS_Y - [0-9] ; [0-9] ; [0-9] ; [0-9] ; [0-9] ; [0-9] = DS_YYMMDD - [0-9] ; [0-9] ; [0-9] ; [0-9] ; - [0-9] ; [0-9] ; [0-9] ; [0-9] = DS_YYMMDD - <scaled:in->out> = DS_SCALED - <month:in->out> = DS_M - [1-9] ; <month:in->out> = DS_DM - <day:in->out> ; <month:in->out> = DS_DM - <month:in->out> ; [1-9] = DS_MD - <month:in->out> ; <day:in->out> = DS_MD - <year:in->out> ; <month:in->out> = DS_YM - <month:in->out> ; <year:in->out> = DS_MY - <ccyy:in->out> ; <month:in->out> = DS_YM - <month:in->out> ; <ccyy:in->out> = DS_MY - - <year:in->out> ; <month:in->out> ; [1-9] = DS_YMD - <year:in->out> ; <month:in->out> ; <day:in->out> = DS_YMD - [1-9] ; <month:in->out> ; <year:in->out> = DS_DMY - <day:in->out> ; <month:in->out> ; <year:in->out> = DS_DMY - - <ccyy:in->out> ; <month:in->out> ; [1-9] = DS_YMD - <ccyy:in->out> ; <month:in->out> ; <day:in->out> = DS_YMD - [1-9] ; <month:in->out> ; <ccyy:in->out> = DS_DMY - <day:in->out> ; <month:in->out> ; <ccyy:in->out> = DS_DMY -} - -ATTR DS_D -ATTR DS_Y -ATTR DS_YYMMDD -ATTR DS_SCALED -ATTR DS_M -ATTR DS_DM -ATTR DS_MD -ATTR DS_YM -ATTR DS_MY -ATTR DS_YMD -ATTR DS_DMY - -DEFATTR DS_FAILURE - -TYPE "enum DATESCAN_TYPE" -PREFIX datescan - - -# vim:ft=txt:et:sw=4:sts=4:ht=4 - diff --git a/src/mairix/datescan.report b/src/mairix/datescan.report @@ -1,3303 +0,0 @@ -NFA state 0 = in - [(epsilon)] -> day#37.in - 1:[1] -> #55 - 4:[4-9] -> #55 - 3:[3] -> #55 - 2:[2] -> #55 - [(epsilon)] -> ccyy#32.in - [(epsilon)] -> ccyy#30.in - [(epsilon)] -> day#27.in - 1:[1] -> #43 - 4:[4-9] -> #43 - 3:[3] -> #43 - 2:[2] -> #43 - [(epsilon)] -> year#22.in - [(epsilon)] -> year#20.in - [(epsilon)] -> month#18.in - [(epsilon)] -> ccyy#16.in - [(epsilon)] -> month#14.in - [(epsilon)] -> year#12.in - [(epsilon)] -> month#10.in - [(epsilon)] -> month#9.in - [(epsilon)] -> day#7.in - 1:[1] -> #21 - 4:[4-9] -> #21 - 3:[3] -> #21 - 2:[2] -> #21 - [(epsilon)] -> month#5.in - [(epsilon)] -> scaled#4.in - 0:[0] -> #11 - 4:[4-9] -> #11 - 3:[3] -> #11 - 2:[2] -> #11 - 1:[1] -> #11 - 0:[0] -> #5 - 4:[4-9] -> #5 - 3:[3] -> #5 - 2:[2] -> #5 - 1:[1] -> #5 - [(epsilon)] -> ccyy#3.in - [(epsilon)] -> year#2.in - [(epsilon)] -> day#1.in - 1:[1] -> #1 - 4:[4-9] -> #1 - 3:[3] -> #1 - 2:[2] -> #1 - Epsilon closure : - (self) - day#1.in - year#2.in - ccyy#3.in - scaled#4.in - month#5.in - day#7.in - month#9.in - month#10.in - year#12.in - month#14.in - ccyy#16.in - month#18.in - year#20.in - year#22.in - day#27.in - ccyy#30.in - ccyy#32.in - day#37.in - -NFA state 1 = #1 - Tags : DS_D - Epsilon closure : - (self) - -NFA state 2 = #2 - Tags : DS_D - Epsilon closure : - (self) - -NFA state 3 = day#1.in - 1:[1] -> day#1.#1 - 2:[2] -> day#1.#1 - 3:[3] -> day#1.#2 - Epsilon closure : - (self) - -NFA state 4 = day#1.#1 - 0:[0] -> day#1.out - 4:[4-9] -> day#1.out - 3:[3] -> day#1.out - 2:[2] -> day#1.out - 1:[1] -> day#1.out - Epsilon closure : - (self) - -NFA state 5 = day#1.#2 - 0:[0] -> day#1.out - 1:[1] -> day#1.out - Epsilon closure : - (self) - -NFA state 6 = day#1.out - [(epsilon)] -> #2 - Epsilon closure : - (self) - #2 - -NFA state 7 = #3 - Tags : DS_Y - Epsilon closure : - (self) - -NFA state 8 = year#2.in - 0:[0] -> year#2.#1 - 4:[4-9] -> year#2.#1 - 3:[3] -> year#2.#2 - Epsilon closure : - (self) - -NFA state 9 = year#2.#1 - 0:[0] -> year#2.out - 4:[4-9] -> year#2.out - 3:[3] -> year#2.out - 2:[2] -> year#2.out - 1:[1] -> year#2.out - Epsilon closure : - (self) - -NFA state 10 = year#2.#2 - 2:[2] -> year#2.out - 4:[4-9] -> year#2.out - 3:[3] -> year#2.out - Epsilon closure : - (self) - -NFA state 11 = year#2.out - [(epsilon)] -> #3 - Epsilon closure : - (self) - #3 - -NFA state 12 = #4 - Tags : DS_Y - Epsilon closure : - (self) - -NFA state 13 = ccyy#3.in - 1:[1] -> ccyy#3.#1 - 4:[4-9] -> ccyy#3.#1 - 3:[3] -> ccyy#3.#1 - 2:[2] -> ccyy#3.#1 - Epsilon closure : - (self) - -NFA state 14 = ccyy#3.#1 - 0:[0] -> ccyy#3.#2 - 4:[4-9] -> ccyy#3.#2 - 3:[3] -> ccyy#3.#2 - 2:[2] -> ccyy#3.#2 - 1:[1] -> ccyy#3.#2 - Epsilon closure : - (self) - -NFA state 15 = ccyy#3.#2 - 0:[0] -> ccyy#3.#3 - 4:[4-9] -> ccyy#3.#3 - 3:[3] -> ccyy#3.#3 - 2:[2] -> ccyy#3.#3 - 1:[1] -> ccyy#3.#3 - Epsilon closure : - (self) - -NFA state 16 = ccyy#3.#3 - 0:[0] -> ccyy#3.out - 4:[4-9] -> ccyy#3.out - 3:[3] -> ccyy#3.out - 2:[2] -> ccyy#3.out - 1:[1] -> ccyy#3.out - Epsilon closure : - (self) - -NFA state 17 = ccyy#3.out - [(epsilon)] -> #4 - Epsilon closure : - (self) - #4 - -NFA state 18 = #5 - 0:[0] -> #6 - 4:[4-9] -> #6 - 3:[3] -> #6 - 2:[2] -> #6 - 1:[1] -> #6 - Epsilon closure : - (self) - -NFA state 19 = #6 - 0:[0] -> #7 - 4:[4-9] -> #7 - 3:[3] -> #7 - 2:[2] -> #7 - 1:[1] -> #7 - Epsilon closure : - (self) - -NFA state 20 = #7 - 0:[0] -> #8 - 4:[4-9] -> #8 - 3:[3] -> #8 - 2:[2] -> #8 - 1:[1] -> #8 - Epsilon closure : - (self) - -NFA state 21 = #8 - 0:[0] -> #9 - 4:[4-9] -> #9 - 3:[3] -> #9 - 2:[2] -> #9 - 1:[1] -> #9 - Epsilon closure : - (self) - -NFA state 22 = #9 - 0:[0] -> #10 - 4:[4-9] -> #10 - 3:[3] -> #10 - 2:[2] -> #10 - 1:[1] -> #10 - Epsilon closure : - (self) - -NFA state 23 = #10 - Tags : DS_YYMMDD - Epsilon closure : - (self) - -NFA state 24 = #11 - 0:[0] -> #12 - 4:[4-9] -> #12 - 3:[3] -> #12 - 2:[2] -> #12 - 1:[1] -> #12 - Epsilon closure : - (self) - -NFA state 25 = #12 - 0:[0] -> #13 - 4:[4-9] -> #13 - 3:[3] -> #13 - 2:[2] -> #13 - 1:[1] -> #13 - Epsilon closure : - (self) - -NFA state 26 = #13 - 0:[0] -> #14 - 4:[4-9] -> #14 - 3:[3] -> #14 - 2:[2] -> #14 - 1:[1] -> #14 - Epsilon closure : - (self) - -NFA state 27 = #14 - 0:[0] -> #15 - 4:[4-9] -> #15 - 3:[3] -> #15 - 2:[2] -> #15 - 1:[1] -> #15 - Epsilon closure : - (self) - -NFA state 28 = #15 - 0:[0] -> #16 - 4:[4-9] -> #16 - 3:[3] -> #16 - 2:[2] -> #16 - 1:[1] -> #16 - Epsilon closure : - (self) - -NFA state 29 = #16 - 0:[0] -> #17 - 4:[4-9] -> #17 - 3:[3] -> #17 - 2:[2] -> #17 - 1:[1] -> #17 - Epsilon closure : - (self) - -NFA state 30 = #17 - 0:[0] -> #18 - 4:[4-9] -> #18 - 3:[3] -> #18 - 2:[2] -> #18 - 1:[1] -> #18 - Epsilon closure : - (self) - -NFA state 31 = #18 - Tags : DS_YYMMDD - Epsilon closure : - (self) - -NFA state 32 = #19 - Tags : DS_SCALED - Epsilon closure : - (self) - -NFA state 33 = scaled#4.in - 0:[0] -> scaled#4.in - 4:[4-9] -> scaled#4.in - 3:[3] -> scaled#4.in - 2:[2] -> scaled#4.in - 1:[1] -> scaled#4.in - 0:[0] -> scaled#4.after_value - 4:[4-9] -> scaled#4.after_value - 3:[3] -> scaled#4.after_value - 2:[2] -> scaled#4.after_value - 1:[1] -> scaled#4.after_value - Epsilon closure : - (self) - -NFA state 34 = scaled#4.after_value - 5:[A-Za-z] -> scaled#4.out - Epsilon closure : - (self) - -NFA state 35 = scaled#4.out - [(epsilon)] -> #19 - Epsilon closure : - (self) - #19 - -NFA state 36 = #20 - Tags : DS_M - Epsilon closure : - (self) - -NFA state 37 = month#5.in - 5:[A-Za-z] -> month#5.#1 - Epsilon closure : - (self) - -NFA state 38 = month#5.#1 - 5:[A-Za-z] -> month#5.#2 - Epsilon closure : - (self) - -NFA state 39 = month#5.#2 - 5:[A-Za-z] -> month#5.out - Epsilon closure : - (self) - -NFA state 40 = month#5.out - [(epsilon)] -> #20 - Epsilon closure : - (self) - #20 - -NFA state 41 = #21 - [(epsilon)] -> month#6.in - Epsilon closure : - (self) - month#6.in - -NFA state 42 = #22 - Tags : DS_DM - Epsilon closure : - (self) - -NFA state 43 = month#6.in - 5:[A-Za-z] -> month#6.#1 - Epsilon closure : - (self) - -NFA state 44 = month#6.#1 - 5:[A-Za-z] -> month#6.#2 - Epsilon closure : - (self) - -NFA state 45 = month#6.#2 - 5:[A-Za-z] -> month#6.out - Epsilon closure : - (self) - -NFA state 46 = month#6.out - [(epsilon)] -> #22 - Epsilon closure : - (self) - #22 - -NFA state 47 = #23 - [(epsilon)] -> month#8.in - Epsilon closure : - (self) - month#8.in - -NFA state 48 = day#7.in - 1:[1] -> day#7.#1 - 2:[2] -> day#7.#1 - 3:[3] -> day#7.#2 - Epsilon closure : - (self) - -NFA state 49 = day#7.#1 - 0:[0] -> day#7.out - 4:[4-9] -> day#7.out - 3:[3] -> day#7.out - 2:[2] -> day#7.out - 1:[1] -> day#7.out - Epsilon closure : - (self) - -NFA state 50 = day#7.#2 - 0:[0] -> day#7.out - 1:[1] -> day#7.out - Epsilon closure : - (self) - -NFA state 51 = day#7.out - [(epsilon)] -> #23 - Epsilon closure : - (self) - #23 - month#8.in - -NFA state 52 = #24 - Tags : DS_DM - Epsilon closure : - (self) - -NFA state 53 = month#8.in - 5:[A-Za-z] -> month#8.#1 - Epsilon closure : - (self) - -NFA state 54 = month#8.#1 - 5:[A-Za-z] -> month#8.#2 - Epsilon closure : - (self) - -NFA state 55 = month#8.#2 - 5:[A-Za-z] -> month#8.out - Epsilon closure : - (self) - -NFA state 56 = month#8.out - [(epsilon)] -> #24 - Epsilon closure : - (self) - #24 - -NFA state 57 = #25 - 1:[1] -> #26 - 4:[4-9] -> #26 - 3:[3] -> #26 - 2:[2] -> #26 - Epsilon closure : - (self) - -NFA state 58 = month#9.in - 5:[A-Za-z] -> month#9.#1 - Epsilon closure : - (self) - -NFA state 59 = month#9.#1 - 5:[A-Za-z] -> month#9.#2 - Epsilon closure : - (self) - -NFA state 60 = month#9.#2 - 5:[A-Za-z] -> month#9.out - Epsilon closure : - (self) - -NFA state 61 = month#9.out - [(epsilon)] -> #25 - Epsilon closure : - (self) - #25 - -NFA state 62 = #26 - Tags : DS_MD - Epsilon closure : - (self) - -NFA state 63 = #27 - [(epsilon)] -> day#11.in - Epsilon closure : - (self) - day#11.in - -NFA state 64 = month#10.in - 5:[A-Za-z] -> month#10.#1 - Epsilon closure : - (self) - -NFA state 65 = month#10.#1 - 5:[A-Za-z] -> month#10.#2 - Epsilon closure : - (self) - -NFA state 66 = month#10.#2 - 5:[A-Za-z] -> month#10.out - Epsilon closure : - (self) - -NFA state 67 = month#10.out - [(epsilon)] -> #27 - Epsilon closure : - (self) - #27 - day#11.in - -NFA state 68 = #28 - Tags : DS_MD - Epsilon closure : - (self) - -NFA state 69 = day#11.in - 1:[1] -> day#11.#1 - 2:[2] -> day#11.#1 - 3:[3] -> day#11.#2 - Epsilon closure : - (self) - -NFA state 70 = day#11.#1 - 0:[0] -> day#11.out - 4:[4-9] -> day#11.out - 3:[3] -> day#11.out - 2:[2] -> day#11.out - 1:[1] -> day#11.out - Epsilon closure : - (self) - -NFA state 71 = day#11.#2 - 0:[0] -> day#11.out - 1:[1] -> day#11.out - Epsilon closure : - (self) - -NFA state 72 = day#11.out - [(epsilon)] -> #28 - Epsilon closure : - (self) - #28 - -NFA state 73 = #29 - [(epsilon)] -> month#13.in - Epsilon closure : - (self) - month#13.in - -NFA state 74 = year#12.in - 0:[0] -> year#12.#1 - 4:[4-9] -> year#12.#1 - 3:[3] -> year#12.#2 - Epsilon closure : - (self) - -NFA state 75 = year#12.#1 - 0:[0] -> year#12.out - 4:[4-9] -> year#12.out - 3:[3] -> year#12.out - 2:[2] -> year#12.out - 1:[1] -> year#12.out - Epsilon closure : - (self) - -NFA state 76 = year#12.#2 - 2:[2] -> year#12.out - 4:[4-9] -> year#12.out - 3:[3] -> year#12.out - Epsilon closure : - (self) - -NFA state 77 = year#12.out - [(epsilon)] -> #29 - Epsilon closure : - (self) - #29 - month#13.in - -NFA state 78 = #30 - Tags : DS_YM - Epsilon closure : - (self) - -NFA state 79 = month#13.in - 5:[A-Za-z] -> month#13.#1 - Epsilon closure : - (self) - -NFA state 80 = month#13.#1 - 5:[A-Za-z] -> month#13.#2 - Epsilon closure : - (self) - -NFA state 81 = month#13.#2 - 5:[A-Za-z] -> month#13.out - Epsilon closure : - (self) - -NFA state 82 = month#13.out - [(epsilon)] -> #30 - Epsilon closure : - (self) - #30 - -NFA state 83 = #31 - [(epsilon)] -> year#15.in - Epsilon closure : - (self) - year#15.in - -NFA state 84 = month#14.in - 5:[A-Za-z] -> month#14.#1 - Epsilon closure : - (self) - -NFA state 85 = month#14.#1 - 5:[A-Za-z] -> month#14.#2 - Epsilon closure : - (self) - -NFA state 86 = month#14.#2 - 5:[A-Za-z] -> month#14.out - Epsilon closure : - (self) - -NFA state 87 = month#14.out - [(epsilon)] -> #31 - Epsilon closure : - (self) - #31 - year#15.in - -NFA state 88 = #32 - Tags : DS_MY - Epsilon closure : - (self) - -NFA state 89 = year#15.in - 0:[0] -> year#15.#1 - 4:[4-9] -> year#15.#1 - 3:[3] -> year#15.#2 - Epsilon closure : - (self) - -NFA state 90 = year#15.#1 - 0:[0] -> year#15.out - 4:[4-9] -> year#15.out - 3:[3] -> year#15.out - 2:[2] -> year#15.out - 1:[1] -> year#15.out - Epsilon closure : - (self) - -NFA state 91 = year#15.#2 - 2:[2] -> year#15.out - 4:[4-9] -> year#15.out - 3:[3] -> year#15.out - Epsilon closure : - (self) - -NFA state 92 = year#15.out - [(epsilon)] -> #32 - Epsilon closure : - (self) - #32 - -NFA state 93 = #33 - [(epsilon)] -> month#17.in - Epsilon closure : - (self) - month#17.in - -NFA state 94 = ccyy#16.in - 1:[1] -> ccyy#16.#1 - 4:[4-9] -> ccyy#16.#1 - 3:[3] -> ccyy#16.#1 - 2:[2] -> ccyy#16.#1 - Epsilon closure : - (self) - -NFA state 95 = ccyy#16.#1 - 0:[0] -> ccyy#16.#2 - 4:[4-9] -> ccyy#16.#2 - 3:[3] -> ccyy#16.#2 - 2:[2] -> ccyy#16.#2 - 1:[1] -> ccyy#16.#2 - Epsilon closure : - (self) - -NFA state 96 = ccyy#16.#2 - 0:[0] -> ccyy#16.#3 - 4:[4-9] -> ccyy#16.#3 - 3:[3] -> ccyy#16.#3 - 2:[2] -> ccyy#16.#3 - 1:[1] -> ccyy#16.#3 - Epsilon closure : - (self) - -NFA state 97 = ccyy#16.#3 - 0:[0] -> ccyy#16.out - 4:[4-9] -> ccyy#16.out - 3:[3] -> ccyy#16.out - 2:[2] -> ccyy#16.out - 1:[1] -> ccyy#16.out - Epsilon closure : - (self) - -NFA state 98 = ccyy#16.out - [(epsilon)] -> #33 - Epsilon closure : - (self) - #33 - month#17.in - -NFA state 99 = #34 - Tags : DS_YM - Epsilon closure : - (self) - -NFA state 100 = month#17.in - 5:[A-Za-z] -> month#17.#1 - Epsilon closure : - (self) - -NFA state 101 = month#17.#1 - 5:[A-Za-z] -> month#17.#2 - Epsilon closure : - (self) - -NFA state 102 = month#17.#2 - 5:[A-Za-z] -> month#17.out - Epsilon closure : - (self) - -NFA state 103 = month#17.out - [(epsilon)] -> #34 - Epsilon closure : - (self) - #34 - -NFA state 104 = #35 - [(epsilon)] -> ccyy#19.in - Epsilon closure : - (self) - ccyy#19.in - -NFA state 105 = month#18.in - 5:[A-Za-z] -> month#18.#1 - Epsilon closure : - (self) - -NFA state 106 = month#18.#1 - 5:[A-Za-z] -> month#18.#2 - Epsilon closure : - (self) - -NFA state 107 = month#18.#2 - 5:[A-Za-z] -> month#18.out - Epsilon closure : - (self) - -NFA state 108 = month#18.out - [(epsilon)] -> #35 - Epsilon closure : - (self) - #35 - ccyy#19.in - -NFA state 109 = #36 - Tags : DS_MY - Epsilon closure : - (self) - -NFA state 110 = ccyy#19.in - 1:[1] -> ccyy#19.#1 - 4:[4-9] -> ccyy#19.#1 - 3:[3] -> ccyy#19.#1 - 2:[2] -> ccyy#19.#1 - Epsilon closure : - (self) - -NFA state 111 = ccyy#19.#1 - 0:[0] -> ccyy#19.#2 - 4:[4-9] -> ccyy#19.#2 - 3:[3] -> ccyy#19.#2 - 2:[2] -> ccyy#19.#2 - 1:[1] -> ccyy#19.#2 - Epsilon closure : - (self) - -NFA state 112 = ccyy#19.#2 - 0:[0] -> ccyy#19.#3 - 4:[4-9] -> ccyy#19.#3 - 3:[3] -> ccyy#19.#3 - 2:[2] -> ccyy#19.#3 - 1:[1] -> ccyy#19.#3 - Epsilon closure : - (self) - -NFA state 113 = ccyy#19.#3 - 0:[0] -> ccyy#19.out - 4:[4-9] -> ccyy#19.out - 3:[3] -> ccyy#19.out - 2:[2] -> ccyy#19.out - 1:[1] -> ccyy#19.out - Epsilon closure : - (self) - -NFA state 114 = ccyy#19.out - [(epsilon)] -> #36 - Epsilon closure : - (self) - #36 - -NFA state 115 = #37 - [(epsilon)] -> month#21.in - Epsilon closure : - (self) - month#21.in - -NFA state 116 = year#20.in - 0:[0] -> year#20.#1 - 4:[4-9] -> year#20.#1 - 3:[3] -> year#20.#2 - Epsilon closure : - (self) - -NFA state 117 = year#20.#1 - 0:[0] -> year#20.out - 4:[4-9] -> year#20.out - 3:[3] -> year#20.out - 2:[2] -> year#20.out - 1:[1] -> year#20.out - Epsilon closure : - (self) - -NFA state 118 = year#20.#2 - 2:[2] -> year#20.out - 4:[4-9] -> year#20.out - 3:[3] -> year#20.out - Epsilon closure : - (self) - -NFA state 119 = year#20.out - [(epsilon)] -> #37 - Epsilon closure : - (self) - #37 - month#21.in - -NFA state 120 = #38 - 1:[1] -> #39 - 4:[4-9] -> #39 - 3:[3] -> #39 - 2:[2] -> #39 - Epsilon closure : - (self) - -NFA state 121 = month#21.in - 5:[A-Za-z] -> month#21.#1 - Epsilon closure : - (self) - -NFA state 122 = month#21.#1 - 5:[A-Za-z] -> month#21.#2 - Epsilon closure : - (self) - -NFA state 123 = month#21.#2 - 5:[A-Za-z] -> month#21.out - Epsilon closure : - (self) - -NFA state 124 = month#21.out - [(epsilon)] -> #38 - Epsilon closure : - (self) - #38 - -NFA state 125 = #39 - Tags : DS_YMD - Epsilon closure : - (self) - -NFA state 126 = #40 - [(epsilon)] -> month#23.in - Epsilon closure : - (self) - month#23.in - -NFA state 127 = year#22.in - 0:[0] -> year#22.#1 - 4:[4-9] -> year#22.#1 - 3:[3] -> year#22.#2 - Epsilon closure : - (self) - -NFA state 128 = year#22.#1 - 0:[0] -> year#22.out - 4:[4-9] -> year#22.out - 3:[3] -> year#22.out - 2:[2] -> year#22.out - 1:[1] -> year#22.out - Epsilon closure : - (self) - -NFA state 129 = year#22.#2 - 2:[2] -> year#22.out - 4:[4-9] -> year#22.out - 3:[3] -> year#22.out - Epsilon closure : - (self) - -NFA state 130 = year#22.out - [(epsilon)] -> #40 - Epsilon closure : - (self) - #40 - month#23.in - -NFA state 131 = #41 - [(epsilon)] -> day#24.in - Epsilon closure : - (self) - day#24.in - -NFA state 132 = month#23.in - 5:[A-Za-z] -> month#23.#1 - Epsilon closure : - (self) - -NFA state 133 = month#23.#1 - 5:[A-Za-z] -> month#23.#2 - Epsilon closure : - (self) - -NFA state 134 = month#23.#2 - 5:[A-Za-z] -> month#23.out - Epsilon closure : - (self) - -NFA state 135 = month#23.out - [(epsilon)] -> #41 - Epsilon closure : - (self) - #41 - day#24.in - -NFA state 136 = #42 - Tags : DS_YMD - Epsilon closure : - (self) - -NFA state 137 = day#24.in - 1:[1] -> day#24.#1 - 2:[2] -> day#24.#1 - 3:[3] -> day#24.#2 - Epsilon closure : - (self) - -NFA state 138 = day#24.#1 - 0:[0] -> day#24.out - 4:[4-9] -> day#24.out - 3:[3] -> day#24.out - 2:[2] -> day#24.out - 1:[1] -> day#24.out - Epsilon closure : - (self) - -NFA state 139 = day#24.#2 - 0:[0] -> day#24.out - 1:[1] -> day#24.out - Epsilon closure : - (self) - -NFA state 140 = day#24.out - [(epsilon)] -> #42 - Epsilon closure : - (self) - #42 - -NFA state 141 = #43 - [(epsilon)] -> month#25.in - Epsilon closure : - (self) - month#25.in - -NFA state 142 = #44 - [(epsilon)] -> year#26.in - Epsilon closure : - (self) - year#26.in - -NFA state 143 = month#25.in - 5:[A-Za-z] -> month#25.#1 - Epsilon closure : - (self) - -NFA state 144 = month#25.#1 - 5:[A-Za-z] -> month#25.#2 - Epsilon closure : - (self) - -NFA state 145 = month#25.#2 - 5:[A-Za-z] -> month#25.out - Epsilon closure : - (self) - -NFA state 146 = month#25.out - [(epsilon)] -> #44 - Epsilon closure : - (self) - #44 - year#26.in - -NFA state 147 = #45 - Tags : DS_DMY - Epsilon closure : - (self) - -NFA state 148 = year#26.in - 0:[0] -> year#26.#1 - 4:[4-9] -> year#26.#1 - 3:[3] -> year#26.#2 - Epsilon closure : - (self) - -NFA state 149 = year#26.#1 - 0:[0] -> year#26.out - 4:[4-9] -> year#26.out - 3:[3] -> year#26.out - 2:[2] -> year#26.out - 1:[1] -> year#26.out - Epsilon closure : - (self) - -NFA state 150 = year#26.#2 - 2:[2] -> year#26.out - 4:[4-9] -> year#26.out - 3:[3] -> year#26.out - Epsilon closure : - (self) - -NFA state 151 = year#26.out - [(epsilon)] -> #45 - Epsilon closure : - (self) - #45 - -NFA state 152 = #46 - [(epsilon)] -> month#28.in - Epsilon closure : - (self) - month#28.in - -NFA state 153 = day#27.in - 1:[1] -> day#27.#1 - 2:[2] -> day#27.#1 - 3:[3] -> day#27.#2 - Epsilon closure : - (self) - -NFA state 154 = day#27.#1 - 0:[0] -> day#27.out - 4:[4-9] -> day#27.out - 3:[3] -> day#27.out - 2:[2] -> day#27.out - 1:[1] -> day#27.out - Epsilon closure : - (self) - -NFA state 155 = day#27.#2 - 0:[0] -> day#27.out - 1:[1] -> day#27.out - Epsilon closure : - (self) - -NFA state 156 = day#27.out - [(epsilon)] -> #46 - Epsilon closure : - (self) - #46 - month#28.in - -NFA state 157 = #47 - [(epsilon)] -> year#29.in - Epsilon closure : - (self) - year#29.in - -NFA state 158 = month#28.in - 5:[A-Za-z] -> month#28.#1 - Epsilon closure : - (self) - -NFA state 159 = month#28.#1 - 5:[A-Za-z] -> month#28.#2 - Epsilon closure : - (self) - -NFA state 160 = month#28.#2 - 5:[A-Za-z] -> month#28.out - Epsilon closure : - (self) - -NFA state 161 = month#28.out - [(epsilon)] -> #47 - Epsilon closure : - (self) - #47 - year#29.in - -NFA state 162 = #48 - Tags : DS_DMY - Epsilon closure : - (self) - -NFA state 163 = year#29.in - 0:[0] -> year#29.#1 - 4:[4-9] -> year#29.#1 - 3:[3] -> year#29.#2 - Epsilon closure : - (self) - -NFA state 164 = year#29.#1 - 0:[0] -> year#29.out - 4:[4-9] -> year#29.out - 3:[3] -> year#29.out - 2:[2] -> year#29.out - 1:[1] -> year#29.out - Epsilon closure : - (self) - -NFA state 165 = year#29.#2 - 2:[2] -> year#29.out - 4:[4-9] -> year#29.out - 3:[3] -> year#29.out - Epsilon closure : - (self) - -NFA state 166 = year#29.out - [(epsilon)] -> #48 - Epsilon closure : - (self) - #48 - -NFA state 167 = #49 - [(epsilon)] -> month#31.in - Epsilon closure : - (self) - month#31.in - -NFA state 168 = ccyy#30.in - 1:[1] -> ccyy#30.#1 - 4:[4-9] -> ccyy#30.#1 - 3:[3] -> ccyy#30.#1 - 2:[2] -> ccyy#30.#1 - Epsilon closure : - (self) - -NFA state 169 = ccyy#30.#1 - 0:[0] -> ccyy#30.#2 - 4:[4-9] -> ccyy#30.#2 - 3:[3] -> ccyy#30.#2 - 2:[2] -> ccyy#30.#2 - 1:[1] -> ccyy#30.#2 - Epsilon closure : - (self) - -NFA state 170 = ccyy#30.#2 - 0:[0] -> ccyy#30.#3 - 4:[4-9] -> ccyy#30.#3 - 3:[3] -> ccyy#30.#3 - 2:[2] -> ccyy#30.#3 - 1:[1] -> ccyy#30.#3 - Epsilon closure : - (self) - -NFA state 171 = ccyy#30.#3 - 0:[0] -> ccyy#30.out - 4:[4-9] -> ccyy#30.out - 3:[3] -> ccyy#30.out - 2:[2] -> ccyy#30.out - 1:[1] -> ccyy#30.out - Epsilon closure : - (self) - -NFA state 172 = ccyy#30.out - [(epsilon)] -> #49 - Epsilon closure : - (self) - #49 - month#31.in - -NFA state 173 = #50 - 1:[1] -> #51 - 4:[4-9] -> #51 - 3:[3] -> #51 - 2:[2] -> #51 - Epsilon closure : - (self) - -NFA state 174 = month#31.in - 5:[A-Za-z] -> month#31.#1 - Epsilon closure : - (self) - -NFA state 175 = month#31.#1 - 5:[A-Za-z] -> month#31.#2 - Epsilon closure : - (self) - -NFA state 176 = month#31.#2 - 5:[A-Za-z] -> month#31.out - Epsilon closure : - (self) - -NFA state 177 = month#31.out - [(epsilon)] -> #50 - Epsilon closure : - (self) - #50 - -NFA state 178 = #51 - Tags : DS_YMD - Epsilon closure : - (self) - -NFA state 179 = #52 - [(epsilon)] -> month#33.in - Epsilon closure : - (self) - month#33.in - -NFA state 180 = ccyy#32.in - 1:[1] -> ccyy#32.#1 - 4:[4-9] -> ccyy#32.#1 - 3:[3] -> ccyy#32.#1 - 2:[2] -> ccyy#32.#1 - Epsilon closure : - (self) - -NFA state 181 = ccyy#32.#1 - 0:[0] -> ccyy#32.#2 - 4:[4-9] -> ccyy#32.#2 - 3:[3] -> ccyy#32.#2 - 2:[2] -> ccyy#32.#2 - 1:[1] -> ccyy#32.#2 - Epsilon closure : - (self) - -NFA state 182 = ccyy#32.#2 - 0:[0] -> ccyy#32.#3 - 4:[4-9] -> ccyy#32.#3 - 3:[3] -> ccyy#32.#3 - 2:[2] -> ccyy#32.#3 - 1:[1] -> ccyy#32.#3 - Epsilon closure : - (self) - -NFA state 183 = ccyy#32.#3 - 0:[0] -> ccyy#32.out - 4:[4-9] -> ccyy#32.out - 3:[3] -> ccyy#32.out - 2:[2] -> ccyy#32.out - 1:[1] -> ccyy#32.out - Epsilon closure : - (self) - -NFA state 184 = ccyy#32.out - [(epsilon)] -> #52 - Epsilon closure : - (self) - #52 - month#33.in - -NFA state 185 = #53 - [(epsilon)] -> day#34.in - Epsilon closure : - (self) - day#34.in - -NFA state 186 = month#33.in - 5:[A-Za-z] -> month#33.#1 - Epsilon closure : - (self) - -NFA state 187 = month#33.#1 - 5:[A-Za-z] -> month#33.#2 - Epsilon closure : - (self) - -NFA state 188 = month#33.#2 - 5:[A-Za-z] -> month#33.out - Epsilon closure : - (self) - -NFA state 189 = month#33.out - [(epsilon)] -> #53 - Epsilon closure : - (self) - #53 - day#34.in - -NFA state 190 = #54 - Tags : DS_YMD - Epsilon closure : - (self) - -NFA state 191 = day#34.in - 1:[1] -> day#34.#1 - 2:[2] -> day#34.#1 - 3:[3] -> day#34.#2 - Epsilon closure : - (self) - -NFA state 192 = day#34.#1 - 0:[0] -> day#34.out - 4:[4-9] -> day#34.out - 3:[3] -> day#34.out - 2:[2] -> day#34.out - 1:[1] -> day#34.out - Epsilon closure : - (self) - -NFA state 193 = day#34.#2 - 0:[0] -> day#34.out - 1:[1] -> day#34.out - Epsilon closure : - (self) - -NFA state 194 = day#34.out - [(epsilon)] -> #54 - Epsilon closure : - (self) - #54 - -NFA state 195 = #55 - [(epsilon)] -> month#35.in - Epsilon closure : - (self) - month#35.in - -NFA state 196 = #56 - [(epsilon)] -> ccyy#36.in - Epsilon closure : - (self) - ccyy#36.in - -NFA state 197 = month#35.in - 5:[A-Za-z] -> month#35.#1 - Epsilon closure : - (self) - -NFA state 198 = month#35.#1 - 5:[A-Za-z] -> month#35.#2 - Epsilon closure : - (self) - -NFA state 199 = month#35.#2 - 5:[A-Za-z] -> month#35.out - Epsilon closure : - (self) - -NFA state 200 = month#35.out - [(epsilon)] -> #56 - Epsilon closure : - (self) - #56 - ccyy#36.in - -NFA state 201 = #57 - Tags : DS_DMY - Epsilon closure : - (self) - -NFA state 202 = ccyy#36.in - 1:[1] -> ccyy#36.#1 - 4:[4-9] -> ccyy#36.#1 - 3:[3] -> ccyy#36.#1 - 2:[2] -> ccyy#36.#1 - Epsilon closure : - (self) - -NFA state 203 = ccyy#36.#1 - 0:[0] -> ccyy#36.#2 - 4:[4-9] -> ccyy#36.#2 - 3:[3] -> ccyy#36.#2 - 2:[2] -> ccyy#36.#2 - 1:[1] -> ccyy#36.#2 - Epsilon closure : - (self) - -NFA state 204 = ccyy#36.#2 - 0:[0] -> ccyy#36.#3 - 4:[4-9] -> ccyy#36.#3 - 3:[3] -> ccyy#36.#3 - 2:[2] -> ccyy#36.#3 - 1:[1] -> ccyy#36.#3 - Epsilon closure : - (self) - -NFA state 205 = ccyy#36.#3 - 0:[0] -> ccyy#36.out - 4:[4-9] -> ccyy#36.out - 3:[3] -> ccyy#36.out - 2:[2] -> ccyy#36.out - 1:[1] -> ccyy#36.out - Epsilon closure : - (self) - -NFA state 206 = ccyy#36.out - [(epsilon)] -> #57 - Epsilon closure : - (self) - #57 - -NFA state 207 = #58 - [(epsilon)] -> month#38.in - Epsilon closure : - (self) - month#38.in - -NFA state 208 = day#37.in - 1:[1] -> day#37.#1 - 2:[2] -> day#37.#1 - 3:[3] -> day#37.#2 - Epsilon closure : - (self) - -NFA state 209 = day#37.#1 - 0:[0] -> day#37.out - 4:[4-9] -> day#37.out - 3:[3] -> day#37.out - 2:[2] -> day#37.out - 1:[1] -> day#37.out - Epsilon closure : - (self) - -NFA state 210 = day#37.#2 - 0:[0] -> day#37.out - 1:[1] -> day#37.out - Epsilon closure : - (self) - -NFA state 211 = day#37.out - [(epsilon)] -> #58 - Epsilon closure : - (self) - #58 - month#38.in - -NFA state 212 = #59 - [(epsilon)] -> ccyy#39.in - Epsilon closure : - (self) - ccyy#39.in - -NFA state 213 = month#38.in - 5:[A-Za-z] -> month#38.#1 - Epsilon closure : - (self) - -NFA state 214 = month#38.#1 - 5:[A-Za-z] -> month#38.#2 - Epsilon closure : - (self) - -NFA state 215 = month#38.#2 - 5:[A-Za-z] -> month#38.out - Epsilon closure : - (self) - -NFA state 216 = month#38.out - [(epsilon)] -> #59 - Epsilon closure : - (self) - #59 - ccyy#39.in - -NFA state 217 = #60 - Tags : DS_DMY - Epsilon closure : - (self) - -NFA state 218 = ccyy#39.in - 1:[1] -> ccyy#39.#1 - 4:[4-9] -> ccyy#39.#1 - 3:[3] -> ccyy#39.#1 - 2:[2] -> ccyy#39.#1 - Epsilon closure : - (self) - -NFA state 219 = ccyy#39.#1 - 0:[0] -> ccyy#39.#2 - 4:[4-9] -> ccyy#39.#2 - 3:[3] -> ccyy#39.#2 - 2:[2] -> ccyy#39.#2 - 1:[1] -> ccyy#39.#2 - Epsilon closure : - (self) - -NFA state 220 = ccyy#39.#2 - 0:[0] -> ccyy#39.#3 - 4:[4-9] -> ccyy#39.#3 - 3:[3] -> ccyy#39.#3 - 2:[2] -> ccyy#39.#3 - 1:[1] -> ccyy#39.#3 - Epsilon closure : - (self) - -NFA state 221 = ccyy#39.#3 - 0:[0] -> ccyy#39.out - 4:[4-9] -> ccyy#39.out - 3:[3] -> ccyy#39.out - 2:[2] -> ccyy#39.out - 1:[1] -> ccyy#39.out - Epsilon closure : - (self) - -NFA state 222 = ccyy#39.out - [(epsilon)] -> #60 - Epsilon closure : - (self) - #60 - --------------------------------- -DFA structure before compression --------------------------------- -DFA state 0 - NFA states : - in - day#1.in - year#2.in - ccyy#3.in - scaled#4.in - month#5.in - day#7.in - month#9.in - month#10.in - year#12.in - month#14.in - ccyy#16.in - month#18.in - year#20.in - year#22.in - day#27.in - ccyy#30.in - ccyy#32.in - day#37.in - - Forward route : - (START)->(HERE) - Transitions : - 0:[0] -> 1 - 1:[1] -> 2 - 2:[2] -> 2 - 3:[3] -> 3 - 4:[4-9] -> 4 - 5:[A-Za-z] -> 5 - -DFA state 1 - NFA states : - year#2.#1 - #5 - #11 - scaled#4.in - scaled#4.after_value - year#12.#1 - year#20.#1 - year#22.#1 - - Forward route : (from state 0) - (START)->0:[0]->(HERE) - Transitions : - 0:[0] -> 6 - 1:[1] -> 6 - 2:[2] -> 6 - 3:[3] -> 6 - 4:[4-9] -> 6 - 5:[A-Za-z] -> 7 - -DFA state 2 - NFA states : - #1 - day#1.#1 - ccyy#3.#1 - #5 - #11 - scaled#4.in - scaled#4.after_value - #21 - month#6.in - day#7.#1 - ccyy#16.#1 - #43 - month#25.in - day#27.#1 - ccyy#30.#1 - ccyy#32.#1 - #55 - month#35.in - day#37.#1 - - Forward route : (from state 0) - (START)->1:[1]->(HERE) - Transitions : - 0:[0] -> 8 - 1:[1] -> 8 - 2:[2] -> 8 - 3:[3] -> 8 - 4:[4-9] -> 8 - 5:[A-Za-z] -> 9 - NFA exit tags applying : - DS_D - Attributes for <(DEFAULT)> : DS_D - -DFA state 3 - NFA states : - #1 - day#1.#2 - year#2.#2 - ccyy#3.#1 - #5 - #11 - scaled#4.in - scaled#4.after_value - #21 - month#6.in - day#7.#2 - year#12.#2 - ccyy#16.#1 - year#20.#2 - year#22.#2 - #43 - month#25.in - day#27.#2 - ccyy#30.#1 - ccyy#32.#1 - #55 - month#35.in - day#37.#2 - - Forward route : (from state 0) - (START)->3:[3]->(HERE) - Transitions : - 0:[0] -> 8 - 1:[1] -> 8 - 2:[2] -> 10 - 3:[3] -> 10 - 4:[4-9] -> 10 - 5:[A-Za-z] -> 9 - NFA exit tags applying : - DS_D - Attributes for <(DEFAULT)> : DS_D - -DFA state 4 - NFA states : - #1 - year#2.#1 - ccyy#3.#1 - #5 - #11 - scaled#4.in - scaled#4.after_value - #21 - month#6.in - year#12.#1 - ccyy#16.#1 - year#20.#1 - year#22.#1 - #43 - month#25.in - ccyy#30.#1 - ccyy#32.#1 - #55 - month#35.in - - Forward route : (from state 0) - (START)->4:[4-9]->(HERE) - Transitions : - 0:[0] -> 10 - 1:[1] -> 10 - 2:[2] -> 10 - 3:[3] -> 10 - 4:[4-9] -> 10 - 5:[A-Za-z] -> 9 - NFA exit tags applying : - DS_D - Attributes for <(DEFAULT)> : DS_D - -DFA state 5 - NFA states : - month#5.#1 - month#9.#1 - month#10.#1 - month#14.#1 - month#18.#1 - - Forward route : (from state 0) - (START)->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 11 - -DFA state 6 - NFA states : - #3 - year#2.out - #6 - #12 - scaled#4.in - scaled#4.after_value - #29 - year#12.out - month#13.in - #37 - year#20.out - month#21.in - #40 - year#22.out - month#23.in - - Forward route : (from state 1) - (START)->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 12 - 1:[1] -> 12 - 2:[2] -> 12 - 3:[3] -> 12 - 4:[4-9] -> 12 - 5:[A-Za-z] -> 13 - NFA exit tags applying : - DS_Y - Attributes for <(DEFAULT)> : DS_Y - -DFA state 7 - NFA states : - #19 - scaled#4.out - - Forward route : (from state 1) - (START)->0:[0]->5:[A-Za-z]->(HERE) - Transitions : - NFA exit tags applying : - DS_SCALED - Attributes for <(DEFAULT)> : DS_SCALED - -DFA state 8 - NFA states : - #2 - day#1.out - ccyy#3.#2 - #6 - #12 - scaled#4.in - scaled#4.after_value - #23 - day#7.out - month#8.in - ccyy#16.#2 - #46 - day#27.out - month#28.in - ccyy#30.#2 - ccyy#32.#2 - #58 - day#37.out - month#38.in - - Forward route : (from state 2) - (START)->1:[1]->0:[0]->(HERE) - Transitions : - 0:[0] -> 14 - 1:[1] -> 14 - 2:[2] -> 14 - 3:[3] -> 14 - 4:[4-9] -> 14 - 5:[A-Za-z] -> 15 - NFA exit tags applying : - DS_D - Attributes for <(DEFAULT)> : DS_D - -DFA state 9 - NFA states : - #19 - scaled#4.out - month#6.#1 - month#25.#1 - month#35.#1 - - Forward route : (from state 2) - (START)->1:[1]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 16 - NFA exit tags applying : - DS_SCALED - Attributes for <(DEFAULT)> : DS_SCALED - -DFA state 10 - NFA states : - #3 - year#2.out - ccyy#3.#2 - #6 - #12 - scaled#4.in - scaled#4.after_value - #29 - year#12.out - month#13.in - ccyy#16.#2 - #37 - year#20.out - month#21.in - #40 - year#22.out - month#23.in - ccyy#30.#2 - ccyy#32.#2 - - Forward route : (from state 3) - (START)->3:[3]->2:[2]->(HERE) - Transitions : - 0:[0] -> 14 - 1:[1] -> 14 - 2:[2] -> 14 - 3:[3] -> 14 - 4:[4-9] -> 14 - 5:[A-Za-z] -> 13 - NFA exit tags applying : - DS_Y - Attributes for <(DEFAULT)> : DS_Y - -DFA state 11 - NFA states : - month#5.#2 - month#9.#2 - month#10.#2 - month#14.#2 - month#18.#2 - - Forward route : (from state 5) - (START)->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 17 - -DFA state 12 - NFA states : - #7 - #13 - scaled#4.in - scaled#4.after_value - - Forward route : (from state 6) - (START)->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 18 - 1:[1] -> 18 - 2:[2] -> 18 - 3:[3] -> 18 - 4:[4-9] -> 18 - 5:[A-Za-z] -> 7 - -DFA state 13 - NFA states : - #19 - scaled#4.out - month#13.#1 - month#21.#1 - month#23.#1 - - Forward route : (from state 6) - (START)->0:[0]->0:[0]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 19 - NFA exit tags applying : - DS_SCALED - Attributes for <(DEFAULT)> : DS_SCALED - -DFA state 14 - NFA states : - ccyy#3.#3 - #7 - #13 - scaled#4.in - scaled#4.after_value - ccyy#16.#3 - ccyy#30.#3 - ccyy#32.#3 - - Forward route : (from state 8) - (START)->1:[1]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 20 - 1:[1] -> 20 - 2:[2] -> 20 - 3:[3] -> 20 - 4:[4-9] -> 20 - 5:[A-Za-z] -> 7 - -DFA state 15 - NFA states : - #19 - scaled#4.out - month#8.#1 - month#28.#1 - month#38.#1 - - Forward route : (from state 8) - (START)->1:[1]->0:[0]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 21 - NFA exit tags applying : - DS_SCALED - Attributes for <(DEFAULT)> : DS_SCALED - -DFA state 16 - NFA states : - month#6.#2 - month#25.#2 - month#35.#2 - - Forward route : (from state 9) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 22 - -DFA state 17 - NFA states : - #20 - month#5.out - #25 - month#9.out - #27 - month#10.out - day#11.in - #31 - month#14.out - year#15.in - #35 - month#18.out - ccyy#19.in - - Forward route : (from state 11) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 0:[0] -> 23 - 1:[1] -> 24 - 2:[2] -> 24 - 3:[3] -> 25 - 4:[4-9] -> 26 - NFA exit tags applying : - DS_M - Attributes for <(DEFAULT)> : DS_M - -DFA state 18 - NFA states : - #8 - #14 - scaled#4.in - scaled#4.after_value - - Forward route : (from state 12) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 27 - 1:[1] -> 27 - 2:[2] -> 27 - 3:[3] -> 27 - 4:[4-9] -> 27 - 5:[A-Za-z] -> 7 - -DFA state 19 - NFA states : - month#13.#2 - month#21.#2 - month#23.#2 - - Forward route : (from state 13) - (START)->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 28 - -DFA state 20 - NFA states : - #4 - ccyy#3.out - #8 - #14 - scaled#4.in - scaled#4.after_value - #33 - ccyy#16.out - month#17.in - #49 - ccyy#30.out - month#31.in - #52 - ccyy#32.out - month#33.in - - Forward route : (from state 14) - (START)->1:[1]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 27 - 1:[1] -> 27 - 2:[2] -> 27 - 3:[3] -> 27 - 4:[4-9] -> 27 - 5:[A-Za-z] -> 29 - NFA exit tags applying : - DS_Y - Attributes for <(DEFAULT)> : DS_Y - -DFA state 21 - NFA states : - month#8.#2 - month#28.#2 - month#38.#2 - - Forward route : (from state 15) - (START)->1:[1]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 30 - -DFA state 22 - NFA states : - #22 - month#6.out - #44 - month#25.out - year#26.in - #56 - month#35.out - ccyy#36.in - - Forward route : (from state 16) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 0:[0] -> 31 - 1:[1] -> 32 - 2:[2] -> 32 - 3:[3] -> 33 - 4:[4-9] -> 34 - NFA exit tags applying : - DS_DM - Attributes for <(DEFAULT)> : DS_DM - -DFA state 23 - NFA states : - year#15.#1 - - Forward route : (from state 17) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->0:[0]->(HERE) - Transitions : - 0:[0] -> 35 - 1:[1] -> 35 - 2:[2] -> 35 - 3:[3] -> 35 - 4:[4-9] -> 35 - -DFA state 24 - NFA states : - #26 - day#11.#1 - ccyy#19.#1 - - Forward route : (from state 17) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->(HERE) - Transitions : - 0:[0] -> 36 - 1:[1] -> 36 - 2:[2] -> 36 - 3:[3] -> 36 - 4:[4-9] -> 36 - NFA exit tags applying : - DS_MD - Attributes for <(DEFAULT)> : DS_MD - -DFA state 25 - NFA states : - #26 - day#11.#2 - year#15.#2 - ccyy#19.#1 - - Forward route : (from state 17) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->(HERE) - Transitions : - 0:[0] -> 36 - 1:[1] -> 36 - 2:[2] -> 37 - 3:[3] -> 37 - 4:[4-9] -> 37 - NFA exit tags applying : - DS_MD - Attributes for <(DEFAULT)> : DS_MD - -DFA state 26 - NFA states : - #26 - year#15.#1 - ccyy#19.#1 - - Forward route : (from state 17) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->4:[4-9]->(HERE) - Transitions : - 0:[0] -> 37 - 1:[1] -> 37 - 2:[2] -> 37 - 3:[3] -> 37 - 4:[4-9] -> 37 - NFA exit tags applying : - DS_MD - Attributes for <(DEFAULT)> : DS_MD - -DFA state 27 - NFA states : - #9 - #15 - scaled#4.in - scaled#4.after_value - - Forward route : (from state 18) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 38 - 1:[1] -> 38 - 2:[2] -> 38 - 3:[3] -> 38 - 4:[4-9] -> 38 - 5:[A-Za-z] -> 7 - -DFA state 28 - NFA states : - #30 - month#13.out - #38 - month#21.out - #41 - month#23.out - day#24.in - - Forward route : (from state 19) - (START)->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 1:[1] -> 39 - 2:[2] -> 39 - 3:[3] -> 40 - 4:[4-9] -> 41 - NFA exit tags applying : - DS_YM - Attributes for <(DEFAULT)> : DS_YM - -DFA state 29 - NFA states : - #19 - scaled#4.out - month#17.#1 - month#31.#1 - month#33.#1 - - Forward route : (from state 20) - (START)->1:[1]->0:[0]->0:[0]->0:[0]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 42 - NFA exit tags applying : - DS_SCALED - Attributes for <(DEFAULT)> : DS_SCALED - -DFA state 30 - NFA states : - #24 - month#8.out - #47 - month#28.out - year#29.in - #59 - month#38.out - ccyy#39.in - - Forward route : (from state 21) - (START)->1:[1]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 0:[0] -> 43 - 1:[1] -> 44 - 2:[2] -> 44 - 3:[3] -> 45 - 4:[4-9] -> 46 - NFA exit tags applying : - DS_DM - Attributes for <(DEFAULT)> : DS_DM - -DFA state 31 - NFA states : - year#26.#1 - - Forward route : (from state 22) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->0:[0]->(HERE) - Transitions : - 0:[0] -> 47 - 1:[1] -> 47 - 2:[2] -> 47 - 3:[3] -> 47 - 4:[4-9] -> 47 - -DFA state 32 - NFA states : - ccyy#36.#1 - - Forward route : (from state 22) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->(HERE) - Transitions : - 0:[0] -> 48 - 1:[1] -> 48 - 2:[2] -> 48 - 3:[3] -> 48 - 4:[4-9] -> 48 - -DFA state 33 - NFA states : - year#26.#2 - ccyy#36.#1 - - Forward route : (from state 22) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->(HERE) - Transitions : - 0:[0] -> 48 - 1:[1] -> 48 - 2:[2] -> 49 - 3:[3] -> 49 - 4:[4-9] -> 49 - -DFA state 34 - NFA states : - year#26.#1 - ccyy#36.#1 - - Forward route : (from state 22) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->4:[4-9]->(HERE) - Transitions : - 0:[0] -> 49 - 1:[1] -> 49 - 2:[2] -> 49 - 3:[3] -> 49 - 4:[4-9] -> 49 - -DFA state 35 - NFA states : - #32 - year#15.out - - Forward route : (from state 23) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->0:[0]->0:[0]->(HERE) - Transitions : - NFA exit tags applying : - DS_MY - Attributes for <(DEFAULT)> : DS_MY - -DFA state 36 - NFA states : - #28 - day#11.out - ccyy#19.#2 - - Forward route : (from state 24) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->(HERE) - Transitions : - 0:[0] -> 50 - 1:[1] -> 50 - 2:[2] -> 50 - 3:[3] -> 50 - 4:[4-9] -> 50 - NFA exit tags applying : - DS_MD - Attributes for <(DEFAULT)> : DS_MD - -DFA state 37 - NFA states : - #32 - year#15.out - ccyy#19.#2 - - Forward route : (from state 25) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->2:[2]->(HERE) - Transitions : - 0:[0] -> 50 - 1:[1] -> 50 - 2:[2] -> 50 - 3:[3] -> 50 - 4:[4-9] -> 50 - NFA exit tags applying : - DS_MY - Attributes for <(DEFAULT)> : DS_MY - -DFA state 38 - NFA states : - #10 - #16 - scaled#4.in - scaled#4.after_value - - Forward route : (from state 27) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 51 - 1:[1] -> 51 - 2:[2] -> 51 - 3:[3] -> 51 - 4:[4-9] -> 51 - 5:[A-Za-z] -> 7 - NFA exit tags applying : - DS_YYMMDD - Attributes for <(DEFAULT)> : DS_YYMMDD - -DFA state 39 - NFA states : - #39 - day#24.#1 - - Forward route : (from state 28) - (START)->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->(HERE) - Transitions : - 0:[0] -> 52 - 1:[1] -> 52 - 2:[2] -> 52 - 3:[3] -> 52 - 4:[4-9] -> 52 - NFA exit tags applying : - DS_YMD - Attributes for <(DEFAULT)> : DS_YMD - -DFA state 40 - NFA states : - #39 - day#24.#2 - - Forward route : (from state 28) - (START)->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->(HERE) - Transitions : - 0:[0] -> 52 - 1:[1] -> 52 - NFA exit tags applying : - DS_YMD - Attributes for <(DEFAULT)> : DS_YMD - -DFA state 41 - NFA states : - #39 - - Forward route : (from state 28) - (START)->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->4:[4-9]->(HERE) - Transitions : - NFA exit tags applying : - DS_YMD - Attributes for <(DEFAULT)> : DS_YMD - -DFA state 42 - NFA states : - month#17.#2 - month#31.#2 - month#33.#2 - - Forward route : (from state 29) - (START)->1:[1]->0:[0]->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 53 - -DFA state 43 - NFA states : - year#29.#1 - - Forward route : (from state 30) - (START)->1:[1]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->0:[0]->(HERE) - Transitions : - 0:[0] -> 54 - 1:[1] -> 54 - 2:[2] -> 54 - 3:[3] -> 54 - 4:[4-9] -> 54 - -DFA state 44 - NFA states : - ccyy#39.#1 - - Forward route : (from state 30) - (START)->1:[1]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->(HERE) - Transitions : - 0:[0] -> 55 - 1:[1] -> 55 - 2:[2] -> 55 - 3:[3] -> 55 - 4:[4-9] -> 55 - -DFA state 45 - NFA states : - year#29.#2 - ccyy#39.#1 - - Forward route : (from state 30) - (START)->1:[1]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->(HERE) - Transitions : - 0:[0] -> 55 - 1:[1] -> 55 - 2:[2] -> 56 - 3:[3] -> 56 - 4:[4-9] -> 56 - -DFA state 46 - NFA states : - year#29.#1 - ccyy#39.#1 - - Forward route : (from state 30) - (START)->1:[1]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->4:[4-9]->(HERE) - Transitions : - 0:[0] -> 56 - 1:[1] -> 56 - 2:[2] -> 56 - 3:[3] -> 56 - 4:[4-9] -> 56 - -DFA state 47 - NFA states : - #45 - year#26.out - - Forward route : (from state 31) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->0:[0]->0:[0]->(HERE) - Transitions : - NFA exit tags applying : - DS_DMY - Attributes for <(DEFAULT)> : DS_DMY - -DFA state 48 - NFA states : - ccyy#36.#2 - - Forward route : (from state 32) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->(HERE) - Transitions : - 0:[0] -> 57 - 1:[1] -> 57 - 2:[2] -> 57 - 3:[3] -> 57 - 4:[4-9] -> 57 - -DFA state 49 - NFA states : - #45 - year#26.out - ccyy#36.#2 - - Forward route : (from state 33) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->2:[2]->(HERE) - Transitions : - 0:[0] -> 57 - 1:[1] -> 57 - 2:[2] -> 57 - 3:[3] -> 57 - 4:[4-9] -> 57 - NFA exit tags applying : - DS_DMY - Attributes for <(DEFAULT)> : DS_DMY - -DFA state 50 - NFA states : - ccyy#19.#3 - - Forward route : (from state 36) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 58 - 1:[1] -> 58 - 2:[2] -> 58 - 3:[3] -> 58 - 4:[4-9] -> 58 - -DFA state 51 - NFA states : - #17 - scaled#4.in - scaled#4.after_value - - Forward route : (from state 38) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 59 - 1:[1] -> 59 - 2:[2] -> 59 - 3:[3] -> 59 - 4:[4-9] -> 59 - 5:[A-Za-z] -> 7 - -DFA state 52 - NFA states : - #42 - day#24.out - - Forward route : (from state 39) - (START)->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->(HERE) - Transitions : - NFA exit tags applying : - DS_YMD - Attributes for <(DEFAULT)> : DS_YMD - -DFA state 53 - NFA states : - #34 - month#17.out - #50 - month#31.out - #53 - month#33.out - day#34.in - - Forward route : (from state 42) - (START)->1:[1]->0:[0]->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 1:[1] -> 60 - 2:[2] -> 60 - 3:[3] -> 61 - 4:[4-9] -> 62 - NFA exit tags applying : - DS_YM - Attributes for <(DEFAULT)> : DS_YM - -DFA state 54 - NFA states : - #48 - year#29.out - - Forward route : (from state 43) - (START)->1:[1]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->0:[0]->0:[0]->(HERE) - Transitions : - NFA exit tags applying : - DS_DMY - Attributes for <(DEFAULT)> : DS_DMY - -DFA state 55 - NFA states : - ccyy#39.#2 - - Forward route : (from state 44) - (START)->1:[1]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->(HERE) - Transitions : - 0:[0] -> 63 - 1:[1] -> 63 - 2:[2] -> 63 - 3:[3] -> 63 - 4:[4-9] -> 63 - -DFA state 56 - NFA states : - #48 - year#29.out - ccyy#39.#2 - - Forward route : (from state 45) - (START)->1:[1]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->2:[2]->(HERE) - Transitions : - 0:[0] -> 63 - 1:[1] -> 63 - 2:[2] -> 63 - 3:[3] -> 63 - 4:[4-9] -> 63 - NFA exit tags applying : - DS_DMY - Attributes for <(DEFAULT)> : DS_DMY - -DFA state 57 - NFA states : - ccyy#36.#3 - - Forward route : (from state 48) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 64 - 1:[1] -> 64 - 2:[2] -> 64 - 3:[3] -> 64 - 4:[4-9] -> 64 - -DFA state 58 - NFA states : - #36 - ccyy#19.out - - Forward route : (from state 50) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - NFA exit tags applying : - DS_MY - Attributes for <(DEFAULT)> : DS_MY - -DFA state 59 - NFA states : - #18 - scaled#4.in - scaled#4.after_value - - Forward route : (from state 51) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 65 - 1:[1] -> 65 - 2:[2] -> 65 - 3:[3] -> 65 - 4:[4-9] -> 65 - 5:[A-Za-z] -> 7 - NFA exit tags applying : - DS_YYMMDD - Attributes for <(DEFAULT)> : DS_YYMMDD - -DFA state 60 - NFA states : - #51 - day#34.#1 - - Forward route : (from state 53) - (START)->1:[1]->0:[0]->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->(HERE) - Transitions : - 0:[0] -> 66 - 1:[1] -> 66 - 2:[2] -> 66 - 3:[3] -> 66 - 4:[4-9] -> 66 - NFA exit tags applying : - DS_YMD - Attributes for <(DEFAULT)> : DS_YMD - -DFA state 61 - NFA states : - #51 - day#34.#2 - - Forward route : (from state 53) - (START)->1:[1]->0:[0]->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->(HERE) - Transitions : - 0:[0] -> 66 - 1:[1] -> 66 - NFA exit tags applying : - DS_YMD - Attributes for <(DEFAULT)> : DS_YMD - -DFA state 62 - NFA states : - #51 - - Forward route : (from state 53) - (START)->1:[1]->0:[0]->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->4:[4-9]->(HERE) - Transitions : - NFA exit tags applying : - DS_YMD - Attributes for <(DEFAULT)> : DS_YMD - -DFA state 63 - NFA states : - ccyy#39.#3 - - Forward route : (from state 55) - (START)->1:[1]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 67 - 1:[1] -> 67 - 2:[2] -> 67 - 3:[3] -> 67 - 4:[4-9] -> 67 - -DFA state 64 - NFA states : - #57 - ccyy#36.out - - Forward route : (from state 57) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - NFA exit tags applying : - DS_DMY - Attributes for <(DEFAULT)> : DS_DMY - -DFA state 65 - NFA states : - scaled#4.in - scaled#4.after_value - - Forward route : (from state 59) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 65 - 1:[1] -> 65 - 2:[2] -> 65 - 3:[3] -> 65 - 4:[4-9] -> 65 - 5:[A-Za-z] -> 7 - -DFA state 66 - NFA states : - #54 - day#34.out - - Forward route : (from state 60) - (START)->1:[1]->0:[0]->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->(HERE) - Transitions : - NFA exit tags applying : - DS_YMD - Attributes for <(DEFAULT)> : DS_YMD - -DFA state 67 - NFA states : - #60 - ccyy#39.out - - Forward route : (from state 63) - (START)->1:[1]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - NFA exit tags applying : - DS_DMY - Attributes for <(DEFAULT)> : DS_DMY - - -Entry states in DFA: -Entry <(ONLY ENTRY)> : 0 -Searching for dead states... -(no dead states found) - ------------------------------ ------- COMPRESSING DFA ------ ------------------------------ -Old DFA state 0 becomes 0 -Old DFA state 1 becomes 1 -Old DFA state 2 becomes 2 -Old DFA state 3 becomes 3 -Old DFA state 4 becomes 4 -Old DFA state 5 becomes 5 -Old DFA state 6 becomes 6 -Old DFA state 7 becomes 7 -Old DFA state 8 becomes 8 -Old DFA state 9 becomes 9 -Old DFA state 10 becomes 10 -Old DFA state 11 becomes 11 -Old DFA state 12 becomes 12 -Old DFA state 13 becomes 13 -Old DFA state 14 becomes 14 -Old DFA state 15 becomes 9 (formerly 9) -Old DFA state 16 becomes 15 -Old DFA state 17 becomes 16 -Old DFA state 18 becomes 17 -Old DFA state 19 becomes 18 -Old DFA state 20 becomes 19 -Old DFA state 21 becomes 15 (formerly 16) -Old DFA state 22 becomes 20 -Old DFA state 23 becomes 21 -Old DFA state 24 becomes 22 -Old DFA state 25 becomes 23 -Old DFA state 26 becomes 24 -Old DFA state 27 becomes 25 -Old DFA state 28 becomes 26 -Old DFA state 29 becomes 13 (formerly 13) -Old DFA state 30 becomes 20 (formerly 22) -Old DFA state 31 becomes 27 -Old DFA state 32 becomes 28 -Old DFA state 33 becomes 29 -Old DFA state 34 becomes 30 -Old DFA state 35 becomes 31 -Old DFA state 36 becomes 32 -Old DFA state 37 becomes 33 -Old DFA state 38 becomes 34 -Old DFA state 39 becomes 35 -Old DFA state 40 becomes 36 -Old DFA state 41 becomes 37 -Old DFA state 42 becomes 18 (formerly 19) -Old DFA state 43 becomes 27 (formerly 31) -Old DFA state 44 becomes 28 (formerly 32) -Old DFA state 45 becomes 29 (formerly 33) -Old DFA state 46 becomes 30 (formerly 34) -Old DFA state 47 becomes 38 -Old DFA state 48 becomes 39 -Old DFA state 49 becomes 40 -Old DFA state 50 becomes 21 (formerly 23) -Old DFA state 51 becomes 41 -Old DFA state 52 becomes 37 (formerly 41) -Old DFA state 53 becomes 26 (formerly 28) -Old DFA state 54 becomes 38 (formerly 47) -Old DFA state 55 becomes 39 (formerly 48) -Old DFA state 56 becomes 40 (formerly 49) -Old DFA state 57 becomes 27 (formerly 31) -Old DFA state 58 becomes 31 (formerly 35) -Old DFA state 59 becomes 42 -Old DFA state 60 becomes 35 (formerly 39) -Old DFA state 61 becomes 36 (formerly 40) -Old DFA state 62 becomes 37 (formerly 41) -Old DFA state 63 becomes 27 (formerly 31) -Old DFA state 64 becomes 38 (formerly 47) -Old DFA state 65 becomes 43 -Old DFA state 66 becomes 37 (formerly 41) -Old DFA state 67 becomes 38 (formerly 47) -Entry <(ONLY ENTRY)>, formerly state 0, now state 0 -------------------------------- -DFA structure after compression -------------------------------- -DFA state 0 - Forward route : - (START)->(HERE) - Transitions : - 0:[0] -> 1 - 1:[1] -> 2 - 2:[2] -> 2 - 3:[3] -> 3 - 4:[4-9] -> 4 - 5:[A-Za-z] -> 5 - -DFA state 1 - Forward route : (from state 0) - (START)->0:[0]->(HERE) - Transitions : - 0:[0] -> 6 - 1:[1] -> 6 - 2:[2] -> 6 - 3:[3] -> 6 - 4:[4-9] -> 6 - 5:[A-Za-z] -> 7 - -DFA state 2 - Forward route : (from state 0) - (START)->1:[1]->(HERE) - Transitions : - 0:[0] -> 8 - 1:[1] -> 8 - 2:[2] -> 8 - 3:[3] -> 8 - 4:[4-9] -> 8 - 5:[A-Za-z] -> 9 - NFA exit tags applying : - DS_D - Attributes for <(DEFAULT)> : DS_D - -DFA state 3 - Forward route : (from state 0) - (START)->3:[3]->(HERE) - Transitions : - 0:[0] -> 8 - 1:[1] -> 8 - 2:[2] -> 10 - 3:[3] -> 10 - 4:[4-9] -> 10 - 5:[A-Za-z] -> 9 - Use state 2 as basis (3 fixups) - NFA exit tags applying : - DS_D - Attributes for <(DEFAULT)> : DS_D - -DFA state 4 - Forward route : (from state 0) - (START)->4:[4-9]->(HERE) - Transitions : - 0:[0] -> 10 - 1:[1] -> 10 - 2:[2] -> 10 - 3:[3] -> 10 - 4:[4-9] -> 10 - 5:[A-Za-z] -> 9 - NFA exit tags applying : - DS_D - Attributes for <(DEFAULT)> : DS_D - -DFA state 5 - Forward route : (from state 0) - (START)->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 11 - -DFA state 6 - Forward route : (from state 1) - (START)->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 12 - 1:[1] -> 12 - 2:[2] -> 12 - 3:[3] -> 12 - 4:[4-9] -> 12 - 5:[A-Za-z] -> 13 - NFA exit tags applying : - DS_Y - Attributes for <(DEFAULT)> : DS_Y - -DFA state 7 - Forward route : (from state 1) - (START)->0:[0]->5:[A-Za-z]->(HERE) - Transitions : - NFA exit tags applying : - DS_SCALED - Attributes for <(DEFAULT)> : DS_SCALED - -DFA state 8 - Forward route : (from state 2) - (START)->1:[1]->0:[0]->(HERE) - Transitions : - 0:[0] -> 14 - 1:[1] -> 14 - 2:[2] -> 14 - 3:[3] -> 14 - 4:[4-9] -> 14 - 5:[A-Za-z] -> 9 - NFA exit tags applying : - DS_D - Attributes for <(DEFAULT)> : DS_D - -DFA state 9 - Forward route : (from state 2) - (START)->1:[1]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 15 - NFA exit tags applying : - DS_SCALED - Attributes for <(DEFAULT)> : DS_SCALED - -DFA state 10 - Forward route : (from state 3) - (START)->3:[3]->2:[2]->(HERE) - Transitions : - 0:[0] -> 14 - 1:[1] -> 14 - 2:[2] -> 14 - 3:[3] -> 14 - 4:[4-9] -> 14 - 5:[A-Za-z] -> 13 - Use state 8 as basis (1 fixups) - NFA exit tags applying : - DS_Y - Attributes for <(DEFAULT)> : DS_Y - -DFA state 11 - Forward route : (from state 5) - (START)->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 16 - -DFA state 12 - Forward route : (from state 6) - (START)->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 17 - 1:[1] -> 17 - 2:[2] -> 17 - 3:[3] -> 17 - 4:[4-9] -> 17 - 5:[A-Za-z] -> 7 - -DFA state 13 - Forward route : (from state 6) - (START)->0:[0]->0:[0]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 18 - NFA exit tags applying : - DS_SCALED - Attributes for <(DEFAULT)> : DS_SCALED - -DFA state 14 - Forward route : (from state 8) - (START)->1:[1]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 19 - 1:[1] -> 19 - 2:[2] -> 19 - 3:[3] -> 19 - 4:[4-9] -> 19 - 5:[A-Za-z] -> 7 - -DFA state 15 - Forward route : (from state 9) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 20 - -DFA state 16 - Forward route : (from state 11) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 0:[0] -> 21 - 1:[1] -> 22 - 2:[2] -> 22 - 3:[3] -> 23 - 4:[4-9] -> 24 - NFA exit tags applying : - DS_M - Attributes for <(DEFAULT)> : DS_M - -DFA state 17 - Forward route : (from state 12) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 25 - 1:[1] -> 25 - 2:[2] -> 25 - 3:[3] -> 25 - 4:[4-9] -> 25 - 5:[A-Za-z] -> 7 - -DFA state 18 - Forward route : (from state 13) - (START)->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 5:[A-Za-z] -> 26 - -DFA state 19 - Forward route : (from state 14) - (START)->1:[1]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 25 - 1:[1] -> 25 - 2:[2] -> 25 - 3:[3] -> 25 - 4:[4-9] -> 25 - 5:[A-Za-z] -> 13 - Use state 17 as basis (1 fixups) - NFA exit tags applying : - DS_Y - Attributes for <(DEFAULT)> : DS_Y - -DFA state 20 - Forward route : (from state 15) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 0:[0] -> 27 - 1:[1] -> 28 - 2:[2] -> 28 - 3:[3] -> 29 - 4:[4-9] -> 30 - NFA exit tags applying : - DS_DM - Attributes for <(DEFAULT)> : DS_DM - -DFA state 21 - Forward route : (from state 16) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->0:[0]->(HERE) - Transitions : - 0:[0] -> 31 - 1:[1] -> 31 - 2:[2] -> 31 - 3:[3] -> 31 - 4:[4-9] -> 31 - -DFA state 22 - Forward route : (from state 16) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->(HERE) - Transitions : - 0:[0] -> 32 - 1:[1] -> 32 - 2:[2] -> 32 - 3:[3] -> 32 - 4:[4-9] -> 32 - NFA exit tags applying : - DS_MD - Attributes for <(DEFAULT)> : DS_MD - -DFA state 23 - Forward route : (from state 16) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->(HERE) - Transitions : - 0:[0] -> 32 - 1:[1] -> 32 - 2:[2] -> 33 - 3:[3] -> 33 - 4:[4-9] -> 33 - NFA exit tags applying : - DS_MD - Attributes for <(DEFAULT)> : DS_MD - -DFA state 24 - Forward route : (from state 16) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->4:[4-9]->(HERE) - Transitions : - 0:[0] -> 33 - 1:[1] -> 33 - 2:[2] -> 33 - 3:[3] -> 33 - 4:[4-9] -> 33 - Use state 23 as basis (2 fixups) - NFA exit tags applying : - DS_MD - Attributes for <(DEFAULT)> : DS_MD - -DFA state 25 - Forward route : (from state 17) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 34 - 1:[1] -> 34 - 2:[2] -> 34 - 3:[3] -> 34 - 4:[4-9] -> 34 - 5:[A-Za-z] -> 7 - -DFA state 26 - Forward route : (from state 18) - (START)->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->(HERE) - Transitions : - 1:[1] -> 35 - 2:[2] -> 35 - 3:[3] -> 36 - 4:[4-9] -> 37 - NFA exit tags applying : - DS_YM - Attributes for <(DEFAULT)> : DS_YM - -DFA state 27 - Forward route : (from state 20) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->0:[0]->(HERE) - Transitions : - 0:[0] -> 38 - 1:[1] -> 38 - 2:[2] -> 38 - 3:[3] -> 38 - 4:[4-9] -> 38 - -DFA state 28 - Forward route : (from state 20) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->(HERE) - Transitions : - 0:[0] -> 39 - 1:[1] -> 39 - 2:[2] -> 39 - 3:[3] -> 39 - 4:[4-9] -> 39 - -DFA state 29 - Forward route : (from state 20) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->(HERE) - Transitions : - 0:[0] -> 39 - 1:[1] -> 39 - 2:[2] -> 40 - 3:[3] -> 40 - 4:[4-9] -> 40 - -DFA state 30 - Forward route : (from state 20) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->4:[4-9]->(HERE) - Transitions : - 0:[0] -> 40 - 1:[1] -> 40 - 2:[2] -> 40 - 3:[3] -> 40 - 4:[4-9] -> 40 - Use state 29 as basis (2 fixups) - -DFA state 31 - Forward route : (from state 21) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->0:[0]->0:[0]->(HERE) - Transitions : - NFA exit tags applying : - DS_MY - Attributes for <(DEFAULT)> : DS_MY - -DFA state 32 - Forward route : (from state 22) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->(HERE) - Transitions : - 0:[0] -> 21 - 1:[1] -> 21 - 2:[2] -> 21 - 3:[3] -> 21 - 4:[4-9] -> 21 - NFA exit tags applying : - DS_MD - Attributes for <(DEFAULT)> : DS_MD - -DFA state 33 - Forward route : (from state 23) - (START)->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->2:[2]->(HERE) - Transitions : - 0:[0] -> 21 - 1:[1] -> 21 - 2:[2] -> 21 - 3:[3] -> 21 - 4:[4-9] -> 21 - Use state 32 as basis (0 fixups) - NFA exit tags applying : - DS_MY - Attributes for <(DEFAULT)> : DS_MY - -DFA state 34 - Forward route : (from state 25) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 41 - 1:[1] -> 41 - 2:[2] -> 41 - 3:[3] -> 41 - 4:[4-9] -> 41 - 5:[A-Za-z] -> 7 - NFA exit tags applying : - DS_YYMMDD - Attributes for <(DEFAULT)> : DS_YYMMDD - -DFA state 35 - Forward route : (from state 26) - (START)->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->(HERE) - Transitions : - 0:[0] -> 37 - 1:[1] -> 37 - 2:[2] -> 37 - 3:[3] -> 37 - 4:[4-9] -> 37 - NFA exit tags applying : - DS_YMD - Attributes for <(DEFAULT)> : DS_YMD - -DFA state 36 - Forward route : (from state 26) - (START)->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->(HERE) - Transitions : - 0:[0] -> 37 - 1:[1] -> 37 - NFA exit tags applying : - DS_YMD - Attributes for <(DEFAULT)> : DS_YMD - -DFA state 37 - Forward route : (from state 26) - (START)->0:[0]->0:[0]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->4:[4-9]->(HERE) - Transitions : - NFA exit tags applying : - DS_YMD - Attributes for <(DEFAULT)> : DS_YMD - -DFA state 38 - Forward route : (from state 27) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->0:[0]->0:[0]->(HERE) - Transitions : - NFA exit tags applying : - DS_DMY - Attributes for <(DEFAULT)> : DS_DMY - -DFA state 39 - Forward route : (from state 28) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->1:[1]->0:[0]->(HERE) - Transitions : - 0:[0] -> 27 - 1:[1] -> 27 - 2:[2] -> 27 - 3:[3] -> 27 - 4:[4-9] -> 27 - -DFA state 40 - Forward route : (from state 29) - (START)->1:[1]->5:[A-Za-z]->5:[A-Za-z]->5:[A-Za-z]->3:[3]->2:[2]->(HERE) - Transitions : - 0:[0] -> 27 - 1:[1] -> 27 - 2:[2] -> 27 - 3:[3] -> 27 - 4:[4-9] -> 27 - Use state 39 as basis (0 fixups) - NFA exit tags applying : - DS_DMY - Attributes for <(DEFAULT)> : DS_DMY - -DFA state 41 - Forward route : (from state 34) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 42 - 1:[1] -> 42 - 2:[2] -> 42 - 3:[3] -> 42 - 4:[4-9] -> 42 - 5:[A-Za-z] -> 7 - -DFA state 42 - Forward route : (from state 41) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 43 - 1:[1] -> 43 - 2:[2] -> 43 - 3:[3] -> 43 - 4:[4-9] -> 43 - 5:[A-Za-z] -> 7 - NFA exit tags applying : - DS_YYMMDD - Attributes for <(DEFAULT)> : DS_YYMMDD - -DFA state 43 - Forward route : (from state 42) - (START)->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->0:[0]->(HERE) - Transitions : - 0:[0] -> 43 - 1:[1] -> 43 - 2:[2] -> 43 - 3:[3] -> 43 - 4:[4-9] -> 43 - 5:[A-Za-z] -> 7 - Use state 42 as basis (0 fixups) - - -Entry states in DFA: -Entry <(ONLY ENTRY)> : 0 diff --git a/src/mairix/db.c b/src/mairix/db.c @@ -1,1297 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002,2003,2004,2005,2006,2007,2009 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -/* Handle complete database */ - -#include "mairix.h" -#include "reader.h" -#include <ctype.h> -#include <assert.h> -#include <sys/time.h> -#include <unistd.h> - -struct sortable_token {/*{{{*/ - char *text; - int index; -}; -/*}}}*/ -static int compare_sortable_tokens(const void *a, const void *b)/*{{{*/ -{ - const struct sortable_token *aa = (const struct sortable_token *) a; - const struct sortable_token *bb = (const struct sortable_token *) b; - int foo; - foo = strcmp(aa->text, bb->text); - if (foo) { - return foo; - } else { - if (aa->index < bb->index) return -1; - else if (aa->index > bb->index) return +1; - else return 0; - } -} -/*}}}*/ -static void check_toktable_enc_integrity(int n_msgs, struct toktable *table)/*{{{*/ -{ - /* FIXME : Check reachability of tokens that are displaced from their natural - * hash bucket (if deletions have occurred during purge). */ - - int idx, incr; - int i, k; - unsigned char *j, *last_char; - int broken_chains = 0; - struct sortable_token *sort_list; - int any_duplicates; - - for (i=0; i<table->size; i++) { - struct token *tok = table->tokens[i]; - if (tok) { - idx = 0; - incr = 0; - last_char = tok->match0.msginfo + tok->match0.n; - for (j = tok->match0.msginfo; j < last_char; ) { - incr = read_increment(&j); - idx += incr; - } - if (idx != tok->match0.highest) { - fprintf(stderr, "broken encoding chain for token <%s>, highest=%ld\n", tok->text, tok->match0.highest); - fflush(stderr); - broken_chains = 1; - } - if (idx >= n_msgs) { - fprintf(stderr, "end of chain higher than number of message paths (%d) for token <%s>\n", n_msgs, tok->text); - fflush(stderr); - broken_chains = 1; - } - } - } - - assert(!broken_chains); - - /* Check there are no duplicated tokens in the table. */ - sort_list = new_array(struct sortable_token, table->n); - k = 0; - for (i=0; i<table->size; i++) { - struct token *tok = table->tokens[i]; - if (tok) { - sort_list[k].text = new_string(tok->text); - sort_list[k].index = i; - k++; - } - } - assert(k == table->n); - - qsort(sort_list, table->n, sizeof(struct sortable_token), compare_sortable_tokens); - /* Check for uniqueness of neighbouring token texts */ - any_duplicates = 0; - for (i=0; i<(table->n - 1); i++) { - if (!strcmp(sort_list[i].text, sort_list[i+1].text)) { - fprintf(stderr, "Token table contains duplicated token %s at indices %d and %d\n", - sort_list[i].text, sort_list[i].index, sort_list[i+1].index); - any_duplicates = 1; - } - } - - /* release */ - for (i=0; i<table->n; i++) { - free(sort_list[i].text); - } - free(sort_list); - - if (any_duplicates) { - fprintf(stderr, "Token table contained duplicate entries, aborting\n"); - assert(0); - } -} -/*}}}*/ -static int compare_strings(const void *a, const void *b)/*{{{*/ -{ - const char **aa = (const char **) a; - const char **bb = (const char **) b; - return strcmp(*aa, *bb); -} -/*}}}*/ -static void check_message_path_integrity(struct database *db)/*{{{*/ -{ - /* TODO : for now only checks integrity of non-mbox paths. */ - /* Check there are no duplicates */ - int i; - int n; - int has_duplicate = 0; - - char **paths; - paths = new_array(char *, db->n_msgs); - for (i=0, n=0; i<db->n_msgs; i++) { - switch (db->type[i]) { - case MTY_DEAD: - case MTY_MBOX: - break; - case MTY_FILE: - paths[n++] = db->msgs[i].src.mpf.path; - break; - } - } - - qsort(paths, n, sizeof(char *), compare_strings); - - for (i=1; i<n; i++) { - if (!strcmp(paths[i-1], paths[i])) { - fprintf(stderr, "Path <%s> repeated\n", paths[i]); - has_duplicate = 1; - } - } - - fflush(stderr); - assert(!has_duplicate); - - free(paths); - return; -} -/*}}}*/ -void check_database_integrity(struct database *db)/*{{{*/ -{ - if (verbose) fprintf(stderr, "Checking message path integrity\n"); - check_message_path_integrity(db); - - /* Just check encoding chains for now */ - if (verbose) fprintf(stderr, "Checking to\n"); - check_toktable_enc_integrity(db->n_msgs, db->to); - if (verbose) fprintf(stderr, "Checking cc\n"); - check_toktable_enc_integrity(db->n_msgs, db->cc); - if (verbose) fprintf(stderr, "Checking from\n"); - check_toktable_enc_integrity(db->n_msgs, db->from); - if (verbose) fprintf(stderr, "Checking subject\n"); - 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(unsigned int hash_key)/*{{{*/ -{ - struct database *result = new(struct database); - struct timeval tv; - pid_t pid; - - result->to = new_toktable(); - result->cc = new_toktable(); - result->from = new_toktable(); - result->subject = new_toktable(); - result->body = new_toktable(); - result->attachment_name = new_toktable(); - - result->msg_ids = new_toktable2(); - - if ( hash_key == CREATE_RANDOM_DATABASE_HASH ) - { - gettimeofday(&tv, NULL); - pid = getpid(); - hash_key = tv.tv_sec ^ (pid ^ (tv.tv_usec << 15)); - } - result->hash_key = hash_key; - - result->msgs = NULL; - result->type = NULL; - result->n_msgs = 0; - result->max_msgs = 0; - - result->mboxen = NULL; - result->n_mboxen = 0; - result->max_mboxen = 0; - - return result; -} -/*}}}*/ -void free_database(struct database *db)/*{{{*/ -{ - int i; - - free_toktable(db->to); - free_toktable(db->cc); - 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) { - for (i=0; i<db->n_msgs; i++) { - switch (db->type[i]) { - case MTY_DEAD: - break; - case MTY_MBOX: - break; - case MTY_FILE: - assert(db->msgs[i].src.mpf.path); - free(db->msgs[i].src.mpf.path); - break; - } - } - free(db->msgs); - free(db->type); - } - - free(db); -} -/*}}}*/ - -static int get_max (int a, int b) {/*{{{*/ - return (a > b) ? a : b; -} -/*}}}*/ -static void import_toktable(char *data, unsigned int hash_key, int n_msgs, struct toktable_db *in, struct toktable *out)/*{{{*/ -{ - int n, size, i; - - n = in->n; - size = 1; - while (size < n) size <<= 1; - size <<= 1; /* safe hash table size */ - - out->size = size; - out->mask = size - 1; - out->n = n; - out->tokens = new_array(struct token *, size); - memset(out->tokens, 0, size * sizeof(struct token *)); - out->hwm = (n + size) >> 1; - - for (i=0; i<n; i++) { - unsigned int hash, index; - char *text; - unsigned char *enc; - int enc_len; - struct token *nt; - int enc_hi; - int idx, incr; - unsigned char *j; - - /* Recover enc_len and enc_hi from the data */ - enc = (unsigned char *) data + in->enc_offsets[i]; - idx = 0; - for (j = enc; *j != 0xff; ) { - incr = read_increment(&j); - idx += incr; - } - enc_len = j - enc; - enc_hi = idx; - - text = data + in->tok_offsets[i]; - hash = hashfn((unsigned char *) text, strlen(text), hash_key); - - nt = new(struct token); - nt->hashval = hash; - nt->text = new_string(text); - /* Allow a bit of headroom for adding more entries later */ - nt->match0.max = get_max(16, enc_len + (enc_len >> 1)); - nt->match0.n = enc_len; - nt->match0.highest = enc_hi; - assert(nt->match0.highest < n_msgs); - nt->match0.msginfo = new_array(unsigned char, nt->match0.max); - memcpy(nt->match0.msginfo, enc, nt->match0.n); - - index = hash & out->mask; - while (out->tokens[index]) { - /* Audit to look for corrupt database with multiple entries for the same - * string. */ - if (!strcmp(nt->text, out->tokens[index]->text)) { - fprintf(stderr, "\n!!! Corrupt token table found in database, token <%s> duplicated, aborting\n", - nt->text); - fprintf(stderr, " Delete the database file and rebuild from scratch as a workaround\n"); - /* No point going on - need to find out why the database got corrupted - * in the 1st place. Workaround for user - rebuild database from - * scratch by deleting it then rerunning. */ - unlock_and_exit(1); - } - ++index; - index &= out->mask; - } - - out->tokens[index] = nt; - } -} -/*}}}*/ -static void import_toktable2(char *data, unsigned int hash_key, int n_msgs, struct toktable2_db *in, struct toktable2 *out)/*{{{*/ -{ - int n, size, i; - - n = in->n; - size = 1; - while (size < n) size <<= 1; - size <<= 1; /* safe hash table size */ - - out->size = size; - out->mask = size - 1; - out->n = n; - out->tokens = new_array(struct token2 *, size); - memset(out->tokens, 0, size * sizeof(struct token *)); - out->hwm = (n + size) >> 1; - - for (i=0; i<n; i++) { - unsigned int hash, index; - char *text; - struct token2 *nt; - unsigned char *enc0, *enc1; - int enc0_len, enc1_len; - int enc0_hi, enc1_hi; - int idx, incr; - unsigned char *j; - -/*{{{ do enc0*/ - enc0 = (unsigned char *) data + in->enc0_offsets[i]; - idx = 0; - for (j = enc0; *j != 0xff; ) { - incr = read_increment(&j); - idx += incr; - } - enc0_len = j - enc0; - enc0_hi = idx; -/*}}}*/ -/*{{{ do enc1*/ - enc1 = (unsigned char *) data + in->enc1_offsets[i]; - idx = 0; - for (j = enc1; *j != 0xff; ) { - incr = read_increment(&j); - idx += incr; - } - enc1_len = j - enc1; - enc1_hi = idx; -/*}}}*/ - - text = data + in->tok_offsets[i]; - hash = hashfn((unsigned char *) text, strlen(text), hash_key); - - nt = new(struct token2); - nt->hashval = hash; - nt->text = new_string(text); - /* Allow a bit of headroom for adding more entries later */ - /*{{{ set up match0 chain */ - nt->match0.max = get_max(16, enc0_len + (enc0_len >> 1)); - nt->match0.n = enc0_len; - nt->match0.highest = enc0_hi; - assert(nt->match0.highest < n_msgs); - nt->match0.msginfo = new_array(unsigned char, nt->match0.max); - memcpy(nt->match0.msginfo, enc0, nt->match0.n); - /*}}}*/ - /*{{{ set up match1 chain */ - nt->match1.max = get_max(16, enc1_len + (enc1_len >> 1)); - nt->match1.n = enc1_len; - nt->match1.highest = enc1_hi; - assert(nt->match1.highest < n_msgs); - nt->match1.msginfo = new_array(unsigned char, nt->match1.max); - memcpy(nt->match1.msginfo, enc1, nt->match1.n); - /*}}}*/ - - index = hash & out->mask; - while (out->tokens[index]) { - ++index; - index &= out->mask; - } - - out->tokens[index] = nt; - } -} -/*}}}*/ -struct database *new_database_from_file(char *db_filename, int do_integrity_checks)/*{{{*/ -{ - /* Read existing database from file for doing incremental update */ - struct database *result; - struct read_db *input; - int i, n, N; - - result = new_database( CREATE_RANDOM_DATABASE_HASH ); - input = open_db(db_filename); - if (!input) { - /* Nothing to initialise */ - if (verbose) printf("Database file was empty, creating a new database\n"); - return result; - } - - /* Build pathname information */ - n = result->n_msgs = input->n_msgs; - result->max_msgs = input->n_msgs; /* let it be extended as-and-when */ - result->msgs = new_array(struct msgpath, n); - result->type = new_array(enum message_type, n); - - result->hash_key = input->hash_key; - - /* Set up mbox structures */ - N = result->n_mboxen = result->max_mboxen = input->n_mboxen; - result->mboxen = N ? (new_array(struct mbox, N)) : NULL; - for (i=0; i<N; i++) { - int nn; - if (input->mbox_paths_table[i]) { - result->mboxen[i].path = new_string(input->data + input->mbox_paths_table[i]); - } else { - /* mbox is dead. */ - result->mboxen[i].path = NULL; - } - result->mboxen[i].file_mtime = input->mbox_mtime_table[i]; - result->mboxen[i].file_size = input->mbox_size_table[i]; - nn = result->mboxen[i].n_msgs = input->mbox_entries_table[i]; - result->mboxen[i].max_msgs = nn; - result->mboxen[i].start = new_array(off_t, nn); - result->mboxen[i].len = new_array(size_t, nn); - result->mboxen[i].check_all = new_array(checksum_t, nn); - /* Copy the entire checksum table in one go. */ - memcpy(result->mboxen[i].check_all, - input->data + input->mbox_checksum_table[i], - nn * sizeof(checksum_t)); - result->mboxen[i].n_so_far = 0; - } - - for (i=0; i<n; i++) { - switch (rd_msg_type(input, i)) { - case DB_MSG_DEAD: - result->type[i] = MTY_DEAD; - break; - case DB_MSG_FILE: - result->type[i] = MTY_FILE; - result->msgs[i].src.mpf.path = new_string(input->data + input->path_offsets[i]); - result->msgs[i].src.mpf.mtime = input->mtime_table[i]; - result->msgs[i].src.mpf.size = input->size_table[i]; - break; - case DB_MSG_MBOX: - { - unsigned int mbi, msgi; - int n; - struct mbox *mb; - result->type[i] = MTY_MBOX; - decode_mbox_indices(input->path_offsets[i], &mbi, &msgi); - result->msgs[i].src.mbox.file_index = mbi; - mb = &result->mboxen[mbi]; - assert(mb->n_so_far == msgi); - n = mb->n_so_far; - result->msgs[i].src.mbox.msg_index = n; - mb->start[n] = input->mtime_table[i]; - mb->len[n] = input->size_table[i]; - ++mb->n_so_far; - } - - 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]; - } - - import_toktable(input->data, input->hash_key, result->n_msgs, &input->to, result->to); - import_toktable(input->data, input->hash_key, result->n_msgs, &input->cc, result->cc); - 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->attachment_name); - import_toktable2(input->data, input->hash_key, result->n_msgs, &input->msg_ids, result->msg_ids); - - close_db(input); - - if (do_integrity_checks) { - check_database_integrity(result); - } - - return result; -} -/*}}}*/ - -static void add_angled_terms(int file_index, unsigned int hash_key, struct toktable2 *table, int add_to_chain1, char *s)/*{{{*/ -{ - char *left, *right; - - if (s) { - left = strchr(s, '<'); - while (left) { - right = strchr(left, '>'); - if (right) { - *right = '\0'; - add_token2_in_file(file_index, hash_key, left+1, table, add_to_chain1); - *right = '>'; /* restore */ - } else { - break; - } - left = strchr(right, '<'); - } - } -} -/*}}}*/ - -/* Macro for what characters can make up token strings. - - The following characters have special meanings: - 0x2b + - 0x2d - - 0x2e . - 0x40 @ - 0x5f _ - - since they can occur within email addresses and message IDs when considered - as a whole rather than as individual words. Underscore (0x5f) is considered - a word-character always too. - - */ -static unsigned char special_table[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00-0f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10-1f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 2, 0, /* 20-2f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30-3f */ - 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40-4f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, /* 50-5f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60-6f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70-7f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80-8f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90-9f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a0-af */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b0-bf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c0-cf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d0-df */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e0-ef */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* f0-ff */ -}; - -#if 0 -#define CHAR_VALID(x,mask) (isalnum((unsigned char) x) || (special_table[(unsigned int)(unsigned char) x] & mask)) -#endif -static inline int char_valid_p(char x, unsigned int mask)/*{{{*/ -{ - unsigned char xx = (unsigned char) x; - if (isalnum(xx)) return 1; - else if (special_table[(unsigned int) xx] & mask) return 1; - else return 0; -} -/*}}}*/ -static void tokenise_string(int file_index, unsigned int hash_key, struct toktable *table, char *data, int match_mask)/*{{{*/ -{ - char *ss, *es, old_es; - ss = data; - for (;;) { - while (*ss && !char_valid_p(*ss,match_mask)) ss++; - if (!*ss) break; - es = ss + 1; - while (*es && char_valid_p(*es,match_mask)) es++; - - /* deal with token [ss,es) */ - old_es = *es; - *es = '\0'; - /* FIXME: Ought to do this by passing start and length - clean up later */ - add_token_in_file(file_index, hash_key, ss, table); - *es = old_es; - - if (!*es) break; - ss = es; - } -} -/*}}}*/ -static void tokenise_html_string(int file_index, unsigned int hash_key, struct toktable *table, char *data)/*{{{*/ -{ - char *ss, *es, old_es; - - /* FIXME : Probably want to rewrite this as an explicit FSM */ - - ss = data; - for (;;) { - /* Assume < and > are never valid token characters ! */ - while (*ss && !char_valid_p(*ss, 1)) { - if (*ss++ == '<') { - /* Skip over HTML tag */ - while (*ss && (*ss != '>')) ss++; - } - } - if (!*ss) break; - - es = ss + 1; - while (*es && char_valid_p(*es, 1)) es++; - - /* deal with token [ss,es) */ - old_es = *es; - *es = '\0'; - /* FIXME: Ought to do this by passing start and length - clean up later */ - add_token_in_file(file_index, hash_key, ss, table); - *es = old_es; - - if (!*es) break; - ss = es; - } -} -/*}}}*/ -void tokenise_message(int file_index, struct database *db, struct rfc822 *msg)/*{{{*/ -{ - struct attachment *a; - - /* Match on whole addresses in these headers as well as the individual words */ - if (msg->hdrs.to) { - tokenise_string(file_index, db->hash_key, db->to, msg->hdrs.to, 1); - tokenise_string(file_index, db->hash_key, db->to, msg->hdrs.to, 2); - } - if (msg->hdrs.cc) { - tokenise_string(file_index, db->hash_key, db->cc, msg->hdrs.cc, 1); - tokenise_string(file_index, db->hash_key, db->cc, msg->hdrs.cc, 2); - } - if (msg->hdrs.from) { - tokenise_string(file_index, db->hash_key, db->from, msg->hdrs.from, 1); - tokenise_string(file_index, db->hash_key, db->from, msg->hdrs.from, 2); - } - if (msg->hdrs.subject) tokenise_string(file_index, db->hash_key, db->subject, msg->hdrs.subject, 1); - - for (a=msg->atts.next; a!=&msg->atts; a=a->next) { - switch (a->ct) { - case CT_TEXT_PLAIN: - tokenise_string(file_index, db->hash_key, db->body, a->data.normal.bytes, 1); - break; - case CT_TEXT_HTML: - tokenise_html_string(file_index, db->hash_key, db->body, a->data.normal.bytes); - break; - case CT_MESSAGE_RFC822: - /* Just recurse for now - maybe we should have separate token tables - * for tokens occurring in embedded messages? */ - - if (a->data.rfc822) { - tokenise_message(file_index, db, a->data.rfc822); - } - break; - default: - /* Don't do anything - unknown text format or some nasty binary stuff. - * In future, we could have all kinds of 'plug-ins' here, e.g. - * something that can parse PDF to get the basic text strings out of - * the pages? */ - break; - } - - if (a->filename) { - add_token_in_file(file_index, db->hash_key, a->filename, db->attachment_name); - } - - } - - /* Deal with threading information */ - add_angled_terms(file_index, db->hash_key, db->msg_ids, 1, msg->hdrs.message_id); - add_angled_terms(file_index, db->hash_key, db->msg_ids, 0, msg->hdrs.in_reply_to); - 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; - for (i=start_at; i<db->n_msgs; i++) { - struct rfc822 *msg = NULL; - int len = strlen(db->msgs[i].src.mpf.path); - - if (len > 10 && !strcmp(db->msgs[i].src.mpf.path + len - 11, "/.gitignore")) - continue; - - switch (db->type[i]) { - case MTY_DEAD: - assert(0); - break; - case MTY_MBOX: - assert(0); /* Should never get here - mbox messages are scanned elsewhere. */ - break; - case MTY_FILE: - if (verbose) fprintf(stderr, "Scanning <%s>\n", db->msgs[i].src.mpf.path); - msg = make_rfc822(db->msgs[i].src.mpf.path); - break; - } - if(msg) - { - db->msgs[i].date = msg->hdrs.date; - scan_maildir_flags(&db->msgs[i]); - tokenise_message(i, db, msg); - free_rfc822(msg); - } - else - fprintf(stderr, "Skipping %s (could not parse message)\n", db->msgs[i].src.mpf.path); - } -} -/*}}}*/ - -static inline void set_bit(unsigned long *x, int n)/*{{{*/ -{ - int set; - unsigned long mask; - set = (n >> 5); - mask = (1UL << (n & 31)); - x[set] |= mask; -} -/*}}}*/ -static inline int isset_bit(unsigned long *x, int n)/*{{{*/ -{ - int set; - unsigned long mask; - set = (n >> 5); - mask = (1UL << (n & 31)); - return (x[set] & mask) ? 1 : 0; -} -/*}}}*/ -static int find_base(int *table, int index) {/*{{{*/ - int a = index; - - /* TODO : make this compress the path lengths down to the base entry */ - while (table[a] != a) { - a = table[a]; - } - return a; -} -/*}}}*/ -static void find_threading(struct database *db)/*{{{*/ -{ - - /* ix is a table mapping path array index to the lowest path array index that - * is known to share at least one message ID in its hdrs somewhere (i.e. they - * must be in the same thread) */ - int *ix; - - int i, m, np, nm, sm; - int next_tid; - - np = db->n_msgs; - nm = db->msg_ids->n; - sm = db->msg_ids->size; - - ix = new_array(int, np); - for (i=0; i<np; i++) { - ix[i] = i; /* default - every message in a thread of its own */ - } - - for (m=0; m<sm; m++) { - struct token2 *tok = db->msg_ids->tokens[m]; - if (tok) { - unsigned char *j = tok->match0.msginfo; - unsigned char *last_char = j + tok->match0.n; - int cur = 0, incr, first=1; - int new_base=-1, old_base; - while (j < last_char) { - incr = read_increment(&j); - cur += incr; - if (first) { - new_base = find_base(ix, cur); - first = 0; - } else { - old_base = find_base(ix, cur); - if (old_base < new_base) { - ix[new_base] = old_base; - new_base = old_base; - } else if (old_base > new_base) { - assert(new_base != -1); - ix[old_base] = new_base; - } - } - } - } - } - - /* Now make each entry point directly to its base */ - for (i=0; i<np; i++) { - if (ix[i] != i) { - /* Sure to work as we're going up from the bottom */ - ix[i] = ix[ix[i]]; - } - } - - /* Now allocate contiguous thread group numbers */ - next_tid = 0; - for (i=0; i<np; i++) { - if (ix[i] == i) { - db->msgs[i].tid = next_tid++; - } else { - db->msgs[i].tid = db->msgs[ix[i]].tid; - } - } - - free(ix); - return; -} -/*}}}*/ -static int lookup_msgpath(struct msgpath *sorted_paths, int n_msgs, char *key)/*{{{*/ -{ - /* Implement bisection search */ - int l, h, m, r; - l = 0, h = n_msgs; - m = -1; - while (h > l) { - m = (h + l) >> 1; - /* Should only get called on 'file' type messages - TBC */ - r = strcmp(sorted_paths[m].src.mpf.path, key); - if (r == 0) break; - if (l == m) return -1; - if (r > 0) h = m; - else l = m; - } - return m; -} -/*}}}*/ -void maybe_grow_message_arrays(struct database *db)/*{{{*/ -{ - if (db->n_msgs == db->max_msgs) { - if (db->max_msgs <= 128) { - db->max_msgs = 256; - } else { - db->max_msgs += (db->max_msgs >> 1); - } - db->msgs = grow_array(struct msgpath, db->max_msgs, db->msgs); - db->type = grow_array(enum message_type, db->max_msgs, db->type); - } -} -/*}}}*/ -static void add_msg_path(struct database *db, char *path, time_t mtime, size_t message_size)/*{{{*/ -{ - maybe_grow_message_arrays(db); - db->type[db->n_msgs] = MTY_FILE; - db->msgs[db->n_msgs].src.mpf.path = new_string(path); - db->msgs[db->n_msgs].src.mpf.mtime = mtime; - db->msgs[db->n_msgs].src.mpf.size = message_size; - ++db->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. - * If the date differs, or the file no longer exist, the existing database - * entry for that file is nulled. (These are only recovered if the database - * is actively compressed.) If the date differed, a new entry for the file - * is put at the end of the list. Similarly, any new file goes at the end. - * These new entries are all rescanned to find tokens and add them to the - * database. */ - - char *file_in_db, *file_in_new_list; - 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); - bzero(file_in_db, n_msgs); - bzero(file_in_new_list, db->n_msgs); - - n_already_dead = 0; - n_newly_pruned = 0; - - for (i=0; i<db->n_msgs; i++) { - 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) { - 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 { - /* 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: - /* Nothing to do on this pass. */ - break; - case MTY_DEAD: - break; - } - } - - /* Add new entries to database */ - new_entries_start_at = db->n_msgs; - - for (i=0; i<db->n_msgs; i++) { - /* Weed dead entries */ - switch (db->type[i]) { - case MTY_FILE: - if (!file_in_new_list[i]) { - free(db->msgs[i].src.mpf.path); - db->msgs[i].src.mpf.path = NULL; - db->type[i] = MTY_DEAD; - ++n_newly_pruned; - } - break; - case MTY_MBOX: - { - int msg_index, file_index, number_valid; - int mbox_valid; - msg_index = db->msgs[i].src.mbox.msg_index; - file_index = db->msgs[i].src.mbox.file_index; - assert (file_index < db->n_mboxen); - mbox_valid = (db->mboxen[file_index].path) ? 1 : 0; - number_valid = db->mboxen[file_index].n_old_msgs_valid; - if (!mbox_valid || (msg_index >= number_valid)) { - db->type[i] = MTY_DEAD; - ++n_newly_pruned; - } - } - break; - case MTY_DEAD: - /* already dead */ - ++n_already_dead; - break; - } - } - - if (verbose) { - fprintf(stderr, "%d newly dead messages, %d messages now dead in total\n", n_newly_pruned, n_newly_pruned+n_already_dead); - } - - 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. */ - 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); - } - } - } - - if (any_new) { - scan_new_messages(db, new_entries_start_at); - } - - /* Add newly found mbox messages. */ - any_new |= add_mbox_messages(db); - - if (any_new) { - find_threading(db); - } else { - if (verbose) fprintf(stderr, "No new messages found\n"); - } - - free(file_in_db); - free(file_in_new_list); - - return any_new || (n_newly_pruned > 0); -} -/*}}}*/ -static void recode_encoding(struct matches *m, int *new_idx)/*{{{*/ -{ - unsigned char *new_enc, *old_enc; - unsigned char *j, *last_char; - int incr, idx, n_idx; - - old_enc = m->msginfo; - j = old_enc; - last_char = old_enc + m->n; - - new_enc = new_array(unsigned char, m->max); /* Probably not bigger than this. */ - m->n = 0; - m->highest = 0; - m->msginfo = new_enc; - idx = 0; - - while (j < last_char) { - incr = read_increment(&j); - idx += incr; - n_idx = new_idx[idx]; - if (n_idx >= 0) { - check_and_enlarge_encoding(m); - insert_index_on_encoding(m, n_idx); - } - } - free(old_enc); -} -/*}}}*/ -static void recode_toktable(struct toktable *tbl, int *new_idx)/*{{{*/ -{ - /* Re-encode the vectors according to the new path indices */ - int i; - int any_dead = 0; - int any_moved, pass; - - for (i=0; i<tbl->size; i++) { - struct token *tok = tbl->tokens[i]; - if (tok) { - recode_encoding(&tok->match0, new_idx); - if (tok->match0.n == 0) { - /* Delete this token. Gotcha - there may be tokens further on in the - * array that didn't get their natural hash bucket due to collisions. - * Need to shuffle such tokens up to guarantee that the buckets between - * the natural one and the one where they are now are all occupied, to - * prevent their lookups failing. */ - -#if 0 - fprintf(stderr, "Token <%s> (bucket %d) no longer has files containing it, deleting\n", tok->text, i); -#endif - free_token(tok); - tbl->tokens[i] = NULL; - --tbl->n; /* Maintain number in use counter */ - any_dead = 1; - } - - } - } - - - if (any_dead) { - /* Now close gaps. This has to be done in a second pass, otherwise we get a - * problem with moving entries that need deleting back before the current - scan point. */ - - pass = 1; - for (;;) { - int i; - - if (verbose) { - fprintf(stderr, "Pass %d\n", pass); - } - - any_moved = 0; - - for (i=0; i<tbl->size; i++) { - if (tbl->tokens[i]) { - int nat_bucket_i; - nat_bucket_i = tbl->tokens[i]->hashval & tbl->mask; - if (nat_bucket_i != i) { - /* Find earliest bucket that we could move i to */ - int j = nat_bucket_i; - while (j != i) { - if (!tbl->tokens[j]) { - /* put it here */ -#if 0 - fprintf(stderr, "Moved <%s> from bucket %d to %d (natural bucket %d)\n", tbl->tokens[i]->text, i, j, nat_bucket_i); -#endif - tbl->tokens[j] = tbl->tokens[i]; - tbl->tokens[i] = NULL; - any_moved = 1; - break; - } else { - j++; - j &= tbl->mask; - } - } - if (tbl->tokens[i]) { -#if 0 - fprintf(stderr, "NOT moved <%s> from bucket %d (natural bucket %d)\n", tbl->tokens[i]->text, i, nat_bucket_i); -#endif - } - } - } - } - - if (!any_moved) break; - pass++; - } - } -} -/*}}}*/ -static void recode_toktable2(struct toktable2 *tbl, int *new_idx)/*{{{*/ -{ - /* Re-encode the vectors according to the new path indices */ - int i; - int any_dead = 0; - int any_moved, pass; - - for (i=0; i<tbl->size; i++) { - struct token2 *tok = tbl->tokens[i]; - if (tok) { - recode_encoding(&tok->match0, new_idx); - recode_encoding(&tok->match1, new_idx); - if ((tok->match0.n == 0) && (tok->match1.n == 0)) { - /* Delete this token. Gotcha - there may be tokens further on in the - * array that didn't get their natural hash bucket due to collisions. - * Need to shuffle such tokens up to guarantee that the buckets between - * the natural one and the one where they are now are all occupied, to - * prevent their lookups failing. */ - -#if 0 - fprintf(stderr, "Token <%s> (bucket %d) no longer has files containing it, deleting\n", tok->text, i); -#endif - free_token2(tok); - tbl->tokens[i] = NULL; - --tbl->n; /* Maintain number in use counter */ - any_dead = 1; - } - } - } - - if (any_dead) { - /* Now close gaps. This has to be done in a second pass, otherwise we get a - * problem with moving entries that need deleting back before the current - scan point. */ - - pass = 1; - for (;;) { - int i; - - if (verbose) { - fprintf(stderr, "Pass %d\n", pass); - } - - any_moved = 0; - - for (i=0; i<tbl->size; i++) { - if (tbl->tokens[i]) { - int nat_bucket_i; - nat_bucket_i = tbl->tokens[i]->hashval & tbl->mask; - if (nat_bucket_i != i) { - /* Find earliest bucket that we could move i to */ - int j = nat_bucket_i; - while (j != i) { - if (!tbl->tokens[j]) { - /* put it here */ -#if 0 - fprintf(stderr, "Moved <%s> from bucket %d to %d (natural bucket %d)\n", tbl->tokens[i]->text, i, j, nat_bucket_i); -#endif - tbl->tokens[j] = tbl->tokens[i]; - tbl->tokens[i] = NULL; - any_moved = 1; - break; - } else { - j++; - j &= tbl->mask; - } - } - if (tbl->tokens[i]) { -#if 0 - fprintf(stderr, "NOT moved <%s> from bucket %d (natural bucket %d)\n", tbl->tokens[i]->text, i, nat_bucket_i); -#endif - } - } - } - } - - if (!any_moved) break; - pass++; - } - } -} -/*}}}*/ -int cull_dead_messages(struct database *db, int do_integrity_checks)/*{{{*/ -{ - /* Return true if any culled */ - - int *new_idx, i, j, n_old; - int any_culled = 0; - - /* Check db is OK before we start on this. (Check afterwards is done in the - * writer.c code.) */ - if (do_integrity_checks) { - check_database_integrity(db); - } - - if (verbose) { - fprintf(stderr, "Culling dead messages\n"); - } - - n_old = db->n_msgs; - - new_idx = new_array(int, n_old); - for (i=0, j=0; i<n_old; i++) { - switch (db->type[i]) { - case MTY_FILE: - case MTY_MBOX: - new_idx[i] = j++; - break; - case MTY_DEAD: - new_idx[i] = -1; - any_culled = 1; - break; - } - } - - recode_toktable(db->to, new_idx); - recode_toktable(db->cc, new_idx); - 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 */ - for (i=0, j=0; i<n_old; i++) { - switch (db->type[i]) { - case MTY_DEAD: - break; - case MTY_FILE: - case MTY_MBOX: - if (i > j) { - db->msgs[j] = db->msgs[i]; - db->type[j] = db->type[i]; - } - j++; - break; - } - } - db->n_msgs = j; - - free(new_idx); - - /* .. and cull dead mboxen */ - cull_dead_mboxen(db); - - return any_culled; -} -/*}}}*/ diff --git a/src/mairix/dfasyn/COPYING b/src/mairix/dfasyn/COPYING @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/src/mairix/dfasyn/INSTALL b/src/mairix/dfasyn/INSTALL @@ -1,19 +0,0 @@ -There is no real configure mechanism (yet). - -To build the program - - make - -To install the program (perhaps as root) - - make prefix=/usr/local install - -or as yourself you might do - - make prefix=$HOME install - -or if your distribution puts manpages in /usr/share/man, you might do - - make prefix=/usr/local mandir=/usr/share/man install - -# vim:et:sw=4 diff --git a/src/mairix/dfasyn/Makefile b/src/mairix/dfasyn/Makefile @@ -1,62 +0,0 @@ -# Makefile for NFA->DFA conversion utility -# -# Copyright (C) Richard P. Curnow 2000-2001,2003,2005,2006,2007 -# 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., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# - -CC=gcc -#CFLAGS=-g -Wall -#CFLAGS=-O2 -pg -CFLAGS=-Wall -prefix?=/usr/local -bindir=$(prefix)/bin -mandir?=$(prefix)/man -man1dir=$(mandir)/man1 -man5dir=$(mandir)/man5 - -OBJ = dfasyn.o parse.o scan.o \ - tokens.o abbrevs.o charclass.o \ - stimulus.o \ - blocks.o states.o \ - n2d.o expr.o evaluator.o \ - tabcompr.o compdfa.o - -all : dfasyn - -install : all - [ -d $(bindir) ] || mkdir -p $(bindir) - [ -d $(man1dir) ] || mkdir -p $(man1dir) - [ -d $(man5dir) ] || mkdir -p $(man5dir) - cp dfasyn $(bindir) - cp dfasyn.1 $(man1dir) - cp dfasyn.5 $(man5dir) - -dfasyn : $(OBJ) - $(CC) $(CFLAGS) -o dfasyn $(OBJ) - -parse.c parse.h : parse.y - bison -v -d -o parse.c parse.y - -parse.o : parse.c dfasyn.h - -scan.c : scan.l - flex -t -s scan.l > scan.c - -scan.o : scan.c parse.h dfasyn.h - -$(OBJ) : dfasyn.h - -clean: - rm -f dfasyn *.o scan.c parse.c parse.h parse.output - diff --git a/src/mairix/dfasyn/NEWS b/src/mairix/dfasyn/NEWS @@ -1,5 +0,0 @@ -New in version 0.2 -================== - -* Added README and NEWS files - diff --git a/src/mairix/dfasyn/README b/src/mairix/dfasyn/README @@ -1,8 +0,0 @@ -dfasyn is a tool for constructing state machines. The input language allows a -lot of generality. For example, it allows repeated elements to be specified -where the items have constraints between the end of one and the start of the -next. (I could not find a way to define such an automaton in the lex/flex -input language, which prompted the writing of the tool.) Currently, you must -do a fair amount of work yourself to build a parser around the resulting state -machine. - diff --git a/src/mairix/dfasyn/abbrevs.c b/src/mairix/dfasyn/abbrevs.c @@ -1,67 +0,0 @@ -/*************************************** - Handle state-related stuff - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2000-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "dfasyn.h" - -static struct Abbrev *abbrevtable=NULL; -static int nabbrevs = 0; -static int maxabbrevs = 0; - -static void grow_abbrevs(void)/*{{{*/ -{ - maxabbrevs += 32; - abbrevtable = resize_array(struct Abbrev, abbrevtable, maxabbrevs); -} -/*}}}*/ -struct Abbrev * create_abbrev(const char *name, struct StimulusList *stimuli)/*{{{*/ -{ - struct Abbrev *result; - if (nabbrevs == maxabbrevs) { - grow_abbrevs(); - } - result = abbrevtable + (nabbrevs++); - result->lhs = new_string(name); - result->stimuli = stimuli; - return result; -} -/*}}}*/ -struct Abbrev * lookup_abbrev(char *name)/*{{{*/ -{ - int found = -1; - int i; - struct Abbrev *result = NULL; - /* Scan table in reverse order. If a name has been redefined, - make sure the most recent definition is picked up. */ - for (i=nabbrevs-1; i>=0; i--) { - if (!strcmp(abbrevtable[i].lhs, name)) { - found = i; - result = abbrevtable + found; - break; - } - } - - return result; -} -/*}}}*/ - diff --git a/src/mairix/dfasyn/blocks.c b/src/mairix/dfasyn/blocks.c @@ -1,168 +0,0 @@ -/*************************************** - Handle blocks - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2000-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "dfasyn.h" - - -static Block **blocks = NULL; -static int nblocks = 0; -static int maxblocks = 0; - -/* ================================================================= */ - -static void grow_blocks(void)/*{{{*/ -{ - maxblocks += 32; - blocks = resize_array(Block*, blocks, maxblocks); -} -/*}}}*/ -static Block * create_block(char *name)/*{{{*/ -{ - Block *result; - int i; - - if (nblocks == maxblocks) { - grow_blocks(); - } - -#if 0 - /* Not especially useful to show this */ - if (verbose) { - fprintf(stderr, " %s", name); - } -#endif - - result = blocks[nblocks++] = new(Block); - result->name = new_string(name); - for (i=0; i<HASH_BUCKETS; i++) { - result->state_hash[i].states = NULL; - result->state_hash[i].nstates = 0; - result->state_hash[i].maxstates = 0; - } - result->states = NULL; - result->nstates = result->maxstates = 0; - result->eclo = NULL; - - result->subcount = 1; - result->subblockcount = 1; - return result; -} -/*}}}*/ -Block * lookup_block(char *name, int create)/*{{{*/ -{ - Block *found = NULL; - int i; - for (i=0; i<nblocks; i++) { - if (!strcmp(blocks[i]->name, name)) { - found = blocks[i]; - break; - } - } - - switch (create) { - case USE_OLD_MUST_EXIST: - if (!found) { - fprintf(stderr, "Could not find block '%s' to instantiate\n", name); - exit(1); - } - break; - case CREATE_MUST_NOT_EXIST: - if (found) { - fprintf(stderr, "Already have a block called '%s', cannot redefine\n", name); - exit(1); - } else { - found = create_block(name); - } - break; - case CREATE_OR_USE_OLD: - if (!found) { - found = create_block(name); - } - break; - } - - return found; -} -/*}}}*/ -/* ================================================================= */ -void instantiate_block(Block *curblock, char *block_name, char *instance_name)/*{{{*/ -{ - Block *master = lookup_block(block_name, USE_OLD_MUST_EXIST); - char namebuf[1024]; - int i; - for (i=0; i<master->nstates; i++) { - State *s = master->states[i]; - State *new_state; - TransList *tl; - Stringlist *sl, *ex; - - strcpy(namebuf, instance_name); - strcat(namebuf, "."); - strcat(namebuf, s->name); - - /* In perverse circumstances, we might already have a state called this */ - new_state = lookup_state(curblock, namebuf, CREATE_OR_USE_OLD); - - for (tl=s->transitions; tl; tl=tl->next) { - TransList *new_tl = new(TransList); - new_tl->type = tl->type; - /* Might cause some dangling ref problem later... */ - new_tl->x = tl->x; - strcpy(namebuf, instance_name); - strcat(namebuf, "."); - strcat(namebuf, tl->ds_name); - new_tl->ds_name = new_string(namebuf); - new_tl->ds_ref = NULL; - new_tl->next = new_state->transitions; - new_state->transitions = new_tl; - } - - /*{{{ Copy state tags */ - ex = NULL; - for (sl=s->tags; sl; sl=sl->next) { - Stringlist *new_sl = new(Stringlist); - new_sl->string = sl->string; - new_sl->next = ex; - ex = new_sl; - } - new_state->tags = ex; - /*}}}*/ - - /* **DON'T** COPY ENTRIES : these are deliberately dropped if they occur - * in a block that gets instantiated elsewhere. */ - - } -} -/*}}}*/ -/* ================================================================= */ -InlineBlock *create_inline_block(char *type, char *in, char *out)/*{{{*/ -{ - InlineBlock *result; - result = new(InlineBlock); - result->type = new_string(type); - result->in = new_string(in); - result->out = new_string(out); - return result; -} -/*}}}*/ diff --git a/src/mairix/dfasyn/charclass.c b/src/mairix/dfasyn/charclass.c @@ -1,364 +0,0 @@ -/*************************************** - Handle character classes - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2001-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "dfasyn.h" -#include <ctype.h> - -struct cc_list { - struct cc_list *next; - CharClass *cc; -}; - -static struct cc_list *cc_list = NULL; -static short mapping[256]; - -int n_charclasses; -static char *strings[256]; - -static void set_bit(unsigned long *bitmap, int entry)/*{{{*/ -{ - int i, j, mask; - i = (entry >> 5); - j = entry & 31; - mask = 1<<j; - bitmap[i] |= mask; -} -/*}}}*/ -static void clear_bit(unsigned long *bitmap, int entry)/*{{{*/ -{ - int i, j, mask; - i = (entry >> 5); - j = entry & 31; - mask = 1<<j; - bitmap[i] &= ~mask; -} -/*}}}*/ -int cc_test_bit(const unsigned long *bitmap, int entry)/*{{{*/ -{ - int i, j, mask; - i = (entry >> 5); - j = entry & 31; - mask = 1<<j; - return (bitmap[i] & mask) ? 1 : 0; -} -/*}}}*/ -CharClass *new_charclass(void)/*{{{*/ -{ - CharClass *result = new(CharClass); - result->is_used = 0; - memset(result->char_bitmap, 0, sizeof(result->char_bitmap)); - memset(result->group_bitmap, 0, sizeof(result->group_bitmap)); - return result; -} -/*}}}*/ -void free_charclass(CharClass *what)/*{{{*/ -{ - free(what); -} -/*}}}*/ -void add_charclass_to_list(CharClass *cc)/*{{{*/ -{ - /* Add the cc to the master list for later processing. */ - struct cc_list *elt = new(struct cc_list); - elt->next = cc_list; - elt->cc = cc; - cc_list = elt; -} -/*}}}*/ -void add_singleton_to_charclass(CharClass *towhat, char thechar)/*{{{*/ -{ - int x; - x = (int)(unsigned char) thechar; - set_bit(towhat->char_bitmap, x); -} -/*}}}*/ -void add_range_to_charclass(CharClass *towhat, char start, char end)/*{{{*/ -{ - int sx, ex, t; - sx = (int)(unsigned char) start; - ex = (int)(unsigned char) end; - if (sx > ex) { - t = sx, sx = ex, ex = t; - } - for (t=sx; t<=ex; t++) { - set_bit(towhat->char_bitmap, t); - } -} -/*}}}*/ -void invert_charclass(CharClass *what)/*{{{*/ -{ - int i; - for (i=0; i<ULONGS_PER_CC; i++) { - what->char_bitmap[i] ^= 0xffffffffUL; - } -} -/*}}}*/ -void diff_charclasses(CharClass *left, CharClass *right)/*{{{*/ -{ - /* Compute set difference */ - int i; - for (i=0; i<ULONGS_PER_CC; i++) { - left->char_bitmap[i] &= ~(right->char_bitmap[i]); - } -} -/*}}}*/ - -static char *emit_char (char *p, int i)/*{{{*/ -{ - if (i == '\\') { - *p++ = '\\'; - *p++ = '\\'; - } else if (isprint(i) && (i != '-')) { - *p++ = i; - } else if (i == '\n') { - *p++ = '\\'; - *p++ = 'n'; - } else if (i == '\r') { - *p++ = '\\'; - *p++ = 'r'; - } else if (i == '\f') { - *p++ = '\\'; - *p++ = 'f'; - } else if (i == '\t') { - *p++ = '\\'; - *p++ = 't'; - } else { - p += sprintf(p, "\\%03o", i); - } - return p; -} -/*}}}*/ -static void generate_string(int idx, const unsigned long *x)/*{{{*/ -{ - int i, j; - char buffer[4096]; - char *p; - - p = buffer; - *p++ = '['; - /* Force '-' to be shown at the start. */ - i = 0; - do { - while ((i < 256) && !cc_test_bit(x,i)) i++; - if (i>=256) break; - - j = i + 1; - while ((j < 256) && cc_test_bit(x,j)) j++; - j--; - - p = emit_char(p, i); - if (j == (i + 1)) { - p = emit_char(p, j); - } else if (j > (i + 1)) { - *p++ = '-'; - p = emit_char(p, j); - } - - i = j + 1; - } while (i < 256); - *p++ = ']'; - *p = 0; - strings[idx] = new_string(buffer); - return; -} -/*}}}*/ -static void combine(unsigned long *into, const unsigned long *with)/*{{{*/ -{ - int i; - for (i=0; i<ULONGS_PER_CC; i++) into[i] |= with[i]; -} -/*}}}*/ -static void set_all(unsigned long *x)/*{{{*/ -{ - int i; - for (i=0; i<ULONGS_PER_CC; i++) x[i] = 0xffffffffUL; -} -/*}}}*/ -static void clear_all(unsigned long *x)/*{{{*/ -{ - int i; - for (i=0; i<ULONGS_PER_CC; i++) x[i] = 0x0UL; -} -/*}}}*/ -static int find_lowest_bit_set(const unsigned long *x)/*{{{*/ -{ - int i; - for (i=0; i<ULONGS_PER_CC; i++) { - if (x[i]) { - int pos = 0; - unsigned long val = x[i]; - if (!(val & 0xffff)) pos += 16, val >>= 16; - if (!(val & 0x00ff)) pos += 8, val >>= 8; - if (!(val & 0x000f)) pos += 4, val >>= 4; - if (!(val & 0x0003)) pos += 2, val >>= 2; - if (!(val & 0x0001)) pos += 1; - return (i << 5) + pos; - } - } - return -1; -} -/*}}}*/ - -static void mark_used_in_block(const Block *b)/*{{{*/ -{ - int i; - - for (i=0; i<b->nstates; i++) { - const State *s = b->states[i]; - const TransList *tl; - for (tl=s->transitions; tl; tl=tl->next) { - switch (tl->type) { - case TT_CHARCLASS: - tl->x.char_class->is_used = 1; - break; - default: - break; - } - } - } -} -/*}}}*/ -static void reduce_list(void)/*{{{*/ -{ - struct cc_list *ccl, *next_ccl; - ccl = cc_list; - cc_list = NULL; - while (ccl) { - next_ccl = ccl->next; - if (ccl->cc->is_used) { - ccl->next = cc_list; - cc_list = ccl; - } else { - free(ccl->cc); - free(ccl); - } - ccl = next_ccl; - } -} -/*}}}*/ -void split_charclasses(const Block *b)/*{{{*/ -{ - unsigned long cc_union[ULONGS_PER_CC]; - struct cc_list *elt; - int i; - int any_left; - - mark_used_in_block(b); - reduce_list(); - - n_charclasses = 0; - - if (!cc_list) { - if (verbose) fprintf(stderr, "No charclasses used\n"); - return; - } - - /* Form union */ - clear_all(cc_union); - for (elt=cc_list; elt; elt=elt->next) { - combine(cc_union, elt->cc->char_bitmap); - } - - for (i=0; i<256; i++) mapping[i] = -1; - - do { - int first_char; - int i; - unsigned long pos[ULONGS_PER_CC], neg[ULONGS_PER_CC]; - first_char = find_lowest_bit_set(cc_union); - set_all(pos); - clear_all(neg); - for (elt=cc_list; elt; elt=elt->next) { - if (cc_test_bit(elt->cc->char_bitmap, first_char)) { - for (i=0; i<ULONGS_PER_CC; i++) pos[i] &= elt->cc->char_bitmap[i]; - } else { - for (i=0; i<ULONGS_PER_CC; i++) neg[i] |= elt->cc->char_bitmap[i]; - } - } - - for (i=0; i<ULONGS_PER_CC; i++) { - pos[i] &= ~neg[i]; - } - - generate_string(n_charclasses, pos); - - for (i=0; i<256; i++) { - if (cc_test_bit(pos, i)) { - mapping[i] = n_charclasses; - clear_bit(cc_union, i); - } - } - - n_charclasses++; - any_left = 0; - for (i=0; i<ULONGS_PER_CC; i++) { - if (cc_union[i]) { - any_left = 1; - break; - } - } - } while (any_left); - - /* Build group bitmaps */ - for (elt=cc_list; elt; elt=elt->next) { - for (i=0; i<256; i++) { - if (cc_test_bit(elt->cc->char_bitmap, i)) { - set_bit(elt->cc->group_bitmap, mapping[i]); - } - } - } - - fprintf(stderr, "Got %d character classes\n", n_charclasses); - - return; -} -/*}}}*/ -void print_charclass_mapping(FILE *out, FILE *header_out, const char *prefix_under)/*{{{*/ -{ - int i; - if (!cc_list) return; - fprintf(out, "short %schar2tok[256] = {", prefix_under); - for (i=0; i<256; i++) { - if (i > 0) fputs(", ", out); - if ((i & 15) == 0) fputs("\n ", out); - if (mapping[i] >= 0) { - fprintf(out, "%3d", mapping[i] + ntokens); - } else { - fprintf(out, "%3d", mapping[i]); - } - } - fputs("\n};\n", out); - if (header_out) { - fprintf(header_out, "extern short %schar2tok[256];\n", - prefix_under); - } - return; -} -/*}}}*/ -void print_charclass(FILE *out, int idx)/*{{{*/ -{ - fprintf(out, "%d:%s", idx, strings[idx]); -} -/*}}}*/ - diff --git a/src/mairix/dfasyn/compdfa.c b/src/mairix/dfasyn/compdfa.c @@ -1,479 +0,0 @@ -/*************************************** - Routines for compressing the DFA by commoning-up equivalent states - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2001-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -/* - The input to this stage is the 'raw' DFA build from the NFA by the subset - construction. Depending on the style of the NFA, there may be large chunks - of the DFA that have equivalent functionality, in terms of resulting in the - same attributes for the same sequence of input tokens, but which are reached - by different prefixes. The idea of this stage is to common up such regions, - to reduce the size of the DFA and hence the table sizes that are generated. - - Conceptually, the basis of the algorithm is to assign the DFA states to - equivalence classes. If there are N different tags-combinations, there are - initially N+1 classes. All states that can exit with a particular value are - placed in a class together, and all non-accepting states are placed together. - Now, a pass is made over all pairs of states. Two states remain equivalent - if for each token, their outbound transitions go to states in the same class. - If the states do not stay equivalent, the class they were in is split - accordingly. This is repeated again and again until no more bisections - occur. - - The algorithm actually used is to assign an ordering to the states based on - their current class and outbound transitions. The states are then sorted. - This allows all checking to be done on near-neighbours in the sequence - generated by the sort, which brings the execution time down to something - finite. - - */ - -#include "dfasyn.h" - -static int last_eq_class; /* Next class to assign */ -static int Nt; /* Number of tokens; has to be made static to be visible to comparison fn. */ - -/* To give 'general_compre' visibility of the current equiv. classes of the - destination states */ -static DFANode **local_dfas; - -static void calculate_signatures(DFANode **seq, DFANode **dfas, int ndfas)/*{{{*/ -/**** Determine state signatures based on transitions and current classes. ****/ -{ - unsigned long sig; - int i, t; - - for (i=0; i<ndfas; i++) { - DFANode *s = seq[i]; - sig = 0UL; - for (t=0; t<Nt; t++) { - int di = s->map[t]; - if (di >= 0) { - DFANode *d = dfas[di]; - int deq_class = d->eq_class; - - sig = increment(sig, deq_class & 0xf); /* 16 bit pairs in sig */ - } - } - - s->signature = sig; - } -} -/*}}}*/ -static int general_compare(const void *a, const void *b)/*{{{*/ -/************************* Do full compare on states *************************/ -{ - Castderef (a, const DFANode *, aa); - Castderef (b, const DFANode *, bb); - - if (aa->eq_class < bb->eq_class) { - return -1; - } else if (aa->eq_class > bb->eq_class) { - return +1; - } else if (aa->signature < bb->signature) { - return -1; - } else if (aa->signature > bb->signature) { - return +1; - } else { - /* The hard way... */ - int i; - for (i=0; i<Nt; i++) { - int am = aa->map[i]; - int bm = bb->map[i]; - - /* Map transition destinations to the current equivalence class of the - destination state (otherwise compressor is very pessimistic). */ - am = (am>=0) ? local_dfas[am]->eq_class: -1; - bm = (bm>=0) ? local_dfas[bm]->eq_class: -1; - - if (am < bm) return -1; - else if (am > bm) return +1; - } - - } - - /* If you get here, the states are still equivalent */ - return 0; - -} -/*}}}*/ -static int split_classes(DFANode **seq, DFANode **dfas, int ndfas)/*{{{*/ -/*********************** Do one pass of class splitting ***********************/ -{ - int i; - int had_to_split = 0; - - calculate_signatures(seq, dfas, ndfas); - qsort(seq, ndfas, sizeof(DFANode *), general_compare); - - seq[0]->new_eq_class = seq[0]->eq_class; - - for (i=1; i<ndfas; i++) { - seq[i]->new_eq_class = seq[i]->eq_class; - - if (seq[i]->eq_class == seq[i-1]->eq_class) { - /* May need to split, otherwise states were previously separated anyway - */ - - if (general_compare(seq+i, seq+i-1) != 0) { - /* Different transition pattern, split existing equivalent class */ - had_to_split = 1; - seq[i]->new_eq_class = ++last_eq_class; - if (verbose) fprintf(stderr, "Found %d equivalence classes\r", last_eq_class+1); - } else { - /* This works even if seq[i-1] was assigned a new class due to - splitting from seq[i-2] etc. */ - seq[i]->new_eq_class = seq[i-1]->new_eq_class; - } - } - } - - /* Set classes to new class values. */ - for (i=0; i<ndfas; i++) { - seq[i]->eq_class = seq[i]->new_eq_class; - } - - return had_to_split; - -} -/*}}}*/ -static int initial_compare(const void *a, const void *b)/*{{{*/ -/************************** Sort based on tags **************************/ -{ - Castderef (a, const DFANode *, aa); - Castderef (b, const DFANode *, bb); - int status; - int i; - - for (i=0; i<n_evaluators; i++) { - - const char *ar = aa->attrs[i], *br = bb->attrs[i]; - if (!ar) ar = get_defattr(i); - if (!br) br = get_defattr(i); - - /* Sort so that states with identical attributes appear together. */ - if (!ar && br) { - return -1; - } else if (ar && !br) { - return +1; - } else { - if (ar && br) { - status = strcmp(ar, br); - if (status < 0) return -1; - else if (status > 0) return +1; - } - - /* So neither had an attribute at all, or both did and they were equal. - * i.e. need to look at attributes further up the vectors */ - } - } - - /* Got here => both states were identical in terms of their attribute sets */ - return 0; -} -/*}}}*/ -static void assign_initial_classes(DFANode **seq, int ndfas)/*{{{*/ -/******************* Determine initial equivalence classes. *******************/ -{ - int i; - qsort(seq, ndfas, sizeof(DFANode *), initial_compare); - - last_eq_class = 0; - - seq[0]->eq_class = last_eq_class; - - for (i=1; i<ndfas; i++) { - if (initial_compare(seq+i-1, seq+i) != 0) { - /* Not same as previous entry, assign a new class */ - seq[i]->eq_class = ++last_eq_class; - } else { - /* Same class as last entry */ - seq[i]->eq_class = last_eq_class; - } - } -} -/*}}}*/ -/*{{{ compress_states() */ -static void compress_states(struct DFA *dfa, int n_dfa_entries, struct DFAEntry *dfa_entries) -/***** Compress the DFA so there is precisely one state in each eq. class *****/ -{ - int *reps; - int i, j, t; - int neqc; - int new_index; - - if (verbose) fprintf(stderr, "%d DFA states before compression\n", dfa->n); - - if (report) { - fprintf(report, - "\n-----------------------------\n" - "------ COMPRESSING DFA ------\n" - "-----------------------------\n"); - } - - neqc = 1 + last_eq_class; - - /* Array containing which state is the representative of each eq. class. - Keep the state which had the lowest array index. */ - reps = new_array(int, neqc); - - for (i=0; i<neqc; i++) reps[i] = -1; /* undefined */ - - /* Go through DFA states to find the representative of each class. */ - for (i=0; i<dfa->n; i++) { - int eqc = dfa->s[i]->eq_class; - if (reps[eqc] < 0) { - reps[eqc] = i; - dfa->s[i]->is_rep = 1; - } else { - dfa->s[i]->is_rep = 0; - } - } - - /* Go through DFA states and assign new indices. */ - for (i=0, new_index=0; i<dfa->n; i++) { - if (dfa->s[i]->is_dead) { - dfa->s[i]->new_index = -1; - if (report) fprintf(report, "Old DFA state %d becomes -1 (dead state)\n", i); - } else if (dfa->s[i]->is_rep) { - dfa->s[i]->new_index = new_index++; - if (report) fprintf(report, "Old DFA state %d becomes %d\n", i, dfa->s[i]->new_index); - } else { - int eqc = dfa->s[i]->eq_class; - int rep = reps[eqc]; - - /* This assignment works because the representative for the class - must have been done earlier in the loop. */ - dfa->s[i]->new_index = dfa->s[rep]->new_index; - - if (report) fprintf(report, "Old DFA state %d becomes %d (formerly %d)\n", i, dfa->s[i]->new_index, rep); - } - } - - /* Go through all transitions and fix them up. */ - for (i=0; i<dfa->n; i++) { - DFANode *s = dfa->s[i]; - for (t=0; t<Nt; t++) { - int dest = s->map[t]; - if (dest >= 0) { - s->map[t] = dfa->s[dest]->new_index; - } - } - } - - /* Go through the entries and fix their states */ - for (i=0; i<n_dfa_entries; i++) { - int ni = dfa->s[dfa_entries[i].state_number]->new_index; - if (report) { - fprintf(report, "Entry <%s>, formerly state %d, now state %d\n", - dfa_entries[i].entry_name, - dfa_entries[i].state_number, ni); - } - dfa_entries[i].state_number = dfa->s[dfa_entries[i].state_number]->new_index; - } - - /* Fix from_state */ - for (i=0; i<dfa->n; i++) { - int old_from_state, new_from_state; - /* If we're not going to preserve the state, move along */ - if (!dfa->s[i]->is_rep) continue; - old_from_state = dfa->s[i]->from_state; - /* Any entry state ..., move along */ - if (old_from_state < 0) continue; - new_from_state = dfa->s[reps[dfa->s[old_from_state]->eq_class]]->new_index; - dfa->s[i]->from_state = new_from_state; - } - - /* Go through and crunch the entries in the DFA array, fixing up the indices */ - for (i=j=0; i<dfa->n; i++) { - if (!dfa->s[i]->is_dead && dfa->s[i]->is_rep) { - dfa->s[j] = dfa->s[i]; - dfa->s[j]->index = dfa->s[j]->new_index; - j++; - } - } - - free(reps); - dfa->n = new_index; /* ignore dead states which are completely pruned. */ - if (verbose) fprintf(stderr, "%d DFA states after compression", dfa->n); -} -/*}}}*/ -static void discard_nfa_bitmaps(struct DFA *dfa)/*{{{*/ -/********** Discard the (now inaccurate) NFA bitmaps from the states **********/ -{ - int i; - for (i=0; i<dfa->n; i++) { - free(dfa->s[i]->nfas); - dfa->s[i]->nfas = NULL; - } - return; -} -/*}}}*/ -static void print_classes(DFANode **dfas, int ndfas)/*{{{*/ -{ - int i; -#if 1 - /* Comment out to print this stuff for debug */ - return; -#endif - if (!report) return; - fprintf(report, "Equivalence classes are :\n"); - for (i=0; i<ndfas; i++) { - fprintf(report, "State %d class %d\n", i, dfas[i]->eq_class); - } - fprintf(report, "\n"); - return; -} -/*}}}*/ -static int has_any_nondefault_attribute(const DFANode *x)/*{{{*/ -{ - int result = 0; - int i; - for (i=0; i<n_evaluators; i++) { - if (x->attrs[i]) { - char *defattr; - defattr = get_defattr(i); - if (defattr && strcmp(defattr, x->attrs[i])) { - result = 1; - break; - } - } - } - return result; -} -/*}}}*/ -static void find_dead_states(DFANode **dfas, int ndfas, int ntokens)/*{{{*/ -{ - /* Find any state that has no transitions out of it and no attribute. - * If you get there, you're guaranteed to be stuck. - * Then, repeatedly look for states which are such that all transitions from - * them lead to dead states. Mark these dead too. - * Then, go through all the dead states and remove their transitions. - * This will force them all into a single class later. */ - - int did_any; - int i, j; - /* Eventually, consider looking for results that are non-default. */ - char *leads_to_result; - int total_found = 0; - - leads_to_result = new_array(char, ndfas); - memset(leads_to_result, 0, ndfas); - - if (report) { - fprintf(report, "Searching for dead states...\n"); - } - - do { - did_any = 0; - for (i=0; i<ndfas; i++) { - if (leads_to_result[i] == 0) { - if (has_any_nondefault_attribute(dfas[i])) { - leads_to_result[i] = 1; - did_any = 1; - continue; - } - - for (j=0; j<ntokens; j++) { - int next_state = dfas[i]->map[j]; - if ((next_state >= 0) && leads_to_result[next_state]) { - leads_to_result[i] = 1; - did_any = 1; - goto do_next_dfa_state; - } - } - } -do_next_dfa_state: - (void) 0; - } - } while (did_any); - - - /* Now prune any transition to states that have no path to a result. */ - for (i=0; i<ndfas; i++) { - if (leads_to_result[i] == 0) { - total_found++; - if (report) { - fprintf(report, "DFA state %d is dead\n", i); - } - dfas[i]->from_state = -1; - dfas[i]->via_token = -1; - dfas[i]->is_dead = 1; - } else { - dfas[i]->is_dead = 0; - } - - for (j=0; j<ntokens; j++) { - int next_state = dfas[i]->map[j]; - if (leads_to_result[next_state] == 0) { - dfas[i]->map[j] = -1; - } - } - } - - free(leads_to_result); - - if (!total_found && report) { - fprintf(report, "(no dead states found)\n"); - } -} -/*}}}*/ -/*{{{ compress_dfa() */ -void compress_dfa(struct DFA *dfa, int ntokens, - int n_dfa_entries, struct DFAEntry *dfa_entries) -{ - DFANode **seq; /* Storage for node sequence */ - int i; - int had_to_split; - - /* Safety net */ - if (dfa->n <= 0) return; - - local_dfas = dfa->s; - Nt = ntokens; - - seq = new_array(DFANode *, dfa->n); - for (i=0; i<dfa->n; i++) { - seq[i] = dfa->s[i]; - } - - find_dead_states(dfa->s, dfa->n, ntokens); - - assign_initial_classes(seq, dfa->n); - - do { - print_classes(dfa->s, dfa->n); - had_to_split = split_classes(seq, dfa->s, dfa->n); - } while (had_to_split); - - print_classes(dfa->s, dfa->n); - - compress_states(dfa, n_dfa_entries, dfa_entries); - discard_nfa_bitmaps(dfa); - - free(seq); - return; - -} -/*}}}*/ - diff --git a/src/mairix/dfasyn/configure b/src/mairix/dfasyn/configure @@ -1,4 +0,0 @@ -#!/bin/sh - -egrep -v '^#' INSTALL - diff --git a/src/mairix/dfasyn/dfasyn.1 b/src/mairix/dfasyn/dfasyn.1 @@ -1,154 +0,0 @@ -.TH DFASYN 1 "" -.SH NAME -dfasyn \- generate deterministic finite automata -.SH SYNOPSYS -.B dfasyn -[ -.BR \-o | \-\-output -.I C-filename -] [ -.BR \-ho | \-\-header-output -.I H-filename -] [ -.BR \-r | \-\-report -.I report-filename -] [ -.BR \-p | \-\-prefix -.I prefix -] [ -.BR \-u | \-\-uncompressed-tables -] [ -.BR \-ud | \-\-uncompressed-dfa -] [ -.BR \-I | \-\-inline-function -] [ -.BR \-v | \-\-verbose -] [ -.BR \-h | \-\-help -] -.I input-file - -.SH DESCRIPTION -.B dfasyn -generates a deterministic finite automaton (DFA) from a description file. - -.SH OPTIONS -.SS Options controlling output files -.TP -.BI "-o " C-filename -.br -.ns -.TP -.BI "--output " C-filename -.br -Specify the name of the file to which the C program text will be written. -If this option is not present, the C program text will be written to stdout. - -.TP -.BI "-ho " H-filename -.br -.ns -.TP -.BI "--header-output " H-filename -.br -Specify the name of the file to which the header information will be written. - -.TP -.BI "-r " report-filename -.br -.ns -.TP -.BI "--report " report-filename -.br -Specify the name of the file to which the report on the generated automaton -will be written. If this option is not present, no report will be written. - -.TP -.I input-file -.br -This is the name of the file containing the definition of the automaton. Refer -to -.BR dfasyn (5) -for more information about the format of this file. - -.SS Options controlling the generated automaton -.TP -.BI "-p " prefix -.br -.ns -.TP -.BI "--prefix " prefix -.br -Specify the prefix to be prepended onto each symbol that -.B dfasyn -generates in the output file. This allows multiple automata to be linked into -the same final program without namespace clashes. - -The string prepended is actually -.I prefix -followed by an underscore ('_'). - -.TP -.BR -u ", " --uncompressed-tables -.br -Do not compress the transition tables. By default, -.B dfasyn -emits the transition tables compressed, and it emits a next-state function that -uses a bisection algorithm to search the tables. By contrast, uncompressed -tables use a simple array indexing algorithm in the next-state algorithm. -However, the generated tables will be much larger, especially if there is a -large set of input symbols and the transitions in the automaton are relatively -sparse. This option therefore represents a speed versus space trade-off in the -generated DFA. - -.TP -.BR -ud ", " --uncompressed-dfa -.br -Do not compress the generated DFA. By default, -.B dfasyn -compresses the DFA to combine common states into a single state in the final -DFA and to remove unreachable states. This option suppresses the compression. -Giving this option can only be to the detriment of the final DFA, in terms of -the array sizes of its tables. However, the option is useful for debugging -.B dfasyn -and will also reduce the run time of -.B dfasyn -since a potentially complex processing step can be omitted. - -.TP -.BR -I ", " --inline-function -.br -This causes the next-state function to emitted as an inline function in the header output. -Specifying this option without -.B -ho -is non-sensical and -.B dfasyn -will complain in that situation. - -Normally, -.B dfasyn -will emit the next_state function in the C program text output. This will -incur a function call overhead for each input symbol when the DFA is used at -run-time. If this is significant to the final application, the -.B -I -option may be useful to allow the next-state function to be inlined. - -.SS General options - -.TP -.BR -v ", " --verbose -.br -Make the output more verbose; provide more comfort messages whilst -.B dfasyn -is running. - -.TP -.BR -h ", " --help -.br -Show usage summary and exit - -.SH "SEE ALSO" -.BR dfasyn (5), -.BR bison (1), -.BR flex (1) - diff --git a/src/mairix/dfasyn/dfasyn.5 b/src/mairix/dfasyn/dfasyn.5 @@ -1,650 +0,0 @@ -.TH DFASYN 5 "" -.SH NAME -dfasyn -.SH SYNOPSYS -This page describes the format of the -.I input-file -for the -.B dfasyn -deterministic finite automaton generator. -.SH DESCRIPTION -.SS Overview -Reserved words may be given in all-lowercase, all-uppercase, initial capitals, -or 'WikiWord' format (e.g. -.B endblock -may be given as -.BR endblock ", " Endblock ", " EndBlock " or " ENDBLOCK . - -.SS Block declaration -A -.B block -declaration is used to group together a set of state declarations. Blocks are -useful if there are blocks of states and their interconnections that occur more -than once in the NFA. In this case it is useful to declare a block, allowing -that block to be instantiated more than once elsewhere in the input file. - -Since state declarations are only allowed inside blocks, there must be at least -one block declaration in any useful input file. - -The syntax of a block declaration is -.RS -.B block -.I block-name -{ -.br -.RS 2 -[ -.I instance-declarations -] -.br -[ -.I state-declarations -] -.RE -.br -} -.RE - -.SS State declarations -A -.B state -declaration gives rise to a state in the input NFA. - -The syntax of a state declaration is -.RS -.B state -.I state-name -[ -.B entry -.I entry-name -] -.br -.RS 2 -[ -.I transitions -] -.RE -.RE - -States are implicitly terminated by the beginning of another type of construct. - -.B entry -.I entry-name -(if present) defines the name of an entry point into the scanner. In the -resulting C-code, a symbol called -.I entry-name -will be declared. Its value will be the DFA state number of the state -containing just this NFA state (plus its epsilon closure.) This allows for -multiple scanners to be generated from the same input file. For example, if -one scanner is the same as another but with some extra text that must match at -the beginning, two different -.B entry -states can be declared to represent this. -.B dfasyn -will be able to common-up all of the common part of the DFA's transition -tables. - -If there are no -.B entry -directives anywhere in the input file, -.B dfasyn -defaults to the last mentioned state in the last block being the entry state. - -.I transitions -is a whitespace-separated sequence of zero or more transitions. These define which -of the automaton's input symbols cause a transition from this state to which other -states. - -The same state may be declared more than once inside its block. In this case, -the transitions given in the second declaration will be merged with those given -in the first, as though all the transitions had been given in the first place. - -.SS Instance declarations -A block may be instantiated inside another block. This is useful if there is a -block of states with their transitions that occurs in more than once place -within the NFA. - -The syntax for an instance declaration is - -.RS -.I instance-name -: -.I block-name -.RE - -where -.I instance-name -is the name of the new instance, and -.I block-name -is the name of the block that is being instantiated. This block -.B must -have been declared earlier in the input file. For one thing, this prevents -mutually recursive definitions. - -When such an instance has been created, the states inside it may be referred to -within the enclosing block by prefixing their names with the -.I instance-name -followed by a period. - -.SS Transitions -A state-to-state transition is specified as follows. - -.RS -.I transition --> -.I destinations -.RE - -.I destinations -is a comma-separated list of one or more fully-qualified state names. These -are the states to which the NFA moves if the -.I transition -is matched next in the input. The destination state names are allowed to be -forward-references; just the name is stored during parsing, and a second pass -later is used to resolve all the names. There is no need for a named -destination to actually be declared with another state definition; a state just -comes into being if it is named at all. - -A -.I transition -defines the inputs that are required to cause the scanner to move -from one state to another. A -.I transition -is a semicolon-separated list of one or more -.I stimuli. -(If there is only one stimulus, no semicolon is required.) The transition -matches as a whole if the stimuli are matched individually in sequential order -from left to right. - -.SS Transitions to a tag -Where a transition leads to a tagged exit state, the following syntax is used: - -.RS -.I transition -= -.I tags -.RE - -where -.I tags -is a comma-separated list of one or more tag names. Thus a construction like - -.RS -state foo XXX = TAG1 -.RE - -indicates that matching the token XXX leads to a state in which TAG1 applies. - -.SS Stimuli -A -.B stimulus -is a pipe-separated list of alternatives. Each alternative may be one of the following: -.IP "*" 7 -the name of a token -.IP "*" 7 -a character class -.IP "*" 7 -the name of an abbreviation -.IP "*" 7 -an empty string (which gives rise to an -.B epsilon transition -) -.IP "*" 7 -an inline block instance - -.SS Input symbols -Input symbols can be defined in two ways. The first is to use ASCII characters -directly. The second is to define a set of -.I tokens -and use a front-end module to generate these based on the actual input. You -can actually mix both types of input symbol. For example, you might wish to -use ASCII characters mostly, but detect \(dqend-of-file\(dq as an explicit symbol. - -.SS ASCII input and character classes. - -Single ASCII characters can be given in double-quotes. Sets of ASCII -characters can be given in square brackets, similar to shell globbing. -Character classes can be negated and differenced. - -.IP [a] 12 -The character "a". -.IP [abe-h] 12 -Any of the characters "a", "b", "e", "f", "g", "h". -.IP ~[abc] 12 -Any of the 253 characters excluding "a", "b" and "c"; a negated character class. -.IP [^abc] 12 -Ditto - another way of expressing a negated character class. -.IP [a-z]~[c] 12 -Equivalent to [abd-z]. - -.PP -The following special cases are available within the square brackets: - -.IP \(rs- 8 -A hyphen. Normally the hyphen is used as a range separator. To get a literal -hyphen, it must be escaped by a back-slash. -.IP \(rs] 8 -A closing square bracket. The escaping is required to prevent it being handled -as the end of the character class. -.IP \(rs\(rs 8 -A literal backslash. -.IP \(rs^ 8 -A literal "^". -.IP \(rsn 8 -The same character as "\(rsn" in C. -.IP \(rsr 8 -The same character as "\(rsr" in C. -.IP \(rsf 8 -The same character as "\(rsf" in C. -.IP \(rst 8 -The same character as "\(rst" in C. -.IP ^A 8 -Generate a control character, in this case ASCII character 1. Defined for ^@ -through to ^Z. -.IP \(rsxa9 8 -The ASCII character with hex value 0xa9. Upper or lower case hex may be used. -.IP \(rs234 -The ASCII character with octal value 0234. - -.SS Tokens -To define non-ASCII inputs, at least one -.B tokens -directive must be used. The syntax is -.PP -.B tokens -.I list-of-tokens -.PP -where -.I list-of-tokens -is a space-separated list of token names. Each token name is a string that -will be acceptable as a C macro name when prefixed by the current prefix string -plus an underscore. - -If more than one -.B tokens -line appears in the input file, the 2nd and subsequent lines are treated as -though their entries were concatenated with the 1st line. - -.SS Abbreviations -An -.B abbreviation -provides a convenient way to define a shorthand name for a frequently used -.B stimulus. - -The syntax is - -.RS -.B abbrev -.I abbrev-name -= -.I stimulus -.RE - -For example: - -.RS -abbrev FOO = [aeiouAEIOU] | A_TOKEN | <xyzzy:in->out> -.RE - -.SS Inline block instances -A -.B stimulus -may take the form of a block instance. This is a convenient shorthand when a -complex sequence of input tokens needs to be matched as part of a transition. - -The syntax of an inline block instance is -.RS -.RI < block_name : entry_state "->" exit_state > -.RE - -As an example, given a block -.B double_a -defined like this -.RS -block double_a - state in A -> out -.br -endblock -.RE - -the following construction -.RS -block x - state foo <double_a:in->out> ; B ; <double_a:in->out> -> bar -.br -endblock -.RE - -is equivalent to -.RS -block x - aa1 : double_a - aa2 : double_a - state foo -> aa1.in - state aa1.out - B -> aa2.in - state aa2.out -> bar -.br -endblock -.RE - -Note that in the second example, where explicit instances have been created, -they must have unique names. In the first case, -.B dfasyn -will create the two anonymous instances automatically and handle all the -plumbing to connect up the in and out states. Note there is no requirement for -the states to be named 'in' and 'out'; that is merely a convention. An -instanced block may have multiple inputs, with different inputs being used in -different instantiations of the block, for example. - -.SS Tags and attributes -.B Tags -are associated with the NFA states in the input. An NFA state may have an -arbitrary number of tags associated with it, through what amounts to a list of -strings. -.B Attributes -are attached to the DFA states in the output. In the generated C-file, the -attributes are expressed in terms of an array which is indexed by the DFA state -number and whose elements are the attribute values applying to the states. - -Once the DFA has been generated, -.B dfasyn -knows the NFA states that apply in each DFA state. From this, the tags -associated with a DFA state are given by the union of all the tags appylying in -all the NFA states that apply in that DFA state. - -The input file defines how a set of tags applying in a DFA state is to be -reduced to a single attribute value. A boolean expression language is provided -for this purpose. - -Although the default is to generate a single attribute table, -.B dfasyn -can generate arbitrarily many tables if required. This is achieved by using -.B attribute groups. -The NFA tag namespace is shared across all such groups. The group syntax is as -follows: - -.RS -.B group -.I groupname -.B { -.I declaration -[ -.RI ", " declaration -\ ... -] -.B } -.RE - -where each -.I declaration -is one of the following: - -.RS -.B attr -.I attribute-name -[ -.RI ", " attribute-name -\ ... ] -.br -.B attr -.I attribute-name -.B : -.I expression -.br -.B early -.B attr -.I attribute-name -[ -.RI ", " attribute-name -\ ... ] -.br -.B early -.B attr -.I attribute-name -.B : -.I expression -.RE - -In the form with no expression, each -.I attribute-name -has an implicit expression consisting of just the tag with the same name as -itself. - -.I expression -is defined in the section -.B Expressions -later. The short form - -.RS -.B attr -foo -.RE - -is short for -.RS -.B attr -foo -.B : -foo -.RE - -i.e. it allows an attribute to be defined which has the same name as a tag and -which is active in the cases where precisely that tag is active. - -If an attribute is prefixed by -.BR early , -it means that the C-code you provide to drive the DFA is going to stop scanning -once this state attribute is detected. For example, this would apply if you -were coding a "shortest match" scanner. -.B dfasyn -will prune all the transitions away from any DFA state having such an -attribute. This may lead to greater opportunities for -.B dfasyn -to compress the DFA. - -A default attribute must be declared. This is used to fill all the entries in -the attribute array for DFA states that end up with no explicit attribute -defined. (It is also used in determining where the DFA may be optimised to -remove "dead states".) The syntax is - -.RS -.B defattr -.I default-attribute-string -.RE - -Finally, the C-type of the attribute must be declared. This becomes the base -type of the array indexed by the DFA state number. The syntax is - -.RS -.B type -.I attribute-type-name -.RE - -It is illegal for more than one attribute in a particular attribute group to be -active in a DFA state. If this situation occurs, it indicates that the -expression logic for that group is defective. - -.SS Expressions -An -.I expression -defines an attribute in terms of a boolean relationship between one more more -tags. An -.I expression -may be any one of the following: - -.RS -.IR expression " & " expression -.br -.IR expression " | " expression -.br -.IR expression " ^ " expression -.br -.IR expression " ? " expression " : " expression -.br -.RI ( expression ) -.br -.RI "~" expression -.br -.RI "!" expression -.br -.I tag-name -.RE - -Note that -.RI "~" expression -and -.RI "!" expression -both mean the negation of expression. - -The operator precedence is what would be expected for a C-programmer. - -.SH Prefix specification -The -.B prefix -used in the generated C-file can optionally be set in the input file using the following syntax: - -.RS -.B prefix -.I prefix-string -.RE - -where -.IR prefix-string _ -(i.e. the specific string followed by an underscore) will occur at the start of -each symbol name in the generated C-file. - -If the prefix has been set via the command line using -.BR -p , -the -.B prefix -line in the input file will be ignored and a warning given. - -.SH "THE GENERATED C-FILE" -The generated file exports the following symbols that can be used by the calling program: - -.TP -.B short -.IB prefix_ char2tok -[256]; -.br -If character classes have been used, this table maps from ASCII values to the -internal tokens numbers used by the generated DFA. This array will be defined -in the generated C-file. If a header file is being generated, it will be -declared in there also. - -.TP -.B #define -.IB prefix_ TOKEN -.I numeric_value -.br -If a -.b tokens -directive has been used, each such token will be assigned a number. These -assignments are emitted by -.b dfasyn -as a series of #define lines. Each token name from the input file will have the -.I prefix -and an underscore prepended to form the name of the symbol in the #define. -If a header file is being generated -.RB ( -ho ), -these definitions are placed in the header file. Otherwise, they are placed in -the main output C-file. - -.TP 7 -.B int -.IB prefix_ next_state -(int current_state, int next_state); -.br -This is the prototype for the next state function which the calling program must invoke. - -If no -.B -I -option has been used, this function will be defined in the generated C-file. -If a header file is being generated, it will be prototyped in there also. - -If -.B -I -has been used, the function will be defined in the header file. - -.TP -.B int -.IB prefix _ entry-name -.br -If the -.B entrystruct -directive has not been used, this format is used to define the DFA state -numbers for the defined entry points. The calling program uses these values to -set the -.I current_state -at the start of the scanning process, depending on which entry point is being -used. - -If there is more than one entry, there will be more than one such line. - - -.TP -.B struct -.I entrystruct-type -{ ... } -.I entrystruct-var -.br -If the -.B entrystruct -directive has been used, the DFA state numbers for the entry points are -declared as elements of a struct. The struct member names are identical to the -entry names used in the -.B dfasyn -input file. The declaration of the struct variable containing the state -numbers will be in the generated C-file. If a header file is being generated -.RB ( -ho ), -the definition of the struct type will be in there. Otherwise, it will be in -the C-file also. - -.TP 12 -.I attr-type -.IB prefix_ attr -.RI [ #DFA-states ] -.br -This defines the attributes for each of the DFA states in the default attribute -group. If no -.B type -.I attr-type -declaration was in the input file, the default of -.B short -will be used. - -If other attribute groups are defined, there will be a similar array for each one: - -.TP 18 -.I group-attr-type -.I prefix_group-name -.RI [ #DFA-states ] -.br -For the attribute group declared with -.B group -.I group-name -in the input file, this defines the attribute of each of the DFA states in that -group. - -.SH TEXT PASSTHROUGH -To pass a block of literal text through to the output file without -interpretation, enclose it in %{ ... %} like this: - -.RS -%{ -.br -#include "foo.h" -.br -%} -.RE - -The opening and closing patterns must be on lines on their own (trailing -whitespace is allowed). - - -.SH "SEE ALSO" -.BR dfasyn (1) - - - diff --git a/src/mairix/dfasyn/dfasyn.c b/src/mairix/dfasyn/dfasyn.c @@ -1,690 +0,0 @@ -/*************************************** - Main program for NFA to DFA table builder program. - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2000-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "dfasyn.h" - -FILE *report = NULL; -FILE *output = NULL; -FILE *header_output = NULL; - -/* If non-null this gets prepended onto the names of the all the entities that - * are generated in the output file. */ -char *prefix = NULL; - -extern int yyparse(void); - -/* ================================================================= */ -static char *entrystruct = NULL; -static char *entryvar = NULL; - -void define_entrystruct(const char *s, const char *v)/*{{{*/ -{ - if (!entrystruct) { - entrystruct = new_string(s); - entryvar = new_string(v); - } else { - fprintf(stderr, "Can't redefine entrystruct with <%s>\n", s); - exit(1); - } -} -/*}}}*/ -/* ================================================================= */ -static void print_token_table(void)/*{{{*/ -{ - FILE *dest; - int i; - extern char *prefix; - - dest = header_output ? header_output : output; - /* Not sure how it makes sense to write this to the C file : maybe if you're going - * to include the C file into a bigger one it's reasonable? Anyway, the intention - * is that you're more likely to use this for real if you're writing a header file. */ - - for (i=0; i<ntokens; i++) { - fprintf(dest, "#define %s_%s %d\n", - prefix ? prefix : "TOK_", - toktable[i], i); - } -} -/*}}}*/ -static void print_attr_tables(struct DFA *dfa, const char *prefix_under)/*{{{*/ -{ - int i, tab; - - for (tab=0; tab<n_evaluators; tab++) { - char *defattr = get_defattr(tab); - char *attrname = get_attr_name(tab); - if (!attrname) attrname = "attr"; - fprintf(output, "%s %s%s[] = {\n", get_attr_type(tab), prefix_under, attrname); - for (i=0; i<dfa->n; i++) { - char *attr = dfa->s[i]->attrs[tab]; - fprintf(output, " %s", attr ? attr : defattr); - fputc ((i<(dfa->n - 1)) ? ',' : ' ', output); - fprintf(output, " /* State %d */\n", i); - } - fprintf(output, "};\n\n"); - if (header_output) { - fprintf(header_output, "extern %s %s%s[];\n", get_attr_type(tab), prefix_under, attrname); - } - } -} -/*}}}*/ -static void check_default_attrs(void)/*{{{*/ -{ - int tab; - int fail = 0; - - for (tab=0; tab<n_evaluators; tab++) { - char *defattr = get_defattr(tab); - char *attrname = get_attr_name(tab); - attrname = attrname ? attrname : "(DEFAULT)"; - if (!defattr) { - fprintf(stderr, "ERROR: No defattr definition for %s\n", attrname); - fail = 1; - } - } - if (fail) { - exit(1); - } -} -/*}}}*/ -static void write_next_state_function_uncompressed(int Nt, int do_inline, const char *prefix_under)/*{{{*/ -{ - FILE *dest; - - dest = do_inline ? header_output : output; - - fprintf(dest, "%sint %snext_state(int current_state, int next_token) {\n", - do_inline ? "static inline " : "", - prefix_under); - fprintf(dest, " if (next_token < 0 || next_token >= %d) return -1;\n", Nt); - fprintf(dest, " return %strans[%d*current_state + next_token];\n", - prefix_under, Nt); - fprintf(dest, "}\n"); - if (!do_inline && header_output) { - fprintf(header_output, "extern int %snext_state(int current_state, int next_token);\n", - prefix_under); - } -} -/*}}}*/ -static void print_uncompressed_tables(struct DFA *dfa, int do_inline, const char *prefix_under)/*{{{*/ -/* Print out the state/transition table uncompressed, i.e. every - token has an array entry in every state. This is fast to access - but quite wasteful on memory with many states and many tokens. */ -{ - int Nt = ntokens + n_charclasses; - int n, i, j; - - n = 0; - fprintf(output, "%sshort %strans[] = {", - do_inline ? "" : "static ", - prefix_under); - - if (do_inline) { - fprintf(header_output, "extern short %strans[];\n", - prefix_under); - } - - for (i=0; i<dfa->n; i++) { - for (j=0; j<Nt; j++) { - if (n>0) fputc (',', output); - if (n%8 == 0) { - fprintf(output, "\n "); - } else { - fputc(' ', output); - } - n++; - fprintf(output, "%4d", dfa->s[i]->map[j]); - } - } - - fprintf(output, "\n};\n\n"); - - write_next_state_function_uncompressed(Nt, do_inline, prefix_under); - -} -/*}}}*/ -static int check_include_char(struct DFA *dfa, int this_state, int token)/*{{{*/ -{ - if (dfa->s[this_state]->defstate >= 0) { - return (dfa->s[this_state]->map[token] != - dfa->s[dfa->s[this_state]->defstate]->map[token]); - } else { - return (dfa->s[this_state]->map[token] >= 0); - } -} -/*}}}*/ -static void write_next_state_function_compressed(int do_inline, const char *prefix_under)/*{{{*/ -/* Write the next_state function for traversing compressed tables into the - output file. */ -{ - FILE *dest; - dest = do_inline ? header_output : output; - - fprintf(dest, "%sint %snext_state(int current_state, int next_token) {\n", - do_inline ? "static inline " : "", - prefix_under); - fprintf(dest, " int h, l, m, xm;\n"); - fprintf(dest, " while (current_state >= 0) {\n"); - fprintf(dest, " l = %sbase[current_state], h = %sbase[current_state+1];\n", prefix_under, prefix_under); - fprintf(dest, " while (h > l) {\n"); - fprintf(dest, " m = (h + l) >> 1; xm = %stoken[m];\n", prefix_under); - fprintf(dest, " if (xm == next_token) goto done;\n"); - fprintf(dest, " if (m == l) break;\n"); - fprintf(dest, " if (xm > next_token) h = m;\n"); - fprintf(dest, " else l = m;\n"); - fprintf(dest, " }\n"); - fprintf(dest, " current_state = %sdefstate[current_state];\n", prefix_under); - fprintf(dest, " }\n"); - fprintf(dest, " return -1;\n"); - fprintf(dest, " done:\n"); - fprintf(dest, " return %snextstate[m];\n", prefix_under); - fprintf(dest, "}\n"); - if (!do_inline && header_output) { - fprintf(header_output, "extern int %snext_state(int current_state, int next_token);\n", - prefix_under); - } - -} -/*}}}*/ -static void print_compressed_tables(struct DFA *dfa, int do_inline, const char *prefix_under)/*{{{*/ -/* Print state/transition table in compressed form. This is more - economical on storage, but requires a bisection search to find - the next state for a given current state & token */ -{ - int *basetab = new_array(int, dfa->n + 1); - int Nt = ntokens + n_charclasses; - int n, i, j; - - n = 0; - fprintf(output, "%sunsigned char %stoken[] = {", - do_inline ? "" : "static ", - prefix_under); - for (i=0; i<dfa->n; i++) { - for (j=0; j<Nt; j++) { - if (check_include_char(dfa, i, j)) { - if (n>0) fputc (',', output); - if (n%8 == 0) { - fprintf(output, "\n "); - } else { - fputc(' ', output); - } - n++; - fprintf(output, "%3d", j); - } - } - } - fprintf(output, "\n};\n\n"); - - n = 0; - fprintf(output, "%sshort %snextstate[] = {", - do_inline ? "" : "static ", - prefix_under); - for (i=0; i<dfa->n; i++) { - basetab[i] = n; - for (j=0; j<Nt; j++) { - if (check_include_char(dfa, i, j)) { - if (n>0) fputc (',', output); - if (n%8 == 0) { - fprintf(output, "\n "); - } else { - fputc(' ', output); - } - n++; - fprintf(output, "%5d", dfa->s[i]->map[j]); - } - } - } - fprintf(output, "\n};\n\n"); - basetab[dfa->n] = n; - - n = 0; - fprintf(output, "%sunsigned short %sbase[] = {", - do_inline ? "" : "static ", - prefix_under); - for (i=0; i<=dfa->n; i++) { - if (n>0) fputc (',', output); - if (n%8 == 0) { - fprintf(output, "\n "); - } else { - fputc(' ', output); - } - n++; - fprintf(output, "%5d", basetab[i]); - } - fprintf(output, "\n};\n\n"); - - n = 0; - fprintf(output, "%sshort %sdefstate[] = {", - do_inline ? "" : "static ", - prefix_under); - for (i=0; i<dfa->n; i++) { - if (n>0) fputc (',', output); - if (n%8 == 0) { - fprintf(output, "\n "); - } else { - fputc(' ', output); - } - n++; - fprintf(output, "%5d", dfa->s[i]->defstate); - } - fprintf(output, "\n};\n\n"); - - if (do_inline) { - fprintf(header_output, "extern unsigned char %stoken[];\n", prefix_under); - fprintf(header_output, "extern short %snextstate[];\n", prefix_under); - fprintf(header_output, "extern unsigned short %sbase[];\n", prefix_under); - fprintf(header_output, "extern short %sdefstate[];\n", prefix_under); - } - free(basetab); - - write_next_state_function_compressed(do_inline, prefix_under); -} -/*}}}*/ -static void print_entries_table(const char *prefix_under)/*{{{*/ -{ - int i; - if (entrystruct) { - int first; - /* If we write the struct defn to the header file, we ought not to emit the - * full struct defn again in the main output. This is tricky unless we can - * guarantee the header will get included, though. */ - fprintf(output, "struct %s {\n", entrystruct); - if (header_output) { - fprintf(header_output, "extern struct %s {\n", entrystruct); - } - for (i=0; i<n_dfa_entries; i++) { - fprintf(output, " int %s;\n", dfa_entries[i].entry_name); - if (header_output) { - fprintf(header_output, " int %s;\n", dfa_entries[i].entry_name); - } - } - fprintf(output, "} %s = {\n", entryvar); - if (header_output) { - fprintf(header_output, "} %s;\n", entryvar); - } - for (i=0, first=1; i<n_dfa_entries; i++, first=0) { - if (!first) { - fputs(",\n", output); - } - fprintf(output, " %d", dfa_entries[i].state_number); - } - fputs("\n};\n", output); - } else { - for (i=0; i<n_dfa_entries; i++) { - fprintf(output, "int %s%s = %d;\n", - prefix_under, - dfa_entries[i].entry_name, dfa_entries[i].state_number); - if (header_output) { - fprintf(header_output, "extern int %s%s;\n", - prefix_under, - dfa_entries[i].entry_name); - } - } - } -} -/*}}}*/ -/* ================================================================= */ -static void deal_with_multiple_entries(Block **blk, struct DFA **dfa)/*{{{*/ -{ - /* Get the list of blocks that are to be combined to form a union of all their states. */ - struct Entrylist *e; - int Ne; - Block **blocks; - Block *jumbo; - int bi, Nb, Ns, si, ei; - - for (Ne=0, e=entries; e; e=e->next) Ne++; - if (report) { - fprintf(report, "Processing %d separate entry points\n", Ne); - } - blocks = new_array(Block*, Ne); - for (Nb=0, e=entries; e; e=e->next) { - int matched = 0; - for (bi=0; bi<Nb; bi++) { - if (e->state->parent == blocks[bi]) { - matched = 1; - break; - } - } - if (!matched) { - blocks[Nb++] = e->state->parent; - } - } - for (Ns=0, bi=0; bi<Nb; bi++) { - Ns += blocks[bi]->nstates; - } - - if (report) { - fprintf(report, "Entries in %d blocks, total of %d states\n", - Nb, Ns); - } - - jumbo = new(Block); - jumbo->name = "(UNION OF MULTIPLE BLOCKS)"; - jumbo->nstates = jumbo->maxstates = Ns; - jumbo->states = new_array(State *, Ns); - jumbo->eclo = NULL; - - for (bi=0, si=0; bi<Nb; bi++) { - int ns = blocks[bi]->nstates; - int i; - int block_name_len; - memcpy(jumbo->states + si, blocks[bi]->states, sizeof(State *) * ns); - block_name_len = strlen(blocks[bi]->name); - for (i=0; i<ns; i++) { - int len; - char *new_name; - State *s = jumbo->states[si + i]; - len = block_name_len + strlen(s->name) + 2; - new_name = new_array(char, len); - strcpy(new_name, blocks[bi]->name); - strcat(new_name, "."); - strcat(new_name, s->name); - free(s->name); - s->name = new_name; - } - si += ns; - } - - /* Reindex all the states */ - for (si=0; si<Ns; si++) { - jumbo->states[si]->index = si; - } - - split_charclasses(jumbo); - expand_charclass_transitions(jumbo); - - if (verbose) fprintf(stderr, "Computing epsilon closure...\n"); - generate_epsilon_closure(jumbo); - print_nfa(jumbo); - build_transmap(jumbo); - - if (verbose) fprintf(stderr, "Building DFA...\n"); - n_dfa_entries = Ne; - dfa_entries = new_array(struct DFAEntry, Ne); - for (e=entries, ei=0; e; e=e->next, ei++) { - dfa_entries[ei].entry_name = new_string(e->entry_name); - dfa_entries[ei].state_number = e->state->index; - } - *dfa = build_dfa(jumbo); - *blk = jumbo; - -} -/*}}}*/ -/* ================================================================= */ -static void usage(void)/*{{{*/ -{ - fprintf(stderr, - "dfasyn, Copyright (C) 2001-2003,2005,2006 Richard P. Curnow\n" - "\n" - "dfasyn comes with ABSOLUTELY NO WARRANTY.\n" - "This is free software, and you are welcome to redistribute it\n" - "under certain conditions; see the GNU General Public License for details.\n" - "\n" - "Usage: dfasyn [OPTION]... FILE\n" - "Read state-machine description from FILE and generate a deterministic automaton.\n" - "Write results to stdout unless options dictate otherwise.\n" - "\n" - "Output files:\n" - " -o, --output FILE Define the name of the output file (e.g. foobar.c)\n" - " -ho, --header-output FILE Define the name of the header output file (e.g. foobar.h)\n" - " -r, --report FILE Define the name where the full generator report goes (e.g. foobar.report)\n" - "\n" - "Generated automaton:\n" - " -p, --prefix PREFIX Specify a prefix for the variables and functions in the generated file(s)\n" - " -u, --uncompressed-tables Don't compress the generated transition tables\n" - " -ud, --uncompressed-dfa Don't common-up identical states in the DFA\n" - " -I, --inline-function Make the next_state function inline (requires -ho)\n" - "\n" - "General:\n" - " -v, --verbose Be verbose\n" - " -h, --help Display this help message\n" - ); - -} -/*}}}*/ -/* ================================================================= */ -int main (int argc, char **argv)/*{{{*/ -{ - int result; - - Block *main_block; - char *input_name = NULL; - char *output_name = NULL; - char *header_output_name = NULL; - char *report_name = NULL; - int uncompressed_tables = 0; - int uncompressed_dfa = 0; /* Useful for debug */ - int do_inline = 0; - extern char *prefix; - char *prefix_under; - FILE *input = NULL; - struct DFA *dfa; - - verbose = 0; - report = NULL; - - /*{{{ Parse cmd line arguments */ - while (++argv, --argc) { - if (!strcmp(*argv, "-h") || !strcmp(*argv, "--help")) { - usage(); - exit(0); - } else if (!strcmp(*argv, "-v") || !strcmp(*argv, "--verbose")) { - verbose = 1; - } else if (!strcmp(*argv, "-o") || !strcmp(*argv, "--output")) { - ++argv, --argc; - output_name = *argv; - } else if (!strcmp(*argv, "-ho") || !strcmp(*argv, "--header-output")) { - ++argv, --argc; - header_output_name = *argv; - } else if (!strcmp(*argv, "-r") || !strcmp(*argv, "--report")) { - ++argv, --argc; - report_name = *argv; - } else if (!strcmp(*argv, "-u") || !strcmp(*argv, "--uncompressed-tables")) { - uncompressed_tables = 1; - } else if (!strcmp(*argv, "-ud") || !strcmp(*argv, "--uncompressed-dfa")) { - uncompressed_dfa = 1; - } else if (!strcmp(*argv, "-I") || !strcmp(*argv, "--inline-function")) { - do_inline = 1; - } else if (!strcmp(*argv, "-p") || !strcmp(*argv, "--prefix")) { - ++argv, --argc; - prefix = *argv; - } else if ((*argv)[0] == '-') { - fprintf(stderr, "Unrecognized command line option %s\n", *argv); - } else { - input_name = *argv; - } - } - /*}}}*/ - - if (do_inline && !header_output_name) {/*{{{*/ - fprintf(stderr, - "--------------------------------------------------------------\n" - "It doesn't make sense to try inlining if you're not generating\n" - "a separate header file.\n" - "Not inlining the transition function.\n" - "--------------------------------------------------------------\n" - ); - do_inline = 0; - } -/*}}}*/ - if (input_name) {/*{{{*/ - input = fopen(input_name, "r"); - if (!input) { - fprintf(stderr, "Can't open %s for input, exiting\n", input_name); - exit(1); - } - } else { - input = stdin; - } - /*}}}*/ - if (output_name) {/*{{{*/ - output = fopen(output_name, "w"); - if (!output) { - fprintf(stderr, "Can't open %s for writing, exiting\n", output_name); - exit(1); - } - } else { - output = stdout; - } -/*}}}*/ - if (header_output_name) {/*{{{*/ - header_output = fopen(header_output_name, "w"); - if (!header_output) { - fprintf(stderr, "Can't open %s for writing, exiting\n", header_output_name); - exit(1); - } - } - /* otherwise the header stuff just goes to the same fd as the main output. */ - -/*}}}*/ - if (report_name) {/*{{{*/ - report = fopen(report_name, "w"); - if (!report) { - fprintf(stderr, "Can't open %s for writing, no report will be created\n", report_name); - } - } -/*}}}*/ - - if (verbose) { - fprintf(stderr, "General-purpose automaton builder\n"); - fprintf(stderr, "Copyright (C) Richard P. Curnow 2000-2003,2005,2006\n"); - } - - eval_initialise(); - - if (verbose) fprintf(stderr, "Parsing input..."); - yyin = input; - - /* Set yyout. This means that if anything leaks from the scanner, or appears - in a %{ .. %} block, it goes to the right place. */ - yyout = output; - - result = yyparse(); - if (result > 0) exit(1); - if (verbose) fprintf(stderr, "\n"); - - make_evaluator_array(); - check_default_attrs(); - - if (!entries) { - /* Support legacy method : the last state to be current in the input file - * is the entry state of the NFA */ - State *start_state; - start_state = get_curstate(); - main_block = start_state->parent; - split_charclasses(main_block); - expand_charclass_transitions(main_block); - if (verbose) fprintf(stderr, "Computing epsilon closure...\n"); - generate_epsilon_closure(main_block); - print_nfa(main_block); - build_transmap(main_block); - - if (verbose) fprintf(stderr, "Building DFA...\n"); - { - struct DFAEntry entry[1]; - n_dfa_entries = 1; - dfa_entries = entry; - entry[0].entry_name = "(ONLY ENTRY)"; - entry[0].state_number = start_state->index; - dfa = build_dfa(main_block); - } - } else { - /* Allow generation of multiple entry states, so you can use the same input file when - * you need several automata that have a lot of logic in common. */ - deal_with_multiple_entries(&main_block, &dfa); - } - if (report) { - fprintf(report, "--------------------------------\n" - "DFA structure before compression\n" - "--------------------------------\n"); - } - print_dfa(dfa); - - if (had_ambiguous_result) { - fprintf(stderr, "No output written, there were ambiguous attribute values for accepting states\n"); - exit(2); - } - - if (!uncompressed_dfa) { - if (verbose) fprintf(stderr, "\nCompressing DFA...\n"); - compress_dfa(dfa, ntokens + n_charclasses, n_dfa_entries, dfa_entries); - } - - if (verbose) fprintf(stderr, "\nCompressing transition tables...\n"); - compress_transition_table(dfa, ntokens + n_charclasses); - - if (report) { - fprintf(report, "-------------------------------\n" - "DFA structure after compression\n" - "-------------------------------\n"); - } - if (verbose) fprintf(stderr, "Writing outputs...\n"); - print_dfa(dfa); - - if (prefix) { - prefix_under = new_array(char, 2 + strlen(prefix)); - strcpy(prefix_under, prefix); - strcat(prefix_under, "_"); - } else { - prefix_under = ""; - } - - if (header_output) { - fprintf(header_output, "#ifndef %sHEADER_H\n", prefix_under); - fprintf(header_output, "#define %sHEADER_H\n", prefix_under); - } - - print_token_table(); - print_charclass_mapping(output, header_output, prefix_under); - print_attr_tables(dfa, prefix_under); - - if (uncompressed_tables) { - print_uncompressed_tables(dfa, do_inline, prefix_under); - } else { - print_compressed_tables(dfa, do_inline, prefix_under); - } - - if (entries) { - /* Emit entry table */ - print_entries_table(prefix_under); - } else { - /* Legacy behaviour - DFA state 0 is implicitly the single entry state. */ - } - - if (report) { - fclose(report); - report = NULL; - } - - report_unused_tags(); - - if (header_output) { - fprintf(header_output, "#endif\n"); - } - - return result; -} -/*}}}*/ diff --git a/src/mairix/dfasyn/dfasyn.h b/src/mairix/dfasyn/dfasyn.h @@ -1,365 +0,0 @@ -/*************************************** - Header file for NFA->DFA conversion utility. - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2001-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#ifndef N2D_H -#define N2D_H - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define new(T) ((T *) malloc(sizeof(T))) -#define new_array(T,N) ((T *) malloc((N) * sizeof(T))) -#define resize_array(T,arr,newN) ((T *) ((arr) ? realloc(arr,(newN)*sizeof(T)) : malloc((newN)*sizeof(T)))) -#define new_string(s) strcpy((char *)malloc((strlen(s)+1)*sizeof(char)),s) - -/* For typecasting, especially useful for declarations of local ptrs to args - of a qsort comparison fn */ -#define Castdecl(x, T, nx) T nx = (T) x - -#define Castderef(x, T, nx) T nx = *(T*) x - -/* Globally visible options to control reporting */ -extern FILE *report; -extern FILE *report; -extern FILE *output; -extern FILE *header_output; - -/* Bison interface. */ -extern FILE *yyin; -extern FILE *yyout; - -extern int verbose; - -extern char *prefix; - -/* Temporary - this will be done better when the charclass stuff is - * added. */ -extern char **toktable; -extern int ntokens; - -extern int n_charclasses; - -extern int had_ambiguous_result; - -extern int n_dfa_entries; -extern struct DFAEntry *dfa_entries; - -struct State; -struct Block; -struct StimulusList; - -struct Abbrev {/*{{{*/ - char *lhs; /* Defined name */ - struct StimulusList *stimuli; -#if 0 - char **rhs; /* Token/define */ - int nrhs; - int maxrhs; -#endif -}; -/*}}}*/ - -typedef enum StimulusType {/*{{{*/ - T_EPSILON, - T_TOKEN, - T_ABBREV, - T_INLINEBLOCK, - T_CHARCLASS -} StimulusType; -/*}}}*/ -typedef struct InlineBlock {/*{{{*/ - char *type; /* Block type */ - char *in; /* Name of input node */ - char *out; /* Name of output node */ -} InlineBlock; -/*}}}*/ - -#define ULONGS_PER_CC 8 - -typedef struct CharClass {/*{{{*/ - int is_used; - unsigned long char_bitmap[ULONGS_PER_CC]; - unsigned long group_bitmap[ULONGS_PER_CC]; -} CharClass; -/*}}}*/ -typedef struct Stimulus {/*{{{*/ - StimulusType type; - union { - /* TODO : token should eventually become a struct ref ? */ - int token; - struct Abbrev *abbrev; - /* placeholders */ - InlineBlock *inline_block; - CharClass *char_class; - } x; -} Stimulus; -/*}}}*/ -typedef struct StimulusList {/*{{{*/ - struct StimulusList *next; - Stimulus *stimulus; -} StimulusList; -/*}}}*/ -typedef enum TransType {/*{{{*/ - TT_EPSILON, - TT_TOKEN, - TT_CHARCLASS -} TransType; -/*}}}*/ -typedef struct TransList {/*{{{*/ - struct TransList *next; - TransType type; - union { - int token; - CharClass *char_class; - } x; - char *ds_name; - struct State *ds_ref; -} TransList; -/*}}}*/ -typedef struct Stringlist {/*{{{*/ - struct Stringlist *next; - char *string; -} Stringlist; -/*}}}*/ - -#if 0 -typedef struct InlineBlockList {/*{{{*/ - struct InlineBlockList *next; - InlineBlock *ib; -} InlineBlockList; -/*}}}*/ -#endif - -typedef struct State {/*{{{*/ - char *name; - int index; /* Array index in containing block */ - struct Block *parent; - TransList *transitions; - Stringlist *tags; - Stringlist *entries; - - /* Pointers to the nodes in the 'transitions' list, sorted into canonical order */ - TransList **ordered_trans; - int n_transitions; - - unsigned char removed; /* Flag indicating state has been pruned by compression stage */ -} State; -/*}}}*/ -typedef struct S_Stateset {/*{{{*/ - State **states; - int nstates; - int maxstates; -} Stateset; -/*}}}*/ -#define HASH_BUCKETS 64 -#define HASH_MASK (HASH_BUCKETS-1) - -typedef struct Block {/*{{{*/ - char *name; - - /* The master table of states within this block. This has to be in a flat - array because we have to work with respect to state indices when doing the - 2D bitmap stuff for the subset construction. */ - State **states; - int nstates; - int maxstates; - - /* epsilon closure for this block (treating it as a top-level block.) */ - unsigned long **eclo; - - /* Hash table for getting rapid access to a state within the block, given - its name */ - Stateset state_hash[HASH_BUCKETS]; - - int subcount; /* Number for generating substates */ - int subblockcount; /* Number for generating inline subblocks */ -} Block; -/*}}}*/ -struct Entrylist {/*{{{*/ - struct Entrylist *next; - char *entry_name; - State *state; -}; -/*}}}*/ -extern struct Entrylist *entries; - -typedef struct DFANode {/*{{{*/ - unsigned long *nfas; - unsigned long signature; /* All the longwords in the nfas array xor'ed together */ - int index; /* Entry's own index in the array */ - int *map; /* index by token code */ - int from_state; /* the state which provided the first transition to this one (leading to its creation) */ - int via_token; /* the token through which we got to this state the first time. */ - Stringlist *nfa_exit_sl; /* NFA exit values */ - Stringlist *nfa_attr_sl; /* NFA exit values */ - char **attrs; /* Attributes, computed by boolean expressions defined in input text */ - int has_early_exit; /* If !=0, the scanner is expected to exit immediately this DFA state is entered. - It means that no out-bound transitions have to be created. */ - - /* Fields calculated in compdfa.c */ - - /* The equivalence class the state is in. */ - int eq_class; - - /* Temp. storage for the new eq. class within a single pass of the splitting alg. */ - int new_eq_class; - - /* Signature field from above is also re-used. */ - - int is_rep; /* Set if state is chosen as the representative of its equivalence class. */ - int is_dead; /* Set if the state has no path to a non-default result */ - int new_index; /* New index assigned to the state. */ - - /* Fields calculated in tabcompr.c */ - - unsigned long transition_sig; - - /* Default state, i.e. the one that supplies transitions for tokens not - explicitly listed for this one. */ - int defstate; - - /* Number of transitions that this state has different to those in the - default state. */ - int best_diff; - -} DFANode; -/*}}}*/ -struct DFAEntry {/*{{{*/ - char *entry_name; - /* Initially the NFA number, overwritten with DFA number by build_dfa */ - int state_number; -}; -/*}}}*/ -struct DFA {/*{{{*/ - DFANode **s; /* states */ - int n; - int max; - - /* the original block that the DFA comes from. */ - Block *b; -}; -/*}}}*/ - -void yyerror(const char *s); -extern int yylex(void); - -/* Constants for 'create' args */ -#define USE_OLD_MUST_EXIST 0 -#define CREATE_MUST_NOT_EXIST 1 -#define CREATE_OR_USE_OLD 2 - -State *get_curstate(void); - -struct Abbrev; -extern struct Abbrev * create_abbrev(const char *name, struct StimulusList *stimuli); - -int lookup_token(char *name, int create); -Block *lookup_block(char *name, int create); -State *lookup_state(Block *in_block, char *name, int create); -void add_entry_to_state(State *curstate, const char *entry); -void define_entrystruct(const char *s, const char *v); -Stringlist * add_string_to_list(Stringlist *existing, const char *token); -void add_transitions(Block *curblock, State *curstate, StimulusList *stimuli, char *destination); -State * add_transitions_to_internal(Block *curblock, State *addtostate, StimulusList *stimuli); -void add_tags(State *curstate, Stringlist *sl); -InlineBlock *create_inline_block(char *type, char *in, char *out); -void instantiate_block(Block *curblock, char *block_name, char *instance_name); -void fixup_state_refs(Block *b); -void expand_charclass_transitions(Block *b); - -void compress_nfa(Block *b); - -extern void generate_epsilon_closure(Block *b); -extern void print_nfa(Block *b); -extern void build_transmap(Block *b); -extern struct DFA *build_dfa(Block *b); -extern void print_dfa(struct DFA *dfa); - -/* In expr.c */ -typedef struct Expr Expr; - -Expr * new_not_expr(Expr *c); -Expr * new_and_expr(Expr *c1, Expr *c2); -Expr * new_or_expr(Expr *c1, Expr *c2); -Expr * new_xor_expr(Expr *c1, Expr *c2); -Expr * new_cond_expr(Expr *c1, Expr *c2, Expr *c3); -Expr * new_tag_expr(char *tag_name); -extern int eval(Expr *e); -void define_tag(char *name, Expr *e); -void clear_tag_values(void); -void report_unused_tags(void); - -/* In evaluator.c */ -typedef struct evaluator Evaluator; -extern int n_evaluators; -extern Evaluator *default_evaluator; -extern Evaluator *start_evaluator(const char *name); -void define_attr(Evaluator *x, char *string, Expr *e, int early); -void define_defattr(Evaluator *x, char *string); -void set_tag_value(char *tag_name); -int evaluate_attrs(char ***, int *); -int evaluator_is_used(Evaluator *x); -void define_defattr(Evaluator *x, char *text); -void define_type(Evaluator *x, char *text); -char* get_defattr(int i); -char* get_attr_type(int i); -char* get_attr_name(int i); -void make_evaluator_array(void); -void emit_dfa_attr_report(char **results, FILE *out); -void eval_initialise(void); - -void compress_transition_table(struct DFA *dfa, int ntokens); -unsigned long increment(unsigned long x, int field); -unsigned long count_bits_set(unsigned long x); - -/* in abbrevs.c */ -struct Abbrev * lookup_abbrev(char *name); - -/* in stimulus.c */ -extern Stimulus *stimulus_from_epsilon(void); -extern Stimulus *stimulus_from_string(char *str); -extern Stimulus *stimulus_from_inline_block(InlineBlock *block); -extern Stimulus *stimulus_from_char_class(CharClass *char_class); -extern StimulusList *append_stimulus_to_list(StimulusList *existing, Stimulus *stim); - -/* in charclass.c */ -extern int cc_test_bit(const unsigned long *bitmap, int entry); -extern CharClass *new_charclass(void); -extern void free_charclass(CharClass *what); -extern void add_charclass_to_list(CharClass *cc); -extern void add_singleton_to_charclass(CharClass *towhat, char thechar); -extern void add_range_to_charclass(CharClass *towhat, char star, char end); -extern void invert_charclass(CharClass *what); -extern void diff_charclasses(CharClass *left, CharClass *right); -extern void split_charclasses(const Block *b); -extern void print_charclass_mapping(FILE *out, FILE *header_out, const char *prefix_under); -extern void print_charclass(FILE *out, int idx); - -/* Return new number of DFA states */ -extern void compress_dfa(struct DFA *dfa, int ntokens, - int n_dfa_entries, struct DFAEntry *dfa_entries); - -#endif /* N2D_H */ - diff --git a/src/mairix/dfasyn/dfasyn.texi b/src/mairix/dfasyn/dfasyn.texi @@ -1,85 +0,0 @@ -@setfilename dfasyn.info -@settitle User guide for the dfasyn DFA construction utility - -@titlepage -@title dfasyn user guide -@subtitle This manual describes how to use dfasyn. -@author Richard P. Curnow -@page -@end titlepage - -@c{{{ Top node -@node Top -@top -@menu -* Introduction:: The introduction -* Input file format:: A reference for the input file -* Concept Index:: Index of concepts -@end menu -@c}}} -@c{{{ ch:Introduction -@node Introduction -@chapter Introduction - -@menu -* Uses for dfasyn:: The types of problem to which dfasyn is well-suited -@end menu - -@node Uses for dfasyn -@section Uses for dfasyn -dfasyn is particularly suited to the following types of scanning problem, both of -which exceed flex's capabilities - -@itemize @bullet -@item When the pattern describing a token cannot be written as a regular -expression. For example, there may be iteration but with constraints between -the end of one iteration and the start of the next. -@item When more than 1 rule matches in a flex input file, flex chooses between -them based on - - @itemize - - @item Longest match first - @item Earliest rule in the file if more than 1 match of the same length exists - @end itemize - -dfasyn allows for a more general method of resolving multiple matches. -Conceptually, it works out which rules match, giving a true/false status for -each rule. The input file defines an arbitrarily complex set of boolean -expressions to reduce the multiple matches down to one unique one. (If more than -one of the boolean expressions evaluates true, this is an error.) - -@item When a customised method is required to construct the input tokens that -pass to the scanner. For example, if the tokens are the characters in a string -(rather than coming from a file), or if some special logic has to be used to -generate the tokens from the input character stream. - -@item If you want to add actions to the scanning loop, e.g. to remember special -locations within the word being scanned. - -@end itemize - -@node Non-uses for dfasyn -@section Cases where flex might be better - -In general, flex is easier and more convenient to use. Where it is applicable -to your problem, there are no obvious benefits to using dfasyn. - -@node Why written -@section Why was dfasyn written? -@c}}} - -@c{{{ ch:Input file format -@node Input file format -@chapter Input file format -This section describes the format of the input file. - -@c}}} - - -@node Concept Index -@unnumbered Concept Index -@printindex cp -@bye - -@c vim:syntax=OFF:fdm=marker:fdc=4:cms=@c%s - diff --git a/src/mairix/dfasyn/evaluator.c b/src/mairix/dfasyn/evaluator.c @@ -1,248 +0,0 @@ -/*************************************** - Routines for merging and prioritising exit tags and attribute tags - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2001-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -/* Handle boolean expressions used to determine the final scanner result from - the set of NFA accepting states that are simultaneously active at the end of - the scan. */ - -#include "dfasyn.h" - -struct Attr { - char *attr; /* The string to write to the output file */ - /* The boolean expression that defines whether the attribute is active */ - Expr *e; - /* If != 0, assume the state machine that the program's output is embedded in - will exit immediately if this result occurs. This may allow lots of - states to be culled from the DFA. */ - int early; -}; - -typedef struct Attr Attr; -struct evaluator { - Attr *attrs; - int is_used; /* Set if any input rules reference this evaluator */ - int n_attrs; - int max_attrs; - char *name; - char *defattr; - char *attr_type; -}; - -Evaluator *default_evaluator; - -struct evaluator_list { - struct evaluator_list *next; - Evaluator *evaluator; -}; - -static struct evaluator_list *evaluator_list = NULL; - -/* Array pointer */ -static struct evaluator **evaluators = NULL; -int n_evaluators = 0; - -Evaluator* start_evaluator(const char *name)/*{{{*/ -{ - Evaluator *x = NULL; - struct evaluator_list *el; - for (el=evaluator_list; el; el=el->next) { - /* name is null for the default (anonymous) attribute group */ - const char *een = el->evaluator->name; - if ((!een && !name) || - (een && name && !strcmp(een, name))) { - x = el->evaluator; - break; - } - } - if (!x) { - struct evaluator_list *nel; - x = new(struct evaluator); - x->attrs = NULL; - x->is_used = 0; - x->n_attrs = x->max_attrs = 0; - x->name = name ? new_string(name) : NULL; - x->defattr = NULL; - x->attr_type = NULL; - nel = new(struct evaluator_list); - nel->next = evaluator_list; - nel->evaluator = x; - evaluator_list = nel; - } - return x; -} -/*}}}*/ -void destroy_evaluator(Evaluator *x)/*{{{*/ -{ - /* Just leak memory for now, no need to clean up. */ - return; -} -/*}}}*/ -void define_defattr(Evaluator *x, char *text)/*{{{*/ -{ - x = x ? x : default_evaluator; - x->defattr = new_string(text); - x->is_used = 1; -} -/*}}}*/ -void define_type(Evaluator *x, char *text)/*{{{*/ -{ - x = x ? x : default_evaluator; - x->attr_type = new_string(text); - x->is_used = 1; -} -/*}}}*/ -char* get_defattr(int i)/*{{{*/ -{ - Evaluator *x = evaluators[i]; - return x->defattr; -} -/*}}}*/ -char* get_attr_type(int i)/*{{{*/ -{ - Evaluator *x = evaluators[i]; - return x->attr_type ? x->attr_type : "short"; -} -/*}}}*/ -char* get_attr_name(int i)/*{{{*/ -{ - Evaluator *x = evaluators[i]; - return x->name ? x->name : NULL; -} -/*}}}*/ -static void grow_attrs(Evaluator *x)/*{{{*/ -{ - if (x->n_attrs == x->max_attrs) { - x->max_attrs += 32; - x->attrs = resize_array(Attr, x->attrs, x->max_attrs); - } -} -/*}}}*/ - -void define_attr(Evaluator *x, char *string, Expr *e, int early)/*{{{*/ -/*++++++++++++++++++++ - Add a attr defn. If the expr is null, it means build a single expr corr. - to the value of the tag with the same name as the attr string. - ++++++++++++++++++++*/ -{ - Attr *r; - - x = x ? x : default_evaluator; - - x->is_used = 1; - grow_attrs(x); - r = &(x->attrs[x->n_attrs++]); - r->attr = new_string(string); - r->early = early; - if (e) { - r->e = e; - } else { - Expr *ne; - ne = new_tag_expr(string); - r->e = ne; - } - - return; -} -/*}}}*/ - -void make_evaluator_array(void)/*{{{*/ -{ - int n; - struct evaluator_list *el; - for (el=evaluator_list, n=0; el; el=el->next, n++) ; - evaluators = new_array(struct evaluator *, n); - n_evaluators = n; - for (el=evaluator_list, n=0; el; el=el->next, n++) { - evaluators[n] = el->evaluator; - } -} -/*}}}*/ -int evaluate_attrs(char ***attrs, int *attr_early)/*{{{*/ -/*++++++++++++++++++++ - Evaluate the attr which holds given the tags that are set - ++++++++++++++++++++*/ -{ - int i, j; - int status; - - if (attr_early) *attr_early = 0; - status = 1; - - *attrs = new_array(char *, n_evaluators); - - for (j=0; j<n_evaluators; j++) { - char **attr; - struct evaluator *x; - int any_attrs_so_far = 0; - int matched = -1; - - attr = &(*attrs)[j]; - x = evaluators[j]; - - for (i=0; i<x->n_attrs; i++) { - if (eval(x->attrs[i].e)) { - if (matched >= 0) { - *attr = NULL; - status = 0; - break; - } else { - any_attrs_so_far = 1; - matched = i; - } - } - } - if (matched < 0) { - *attr = NULL; - } else { - *attr = x->attrs[matched].attr; - if (attr_early) *attr_early |= x->attrs[matched].early; - } - } - - return status; -} -/*}}}*/ -int evaluator_is_used(Evaluator *x)/*{{{*/ -{ - return x->is_used; -} -/*}}}*/ -void emit_dfa_attr_report(char **attrs, FILE *out)/*{{{*/ -{ - int i; - for (i=0; i<n_evaluators; i++) { - if (attrs[i]) { - const char *name = evaluators[i]->name; - fprintf(out, " Attributes for <%s> : %s\n", - name ? name : "(DEFAULT)", attrs[i]); - } - } -} -/*}}}*/ -/* Initialisation */ -void eval_initialise(void)/*{{{*/ -{ - default_evaluator = start_evaluator(NULL); -} -/*}}}*/ diff --git a/src/mairix/dfasyn/expr.c b/src/mairix/dfasyn/expr.c @@ -1,243 +0,0 @@ -/*************************************** - Routines for merging and prioritising exit tags and attribute tags - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2001-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -/* Handle boolean expressions used to determine the final scanner result from - the set of NFA accepting states that are simultaneously active at the end of - the scan. */ - -#include "dfasyn.h" - -enum ExprType { - E_AND, E_OR, E_XOR, E_COND, E_NOT, E_TAG -}; - -struct Tag; - -struct Expr { - enum ExprType type; - union { - struct { struct Expr *c1, *c2; } and; - struct { struct Expr *c1, *c2; } or; - struct { struct Expr *c1, *c2; } xor; - struct { struct Expr *c1, *c2, *c3; } cond; - struct { struct Expr *c1; } not; - struct { char *name; struct Tag *s; } tag; - } data; -}; - -struct Tag { - char *name; - int is_expr; - union { - Expr *e; - int val; - } data; - int is_used; -}; - -struct TagList { - struct TagList *next; - struct Tag *tag; -}; - -typedef struct Tag Tag; -typedef struct TagList TagList; - -static TagList *tags = NULL; - -Expr * new_not_expr(Expr *c)/*{{{*/ -{ - Expr *r = new(Expr); - r->type = E_NOT; - r->data.not.c1 = c; - return r; -} -/*}}}*/ -Expr * new_and_expr(Expr *c1, Expr *c2)/*{{{*/ -{ - Expr *r = new(Expr); - r->type = E_AND; - r->data.and.c1 = c1; - r->data.and.c2 = c2; - return r; -} -/*}}}*/ -Expr * new_or_expr(Expr *c1, Expr *c2)/*{{{*/ -{ - Expr *r = new(Expr); - r->type = E_OR; - r->data.or.c1 = c1; - r->data.or.c2 = c2; - return r; -} -/*}}}*/ -Expr * new_xor_expr(Expr *c1, Expr *c2)/*{{{*/ -{ - Expr *r = new(Expr); - r->type = E_XOR; - r->data.xor.c1 = c1; - r->data.xor.c2 = c2; - return r; -} -/*}}}*/ -Expr * new_cond_expr(Expr *c1, Expr *c2, Expr *c3)/*{{{*/ -{ - Expr *r = new(Expr); - r->type = E_COND; - r->data.cond.c1 = c1; - r->data.cond.c2 = c2; - r->data.cond.c3 = c3; - return r; -} -/*}}}*/ - -Expr * new_tag_expr(char *tag_name)/*{{{*/ -/* Return expr for tag name if it already exist, else create. Don't bind to - actual tag instance yet. At the stage of parsing where this function is - used, we don't know yet which tag table the tag has to exist in. */ -{ - Expr *r; - - r = new(Expr); - r->type = E_TAG; - r->data.tag.name = new_string(tag_name); - r->data.tag.s = NULL; /* Force binding at first use */ - return r; -} -/*}}}*/ -static void add_new_tag(Tag *s)/*{{{*/ -{ - TagList *nsl = new(TagList); - nsl->tag = s; - nsl->next = tags; - tags = nsl; -} - /*}}}*/ -static Tag * find_tag_or_create(char *tag_name)/*{{{*/ -{ - Tag *s; - TagList *sl; - for (sl=tags; sl; sl=sl->next) { - s = sl->tag; - if (!strcmp(s->name, tag_name)) { - return s; - } - } - - s = new(Tag); - add_new_tag(s); - s->is_expr = 0; /* Until proven otherwise */ - s->data.val = 0; /* Force initial value to be well-defined */ - s->name = new_string(tag_name); - s->is_used = 0; - return s; -} -/*}}}*/ -void define_tag(char *name, Expr *e)/*{{{*/ -/*++++++++++++++++++++ - Define an entry in the tag table. - ++++++++++++++++++++*/ -{ - Tag *s; - s = find_tag_or_create(name); - s->data.e = e; - s->is_expr = 1; - return; -} -/*}}}*/ - -void clear_tag_values(void)/*{{{*/ -{ - TagList *sl; - for (sl=tags; sl; sl=sl->next) { - Tag *s = sl->tag; - if (0 == s->is_expr) { - s->data.val = 0; - } - } -} -/*}}}*/ -void set_tag_value(char *tag_name)/*{{{*/ -{ - Tag *s; - - s = find_tag_or_create(tag_name); - if (s->is_expr) { - fprintf(stderr, "Cannot set value for tag '%s', it is defined by an expression\n", s->name); - exit(2); - } else { - s->data.val = 1; - } -} -/*}}}*/ -int eval(Expr *e)/*{{{*/ -/*++++++++++++++++++++ - Evaluate the value of an expr - ++++++++++++++++++++*/ -{ - switch (e->type) { - case E_AND: - return eval(e->data.and.c1) && eval(e->data.and.c2); - case E_OR: - return eval(e->data.or.c1) || eval(e->data.or.c2); - case E_XOR: - return eval(e->data.xor.c1) ^ eval(e->data.xor.c2); - case E_COND: - return eval(e->data.cond.c1) ? eval(e->data.cond.c2) : eval(e->data.cond.c3); - case E_NOT: - return !eval(e->data.not.c1); - case E_TAG: - { - Tag *s = e->data.tag.s; - int result; - if (!s) { - /* Not bound yet */ - e->data.tag.s = s = find_tag_or_create(e->data.tag.name); - } - if (s->is_expr) { - result = eval(s->data.e); - } else { - result = s->data.val; - } - s->is_used = 1; - return result; - } - default: - fprintf(stderr, "Interal error : Can't get here!\n"); - exit(2); - } -} -/*}}}*/ -void report_unused_tags(void)/*{{{*/ -{ - Tag *s; - TagList *sl; - for (sl=tags; sl; sl=sl->next) { - s = sl->tag; - if (!s->is_used) { - fprintf(stderr, "Warning: tag <%s> not referenced by any attribute expression\n", s->name); - } - } -} -/*}}}*/ diff --git a/src/mairix/dfasyn/n2d.c b/src/mairix/dfasyn/n2d.c @@ -1,696 +0,0 @@ -/*************************************** - Convert NFA to DFA - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2000-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -/* {{{ General comments - Convert a nondeterminstic finite automaton (NFA) into a deterministic finite - automaton (DFA). - - The NFA is defined in terms of a set of states, with transitions between the - states. The transitions may occur on any one of a set of symbols (specified - with | characters between the options), or may be 'epsilon' transitions, i.e. - occurring without consumption of any input. A state may have multiple - transitions for the same input symbol (hence 'nondeterministic'). The final - state encountered within the final block defined in the input file is taken - to be the start state of the whole NFA. A state may be entered more than - once in the file; the transitions in the multiple definitions are combined to - give the complete transition set. A state may have 1 or more tags assigned - (with =); this is the return value of the automaton if the end of string is - encountered when in that state. - }}} */ - -#include <ctype.h> -#include "dfasyn.h" -#include <assert.h> - -/* Globally visible options to control reporting */ -int verbose; - -struct Entrylist *entries = NULL; - -/* ================================================================= */ -static inline int round_up(const int x) {/*{{{*/ - return (x+31)>>5; -} -/*}}}*/ -static inline void set_bit(unsigned long *x, int n)/*{{{*/ -{ - int r = n>>5; - unsigned long m = 1UL<<(n&31); - x[r] |= m; -} -/*}}}*/ -static inline int is_set(unsigned long *x, int n)/*{{{*/ -{ - int r = n>>5; - unsigned long m = 1UL<<(n&31); - return !!(x[r] & m); -} -/*}}}*/ -/* ================================================================= */ -static void transitively_close_eclo(unsigned long **eclo, int N)/*{{{*/ -{ - int from; - unsigned long *from_row; - unsigned long *todo, this_todo; - int Nru; - int i, i32, j, k, merge_idx; - int j_limit; - int any_changes; - - Nru = round_up(N); - todo = new_array(unsigned long, Nru); - - for (from=0; from<N; from++) { - from_row = eclo[from]; - for (i=0; i<Nru; i++) { - todo[i] = from_row[i]; - } - any_changes = 1; - while (any_changes) { - any_changes = 0; - for (i=0; i<Nru; i++) { /* loop over words in bitvector */ - i32 = i<<5; - this_todo = todo[i]; - todo[i] = 0UL; /* reset to avoid oo-loop */ - if (!this_todo) continue; /* none to do in this block */ - j_limit = N - i32; - if (j_limit > 32) j_limit = 32; - - for (j=0; j<j_limit;) { /* loop over bits in this word */ - if (this_todo & 1) { - /* Merge in */ - merge_idx = i32 + j; - for (k=0; k<Nru; k++) { - unsigned long to_merge = eclo[merge_idx][k]; - unsigned long orig = from_row[k]; - unsigned long diffs = to_merge & (~orig); - from_row[k] |= to_merge; - if (diffs) any_changes = 1; - todo[k] |= diffs; - } - } - this_todo >>= 1; - if (!this_todo) break; /* Workload reduction at end */ - j++; - } - } - } - } -} -/*}}}*/ -void generate_epsilon_closure(Block *b)/*{{{*/ -{ - int i, j, N; - - N = b->nstates; - b->eclo = new_array(unsigned long*, N); - for (i=0; i<N; i++) { - b->eclo[i] = new_array(unsigned long, round_up(N)); - for (j=0; j<round_up(N); j++) { - b->eclo[i][j] = 0; - } - } - - /* Determine initial immediate transitions */ - for (i=0; i<N; i++) { - State *s = b->states[i]; - TransList *tl; - int from_state = s->index; - set_bit(b->eclo[from_state], from_state); /* Always reflexive */ - - for (tl=s->transitions; tl; tl=tl->next) { - switch (tl->type) { - case TT_EPSILON: - { - int to_state = tl->ds_ref->index; - set_bit(b->eclo[from_state], to_state); - } - break; - case TT_TOKEN: - /* smoke out old method of indicating an epsilon trans */ - assert(tl->x.token >= 0); - break; - default: - assert(0); - break; - } - } - } - - transitively_close_eclo(b->eclo, N); - -} -/*}}}*/ -void print_nfa(Block *b)/*{{{*/ -{ - int i, j, N; - N = b->nstates; - - if (!report) return; - - for (i=0; i<N; i++) { - State *s = b->states[i]; - TransList *tl; - Stringlist *sl; - fprintf(report, "NFA state %d = %s", i, s->name); - if (s->entries) { - int first = 1; - Stringlist *e = s->entries; - fputs(" [Entries: ", report); - while (e) { - if (!first) { - fputc(',', report); - } - first = 0; - fputs(e->string, report); - e = e->next; - } - fputc(']', report); - } - fputc('\n', report); - for (tl=s->transitions; tl; tl=tl->next) { - switch (tl->type) { - case TT_EPSILON: - fprintf(report, " [(epsilon)] -> "); - break; - case TT_TOKEN: - assert(tl->x.token >= 0); - if (tl->x.token >= ntokens) { - fprintf(report, " "); - print_charclass(report, tl->x.token - ntokens); - fprintf(report, " -> "); - } else { - fprintf(report, " %s -> ", toktable[tl->x.token]); - } - break; - default: - assert(0); - break; - } - fprintf(report, "%s\n", tl->ds_name); - } - if (s->tags) { - int first = 1; - fprintf(report, " Tags : "); - for (sl=s->tags; sl; sl=sl->next) { - fprintf(report, "%s%s", - first ? "" : "|", - sl->string); - } - fprintf(report, "\n"); - } - fprintf(report, " Epsilon closure :\n (self)\n"); - for (j=0; j<N; j++) { - if (i!=j && is_set(b->eclo[i], j)) { - fprintf(report, " %s\n", b->states[j]->name); - } - } - - fprintf(report, "\n"); - } - -} -/*}}}*/ -/* ================================================================= */ - -/* Indexed [from_state][token][to_state], flag set if there is - a transition from from_state to to_state, via token then zero or more - epsilon transitions */ - -static unsigned long ***transmap; - -/* Index [from_nfa_state][token], flag set if there is a transition - to any destination nfa state for that token. */ -static unsigned long **anytrans; - -/* ================================================================= */ -void build_transmap(Block *b)/*{{{*/ -{ - int N = b->nstates; - int Nt = ntokens + n_charclasses; - int i, j, k, m, dest; - - transmap = new_array(unsigned long **, N); - anytrans = new_array(unsigned long *, N); - for (i=0; i<N; i++) { - transmap[i] = new_array(unsigned long *, Nt); - anytrans[i] = new_array(unsigned long, round_up(Nt)); - for (j=0; j<round_up(Nt); j++) { - anytrans[i][j] = 0UL; - } - for (j=0; j<Nt; j++) { - transmap[i][j] = new_array(unsigned long, round_up(N)); - for (k=0; k<round_up(N); k++) { - transmap[i][j][k] = 0UL; - } - } - } - - for (i=0; i<N; i++) { - State *s = b->states[i]; - TransList *tl; - for (tl=s->transitions; tl; tl=tl->next) { - switch (tl->type) { - case TT_EPSILON: - break; - case TT_TOKEN: - { - assert(tl->x.token >= 0); - dest = tl->ds_ref->index; - for (m=0; m<round_up(N); m++) { - unsigned long x = b->eclo[dest][m]; - transmap[i][tl->x.token][m] |= x; - if (!!x) set_bit(anytrans[i], tl->x.token); - } - } - break; - default: - assert(0); - break; - } - } - } -} -/*}}}*/ -/* ================================================================= */ - -int had_ambiguous_result = 0; - -/* ================================================================= */ - -/* Implement an array of linked lists to access DFA states directly. The - * hashes are given by folding the signatures down to single bytes. */ - -struct DFAList { - struct DFAList *next; - DFANode *dfa; -}; - -#define DFA_HASHSIZE 256 -static struct DFAList *dfa_hashtable[DFA_HASHSIZE]; - -/* ================================================================= */ - -int n_dfa_entries; -struct DFAEntry *dfa_entries = NULL; - -/* ================================================================= */ -static void grow_dfa(struct DFA *dfa)/*{{{*/ -{ - dfa->max += 32; - dfa->s = resize_array(DFANode*, dfa->s, dfa->max); -} -/*}}}*/ -static unsigned long fold_signature(unsigned long sig)/*{{{*/ -{ - unsigned long folded; - folded = sig ^ (sig >> 16); - folded ^= (folded >> 8); - folded &= 0xff; - return folded; -} -/*}}}*/ -/* ================================================================= */ -static int find_dfa(unsigned long *nfas, int N)/*{{{*/ -/* Simple linear search. Use 'signatures' to get rapid rejection - of any DFA state that can't possibly match */ -{ - int j; - unsigned long signature = 0UL; - unsigned long folded_signature; - struct DFAList *dfal; - - for (j=0; j<round_up(N); j++) { - signature ^= nfas[j]; - } - folded_signature = fold_signature(signature); - - for(dfal=dfa_hashtable[folded_signature]; dfal; dfal = dfal->next) { - DFANode *dfa = dfal->dfa; - int matched; - - if (signature != dfa->signature) continue; - - matched=1; - - for (j=0; j<round_up(N); j++) { - if (nfas[j] != dfa->nfas[j]) { - matched = 0; - break; - } - } - if (matched) { - return dfa->index; - } - } - return -1; -} -/*}}}*/ - -/*{{{ add_dfa() */ -static int add_dfa(Block *b, struct DFA *dfa, unsigned long *nfas, int N, int Nt, int from_state, int via_token) -{ - int j; - int result = dfa->n; - int this_result_unambiguous; - - Stringlist *ex; - unsigned long signature = 0UL, folded_signature; - struct DFAList *dfal; - - if (verbose) { - fprintf(stderr, "Adding DFA state %d\r", dfa->n); - fflush(stderr); - } - - if (dfa->max == dfa->n) { - grow_dfa(dfa); - } - - dfa->s[dfa->n] = new(DFANode); - dfa->s[dfa->n]->nfas = new_array(unsigned long, round_up(N)); - dfa->s[dfa->n]->map = new_array(int, Nt); - for (j=0; j<Nt; j++) dfa->s[dfa->n]->map[j] = -1; - dfa->s[dfa->n]->index = dfa->n; - dfa->s[dfa->n]->defstate = -1; - - dfa->s[dfa->n]->from_state = from_state; - dfa->s[dfa->n]->via_token = via_token; - - for (j=0; j<round_up(N); j++) { - unsigned long x = nfas[j]; - signature ^= x; - dfa->s[dfa->n]->nfas[j] = x; - } - dfa->s[dfa->n]->signature = signature; - - folded_signature = fold_signature(signature); - dfal = new(struct DFAList); - dfal->dfa = dfa->s[dfa->n]; - dfal->next = dfa_hashtable[folded_signature]; - dfa_hashtable[folded_signature] = dfal; - - /* {{{ Boolean reductions to get attributes */ - ex = NULL; - clear_tag_values(); - for (j=0; j<N; j++) { - if (is_set(dfa->s[dfa->n]->nfas, j)) { - Stringlist *sl; - State *s = b->states[j]; - for (sl = s->tags; sl; sl = sl->next) { - Stringlist *new_sl; - new_sl = new(Stringlist); - new_sl->string = sl->string; - new_sl->next = ex; - ex = new_sl; - - set_tag_value(sl->string); - } - } - } - - dfa->s[dfa->n]->nfa_exit_sl = ex; - - this_result_unambiguous = - evaluate_attrs(&dfa->s[dfa->n]->attrs, &dfa->s[dfa->n]->has_early_exit); - - if (!this_result_unambiguous) { - Stringlist *sl; - fprintf(stderr, "WARNING : Ambiguous exit state abandoned for DFA state %d\n", dfa->n); - fprintf(stderr, "NFA exit tags applying in this stage :\n"); - for (sl = ex; sl; sl = sl->next) { - fprintf(stderr, " %s\n", sl->string); - } - had_ambiguous_result = 1; - } - /*}}}*/ - - ++dfa->n; - return result; -} -/*}}}*/ -static void clear_nfas(unsigned long *nfas, int N)/*{{{*/ -{ - int i; - for (i=0; i<round_up(N); i++) { - nfas[i] = 0; - } -} -/*}}}*/ -struct DFA *build_dfa(Block *b)/*{{{*/ -{ - unsigned long **nfas; - int i; - int j; - int N, Nt; - int next_to_do; - int *found_any; - int rup_N; - struct DFA *dfa; - - dfa = new(struct DFA); - dfa->n = 0; - dfa->max = 0; - dfa->s = NULL; - dfa->b = b; - - for (i=0; i<DFA_HASHSIZE; i++) dfa_hashtable[i] = NULL; - - N = b->nstates; - rup_N = round_up(N); - Nt = ntokens + n_charclasses; - - nfas = new_array(unsigned long *, Nt); - for (i=0; i<Nt; i++) { - nfas[i] = new_array(unsigned long, round_up(N)); - } - - /* Add initial states */ - for (j=0; j<n_dfa_entries; j++) { - int idx; - clear_nfas(nfas[0], N); - for (i=0; i<round_up(N); i++) { - nfas[0][i] |= b->eclo[dfa_entries[j].state_number][i]; - } - /* Must handle the case where >=2 of the start states are actually identical; - * nothing in the input language prevents this. */ - idx = find_dfa(nfas[0], N); - if (idx < 0) { - idx = dfa->n; - add_dfa(b, dfa, nfas[0], N, Nt, -1, -1); - } - dfa_entries[j].state_number = idx; - } - - next_to_do = 0; - found_any = new_array(int, Nt); - - /* Now the heart of the program : the subset construction to turn the NFA - into a DFA. This is a major performance hog in the program, so there are - lots of tricks to speed this up (particularly, hoisting intermediate - pointer computations out of the loop to assert the fact that there is no - aliasing between the arrays.) */ - - while (next_to_do < dfa->n) { - - int t; /* token index */ - int j0, j0_5, j1, j, mask, k; - int idx; - unsigned long *current_nfas; - unsigned long block_bitmap; - - /* If the next DFA state has the result_early flag set, it means that the scanner will - * always exit straight away when that state is reached, so there's no need to compute - * any transitions out of it. */ - - if (dfa->s[next_to_do]->has_early_exit) { - next_to_do++; - continue; - } - - for (j=0; j<Nt; j++) { - clear_nfas(nfas[j], N); - found_any[j] = 0; - } - - current_nfas = dfa->s[next_to_do]->nfas; - for (j0=0; j0<rup_N; j0++) { /* Loop over NFA states which may be in this DFA state */ - block_bitmap = current_nfas[j0]; - if (!block_bitmap) continue; - j0_5 = j0 << 5; - for (mask=1UL, j1=0; j1<32; mask<<=1, j1++) { - j = j0_5 + j1; - if (block_bitmap & mask) { /* Is NFA state in DFA */ - unsigned long **transmap_j = transmap[j]; - unsigned long *anytrans_j = anytrans[j]; - for (t=0; t<Nt; t++) { /* Loop over transition symbols */ - unsigned long *transmap_t; - unsigned long *nfas_t; - unsigned long found_any_t; - if (!is_set(anytrans_j, t)) continue; - transmap_t = transmap_j[t]; - nfas_t = nfas[t]; - found_any_t = found_any[t]; - for (k=0; k<rup_N; k++) { /* Loop over destination NFA states */ - unsigned long x; - x = transmap_t[k]; - nfas_t[k] |= x; - found_any_t |= !!x; - } - found_any[t] = found_any_t; - } - } - } - } - - for (t=0; t<Nt; t++) { - if (found_any[t]) { - idx = find_dfa(nfas[t], N); - if (idx < 0) { - idx = add_dfa(b, dfa, nfas[t], N, Nt, next_to_do, t); - } - } else { - idx = -1; - } - dfa->s[next_to_do]->map[t] = idx; - } - - next_to_do++; - } - - free(found_any); - for (i=0; i<Nt; i++) free(nfas[i]); - free(nfas); - return dfa; -} -/*}}}*/ -/* ================================================================= */ -static void display_route(struct DFA *dfa, int idx, FILE *out)/*{{{*/ -{ - int from_state, via_token; - from_state = dfa->s[idx]->from_state; - if (from_state >= 0) { - display_route(dfa, from_state, out); - fputs("->", out); - } - - via_token = dfa->s[idx]->via_token; - if (via_token >= ntokens) { - print_charclass(out, via_token - ntokens); - } else if (via_token >= 0) { - fprintf(out, "%s", toktable[via_token]); - } -} -/*}}}*/ -void print_dfa(struct DFA *dfa)/*{{{*/ -{ - int N = dfa->b->nstates; - int Nt = ntokens + n_charclasses; - - int i, j0, j0_5, j1, t; - unsigned long mask; - unsigned long current_nfas; - int rup_N = round_up(N); - int from_state, this_state; - - if (!report) return; - - for (i=0; i<dfa->n; i++) { - fprintf(report, "DFA state %d\n", i); - if (dfa->s[i]->nfas) { - fprintf(report, " NFA states :\n"); - for (j0=0; j0<rup_N; j0++) { - current_nfas = dfa->s[i]->nfas[j0]; - if (!current_nfas) continue; - j0_5 = j0<<5; - for (j1=0, mask=1UL; j1<32; mask<<=1, j1++) { - if (current_nfas & mask) { - fprintf(report, " %s\n", dfa->b->states[j0_5 + j1]->name); - } - } - } - fprintf(report, "\n"); - } - fprintf(report, " Forward route :"); - this_state = i; - from_state = dfa->s[i]->from_state; - if (from_state >= 0) { - fprintf(report, " (from state %d)", from_state); - } - fputs("\n (START)", report); - display_route(dfa, i, report); - fputs("->(HERE)", report); - fprintf(report, "\n"); - - fprintf(report, " Transitions :\n"); - for (t=0; t<Nt; t++) { - int dest = dfa->s[i]->map[t]; - if (dest >= 0) { - if (t >= ntokens) { - fprintf(report, " "); - print_charclass(report, t - ntokens); - fprintf(report, " -> %d\n", dest); - } else { - fprintf(report, " %s -> %d\n", toktable[t], dest); - } - } - } - if (dfa->s[i]->defstate >= 0) { - fprintf(report, " Use state %d as basis (%d fixups)\n", - dfa->s[i]->defstate, dfa->s[i]->best_diff); - } - if (dfa->s[i]->nfa_exit_sl) { - Stringlist *sl; - fprintf(report, " NFA exit tags applying :\n"); - for (sl=dfa->s[i]->nfa_exit_sl; sl; sl = sl->next) { - fprintf(report, " %s\n", sl->string); - } - } - - emit_dfa_attr_report(dfa->s[i]->attrs, report); - fprintf(report, "\n"); - } - fprintf(report, "\nEntry states in DFA:\n"); - for (i=0; i<n_dfa_entries; i++) { - fprintf(report, "Entry <%s> : %d\n", - dfa_entries[i].entry_name, - dfa_entries[i].state_number); - } - -} -/*}}}*/ -/* ================================================================= */ -void yyerror (const char *s)/*{{{*/ -{ - extern int lineno; - fprintf(stderr, "%s at line %d\n", s, lineno); -} -/*}}}*/ -int yywrap(void) /*{{{*/ -{ - return -1; -} -/*}}}*/ -/* ================================================================= */ - diff --git a/src/mairix/dfasyn/n2d.h b/src/mairix/dfasyn/n2d.h @@ -1,226 +0,0 @@ -/*************************************** - $Header: /cvs/src/dfasyn/n2d.h,v 1.2 2003/03/02 23:42:11 richard Exp $ - - Header file for NFA->DFA conversion utility. - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2001-2003,2005 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#ifndef N2D_H -#define N2D_H - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define new(T) ((T *) malloc(sizeof(T))) -#define new_array(T,N) ((T *) malloc((N) * sizeof(T))) -#define resize_array(T,arr,newN) ((T *) ((arr) ? realloc(arr,(newN)*sizeof(T)) : malloc((newN)*sizeof(T)))) -#define new_string(s) strcpy((char *)malloc((strlen(s)+1)*sizeof(char)),s) - -/* For typecasting, especially useful for declarations of local ptrs to args - of a qsort comparison fn */ -#define Castdecl(x, T, nx) T nx = (T) x - -#define Castderef(x, T, nx) T nx = *(T*) x - -/* Globally visible options to control reporting */ -extern FILE *report; -extern int verbose; - -struct State; -struct Block; - -typedef struct Translist { - struct Translist *next; - int token; - char *ds_name; - struct State *ds_ref; -} Translist; - -typedef struct Stringlist { - struct Stringlist *next; - char *string; -} Stringlist; - -typedef struct InlineBlock { - char *type; /* Block type */ - char *in; /* Name of input node */ - char *out; /* Name of output node */ -} InlineBlock; - -typedef struct InlineBlockList { - struct InlineBlockList *next; - InlineBlock *ib; -} InlineBlockList; - -typedef struct State { - char *name; - int index; /* Array index in containing block */ - struct Block *parent; - Translist *transitions; - Stringlist *exitvals; - Stringlist *attributes; - - /* Pointers to the nodes in the 'transitions' list, sorted into canonical order */ - Translist **ordered_trans; - int n_transitions; - - unsigned char removed; /* Flag indicating state has been pruned by compression stage */ -} State; - -typedef struct S_Stateset { - State **states; - int nstates; - int maxstates; -} Stateset; - -#define HASH_BUCKETS 64 -#define HASH_MASK (HASH_BUCKETS-1) - -typedef struct Block { - char *name; - - /* The master table of states within this block. This has to be in a flat - array because we have to work with respect to state indices when doing the - 2D bitmap stuff for the subset construction. */ - State **states; - int nstates; - int maxstates; - - /* Hash table for getting rapid access to a state within the block, given - its name */ - Stateset state_hash[HASH_BUCKETS]; - - int subcount; /* Number for generating substates */ - int subblockcount; /* Number for generating inline subblocks */ -} Block; - -typedef struct { - unsigned long *nfas; - unsigned long signature; /* All the longwords in the nfas array xor'ed together */ - int index; /* Entry's own index in the array */ - int *map; /* index by token code */ - int from_state; /* the state which provided the first transition to this one (leading to its creation) */ - int via_token; /* the token through which we got to this state the first time. */ - Stringlist *nfa_exit_sl; /* NFA exit values */ - Stringlist *nfa_attr_sl; /* NFA exit values */ - char *result; /* Result token, computed by boolean expressions defined in input text */ - int result_early; /* If !=0, the scanner is expected to exit immediately this DFA state is entered. - It means that no out-bound transitions have to be created. */ - char *attribute; /* Attribute token, computed by boolean expressions defined in input text */ - - /* Fields calculated in compdfa.c */ - - /* The equivalence class the state is in. */ - int eq_class; - - /* Temp. storage for the new eq. class within a single pass of the splitting alg. */ - int new_eq_class; - - /* Signature field from above is also re-used. */ - - int is_rep; /* Set if state is chosen as the representative of its equivalence class. */ - int new_index; /* New index assigned to the state. */ - - /* Fields calculated in tabcompr.c */ - - unsigned long transition_sig; - - /* Default state, i.e. the one that supplies transitions for tokens not - explicitly listed for this one. */ - int defstate; - - /* Number of transitions that this state has different to those in the - default state. */ - int best_diff; - -} DFANode; - - -void yyerror(const char *s); -extern int yylex(void); - -/* Constants for 'create' args */ -#define USE_OLD_MUST_EXIST 0 -#define CREATE_MUST_NOT_EXIST 1 -#define CREATE_OR_USE_OLD 2 - -State *get_curstate(void); - -struct Abbrev; -extern struct Abbrev * create_abbrev(char *name); -extern void add_tok_to_abbrev(struct Abbrev *abbrev, char *tok); - -int lookup_token(char *name, int create); -Block *lookup_block(char *name, int create); -State *lookup_state(Block *in_block, char *name, int create); -Stringlist * add_token(Stringlist *existing, char *token); -void add_transitions(State *curstate, Stringlist *tokens, char *destination); -State * add_transitions_to_internal(Block *curblock, State *addtostate, Stringlist *tokens); -void add_exit_value(State *curstate, char *value); -void set_state_attribute(State *curstate, char *name); -InlineBlock *create_inline_block(char *type, char *in, char *out); -InlineBlockList *add_inline_block(InlineBlockList *existing, InlineBlock *nib); -State * add_inline_block_transitions(Block *curblock, State *addtostate, InlineBlockList *ibl); -void instantiate_block(Block *curblock, char *block_name, char *instance_name); -void fixup_state_refs(Block *b); - -void compress_nfa(Block *b); - -/* In expr.c */ -typedef struct Expr Expr; - -typedef struct evaluator Evaluator; -extern Evaluator *exit_evaluator; -extern Evaluator *attr_evaluator; - -Expr * new_wild_expr(void); -Expr * new_not_expr(Expr *c); -Expr * new_and_expr(Expr *c1, Expr *c2); -Expr * new_or_expr(Expr *c1, Expr *c2); -Expr * new_xor_expr(Expr *c1, Expr *c2); -Expr * new_cond_expr(Expr *c1, Expr *c2, Expr *c3); -Expr * new_sym_expr(char *sym_name); - -void define_symbol(Evaluator *x, char *name, Expr *e); -void define_result(Evaluator *x, char *string, Expr *e, int early); -void define_symresult(Evaluator *x, char *string, Expr *e, int early); -void define_defresult(Evaluator *x, char *string); -void clear_symbol_values(Evaluator *x); -void set_symbol_value(Evaluator *x, char *sym_name); -int evaluate_result(Evaluator *x, char **, int *); -int evaluator_is_used(Evaluator *x); -void define_defresult(Evaluator *x, char *text); -void define_type(Evaluator *x, char *text); -char* get_defresult(Evaluator *x); -char* get_result_type(Evaluator *x); -void eval_initialise(void); - -void compress_transition_table(DFANode **dfas, int ndfas, int ntokens); -unsigned long increment(unsigned long x, int field); -unsigned long count_bits_set(unsigned long x); - -/* Return new number of DFA states */ -int compress_dfa(DFANode **dfas, int ndfas, int ntokens); - -#endif /* N2D_H */ - diff --git a/src/mairix/dfasyn/parse.y b/src/mairix/dfasyn/parse.y @@ -1,262 +0,0 @@ -/********************************************************************** - Grammar definition for input files defining an NFA - *********************************************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2001-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -%{ -#include "dfasyn.h" - -static Block *curblock = NULL; /* Current block being built */ -static State *curstate = NULL; /* Current state being worked on */ -static State *addtostate = NULL; /* Current state (incl ext) to which transitions are added */ -static StimulusList *curtranslist = NULL; /* Final option set of stimuli prior to ARROW */ -static CharClass *curcharclass = NULL; -static Evaluator *current_evaluator = NULL; - -State *get_curstate(void) { return curstate; } - -%} - -%union { - char c; - char *s; - int i; - Stringlist *sl; - Stimulus *st; - StimulusList *stl; - InlineBlock *ib; - CharClass *cc; - Expr *e; -} - -%token STRING STATE TOKENS PREFIX ARROW BLOCK ENDBLOCK COLON EQUAL SEMICOLON COMMA -%token ABBREV DEFINE -%type<s> STRING -%type<st> stimulus -%type<sl> tag_seq -%type<stl> stimulus_seq -%type<stl> transition_seq -%type<e> expr -%type<ib> inline_block -%type<c> CHAR -%type<cc> char_class simple_char_class negated_char_class char_class_diff - -%token ATTR TAG -%token DEFATTR -%token EARLY -%token TYPE -%token ENTRY -%token ENTRYSTRUCT -%token GROUP -%token LBRACE RBRACE - -%token LSQUARE RSQUARE -%token LSQUARE_CARET -%token CHAR HYPHEN - -%right QUERY COLON -%left PIPE -%left XOR -%left AND -%left NOT -%left LPAREN RPAREN -%left LANGLE RANGLE - -%% - -all : decl_seq ; - -decl_seq : /* empty */ | decl_seq decl ; - -decl : block_decl - | tokens_decl | abbrev_decl - | attr_decl | group_decl | tag_decl - | prefix_decl | entrystruct_decl ; - -/* Don't invalidate curstate at the end, this is the means of working out the - starting state of the NFA */ -block_decl : block1 block2 { fixup_state_refs(curblock); curblock = NULL; } ; - -block1 : BLOCK STRING LBRACE { curblock = lookup_block($2, CREATE_MUST_NOT_EXIST); addtostate = curstate = NULL; } ; - -block2 : instance_decl_seq state_decl_seq RBRACE ; - -prefix_decl : PREFIX STRING - { if (!prefix) { - prefix = $2; - } else { - fprintf(stderr, "\n\nWarning: prefix declaration ignored; already set on the command line\n"); - } - }; - -tokens_decl : TOKENS token_seq ; - -abbrev_decl : ABBREV STRING EQUAL stimulus_seq - { create_abbrev($2, $4); } - ; - -token_seq : token_seq token | token ; - -token : STRING { (void) lookup_token($1, CREATE_MUST_NOT_EXIST); } ; - -instance_decl_seq : /* empty */ | instance_decl_seq instance_decl ; - -state_decl_seq : /* empty */ | state_decl_seq state_decl ; - -state_decl : STATE STRING { addtostate = curstate = lookup_state(curblock, $2, CREATE_OR_USE_OLD); } - sdecl_seq - | STATE STRING ENTRY STRING { addtostate = curstate = lookup_state(curblock, $2, CREATE_OR_USE_OLD); - add_entry_to_state(curstate, $4); } - sdecl_seq - ; - -sdecl_seq : /* empty */ | sdecl_seq sdecl ; - -sdecl : transition_decl ; - -instance_decl : STRING COLON STRING { instantiate_block(curblock, $3 /* master_block_name */, $1 /* instance_name */ ); } ; - -transition_decl : transition_seq ARROW { curtranslist = $1; } destination_seq { addtostate = curstate; } - | transition_seq EQUAL tag_seq { addtostate = add_transitions_to_internal(curblock, addtostate, $1); - add_tags(addtostate, $3); - addtostate = curstate; } - ; - -destination_seq : STRING { add_transitions(curblock, addtostate, curtranslist, $1); } - | destination_seq COMMA STRING { add_transitions(curblock, addtostate, curtranslist, $3); } - ; - -transition_seq : stimulus_seq { $$ = $1; } - | transition_seq SEMICOLON stimulus_seq - { - addtostate = add_transitions_to_internal(curblock, addtostate, $1); - $$ = $3; - } - ; - -tag_seq : STRING { $$ = add_string_to_list(NULL, $1); } - | tag_seq COMMA STRING { $$ = add_string_to_list($1, $3); } - ; - -stimulus_seq : stimulus - { $$ = append_stimulus_to_list(NULL, $1); } - | stimulus_seq PIPE stimulus - { $$ = append_stimulus_to_list($1, $3); } - ; - -/* A 'thing' that will make the DFA move from one state to another */ -stimulus : STRING - { $$ = stimulus_from_string($1); } - | inline_block - { $$ = stimulus_from_inline_block($1); } - | char_class - { add_charclass_to_list($1); /* freeze it into the list. */ - $$ = stimulus_from_char_class($1); } - | /* empty */ - { $$ = stimulus_from_epsilon(); } - ; - -inline_block : LANGLE STRING COLON STRING ARROW STRING RANGLE - { $$ = create_inline_block($2, $4, $6); } - ; - -char_class : simple_char_class - | negated_char_class - | char_class_diff - ; - -negated_char_class : NOT simple_char_class - { invert_charclass($2); $$ = $2; } - ; - -char_class_diff : simple_char_class NOT simple_char_class - { diff_charclasses($1, $3); - free_charclass($3); - $$ = $1; - } - ; - -simple_char_class : LSQUARE { curcharclass = new_charclass(); } - cc_body - RSQUARE { $$ = curcharclass; - curcharclass = NULL; } - | LSQUARE_CARET { curcharclass = new_charclass(); } - cc_body - RSQUARE { $$ = curcharclass; - invert_charclass($$); - curcharclass = NULL; } - ; - -cc_body : CHAR { add_singleton_to_charclass(curcharclass, $1); } - | CHAR HYPHEN CHAR { add_range_to_charclass(curcharclass, $1, $3); } - | cc_body CHAR { add_singleton_to_charclass(curcharclass, $2); } - | cc_body CHAR HYPHEN CHAR { add_range_to_charclass(curcharclass, $2, $4); } - ; - -attr_decl : ATTR simple_attr_seq - | ATTR STRING COLON expr { define_attr(current_evaluator, $2, $4, 0); } - | EARLY ATTR early_attr_seq - | EARLY ATTR STRING COLON expr { define_attr(current_evaluator, $3, $5, 1); } - | DEFATTR STRING { define_defattr(current_evaluator, $2); } - | TYPE STRING { define_type(current_evaluator, $2); } - ; - -simple_attr_seq : STRING - { define_attr(current_evaluator, $1, NULL, 0); } - | simple_attr_seq COMMA STRING - { define_attr(current_evaluator, $3, NULL, 0); } - ; - -early_attr_seq : STRING - { define_attr(current_evaluator, $1, NULL, 1); } - | early_attr_seq COMMA STRING - { define_attr(current_evaluator, $3, NULL, 1); } - ; - -group_decl : GROUP STRING LBRACE { current_evaluator = start_evaluator($2); } - attr_decl_seq - RBRACE { current_evaluator = NULL; } - ; - -attr_decl_seq : /* empty */ - | attr_decl_seq attr_decl - ; - -tag_decl : TAG STRING EQUAL expr { define_tag($2, $4); } - ; - -entrystruct_decl : - ENTRYSTRUCT STRING STRING { define_entrystruct($2, $3); } - ; - -expr : NOT expr { $$ = new_not_expr($2); } - | expr AND expr { $$ = new_and_expr($1, $3); } - | expr PIPE /* OR */ expr { $$ = new_or_expr($1, $3); } - | expr XOR expr { $$ = new_xor_expr($1, $3); } - | expr QUERY expr COLON expr { $$ = new_cond_expr($1, $3, $5); } - | LPAREN expr RPAREN { $$ = $2; } - | STRING { $$ = new_tag_expr($1); } - ; - -/* vim:et -*/ - diff --git a/src/mairix/dfasyn/scan.l b/src/mairix/dfasyn/scan.l @@ -1,111 +0,0 @@ -/********************************************************************** - Lexical analyser definition for input files defining an NFA - *********************************************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2001-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -%{ -#include "dfasyn.h" -#include "parse.h" - -/* yyunput() not used - define this to avoid compiler warnings */ -#define YY_NO_UNPUT - -int lineno = 1; -%} - -%x PASSTHRU -%x STR -%x CHARCLASS - -%% - -STATE|State|state { return STATE; } -ABBREV|Abbrev|abbrev { return ABBREV; } -DEFINE|Define|define { return DEFINE; } -TOKENS|Tokens|tokens { return TOKENS; } -PREFIX|Prefix|prefix { return PREFIX; } -BLOCK|Block|block { return BLOCK; } -TYPE|Type|type { return TYPE; } -ENTRY|Entry|entry { return ENTRY; } -ENTRYSTRUCT { return ENTRYSTRUCT; } -EntryStruct { return ENTRYSTRUCT; } -Entrystruct { return ENTRYSTRUCT; } -entrystruct { return ENTRYSTRUCT; } -ATTR|Attr|attr { return ATTR; } -EARLY|Early|early { return EARLY; } -DEFATTR|DefAttr { return DEFATTR; } -Defattr|defattr { return DEFATTR; } -TAG|Tag|tag { return TAG; } -GROUP|Group|group { return GROUP; } -[A-Za-z0-9_.]+ { yylval.s = new_string(yytext); return STRING; } -\#.*$ { /* strip comments */ } -\-\> { return ARROW; } -= { return EQUAL; } -\| { return PIPE; /* OR */ } -\& { return AND; } -\~ { return NOT; } -\! { return NOT; } -\^ { return XOR; } -\? { return QUERY; } -\: { return COLON; } -\; { return SEMICOLON; } -\( { return LPAREN; } -\) { return RPAREN; } -\{ { return LBRACE; } -\} { return RBRACE; } -\< { return LANGLE; } -\> { return RANGLE; } -\[ { BEGIN CHARCLASS; return LSQUARE; } -\[\^ { BEGIN CHARCLASS; return LSQUARE_CARET; } -\, { return COMMA; } -\n { lineno++; } -[ \t]+ { /* ignore */ } -^\%\{[ \t]*\n { BEGIN PASSTHRU; } -\" { BEGIN STR; } -. { printf("Unmatched input <%s> at line %d\n", yytext, lineno); exit (1); } - -<PASSTHRU>^\%\}[ \t]*\n { BEGIN INITIAL; } -<PASSTHRU>\n { fputs(yytext, yyout); lineno++; } -<PASSTHRU>.+ { fputs(yytext, yyout); } - -<STR>\" { BEGIN INITIAL; } -<STR>[^"]* { yylval.s = new_string(yytext); return STRING; } - -<CHARCLASS>\] { BEGIN INITIAL; return RSQUARE; } -<CHARCLASS>\- { return HYPHEN; } -<CHARCLASS>\\- { yylval.c = '-'; return CHAR; } -<CHARCLASS>\\] { yylval.c = ']'; return CHAR; } -<CHARCLASS>\\^ { yylval.c = '^'; return CHAR; } -<CHARCLASS>\\n { yylval.c = '\n'; return CHAR; } -<CHARCLASS>\\r { yylval.c = '\r'; return CHAR; } -<CHARCLASS>\\f { yylval.c = '\f'; return CHAR; } -<CHARCLASS>\\t { yylval.c = '\t'; return CHAR; } -<CHARCLASS>\\\\ { yylval.c = '\\'; return CHAR; } -<CHARCLASS>\^[@A-Z] { yylval.c = yytext[1] - '@'; return CHAR; } -<CHARCLASS>\\x[0-9a-fA-F][0-9a-fA-F] { unsigned int foo; sscanf(yytext+2,"%x",&foo); yylval.c = (char) foo; return CHAR; } -<CHARCLASS>\\[0-7][0-7][0-7] { unsigned int foo; sscanf(yytext+1,"%o",&foo); yylval.c = (char) foo; return CHAR; } -<CHARCLASS>. { yylval.c = yytext[0]; return CHAR; } - -%{ -/* vim:et -*/ -%} diff --git a/src/mairix/dfasyn/states.c b/src/mairix/dfasyn/states.c @@ -1,303 +0,0 @@ -/*************************************** - Handle state-related stuff - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2000-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "dfasyn.h" - -static void maybe_grow_states(Block *b, int hash)/*{{{*/ -{ - Stateset *ss = b->state_hash + hash; - if (ss->nstates == ss->maxstates) { - ss->maxstates += 8; - ss->states = resize_array(State*, ss->states, ss->maxstates); - } - if (b->nstates == b->maxstates) { - b->maxstates += 32; - b->states = resize_array(State*, b->states, b->maxstates); - } - -} -/*}}}*/ -static unsigned long hashfn(const char *s)/*{{{*/ -{ - unsigned long y = 0UL, v, w, x, k; - const char *t = s; - while (1) { - k = (unsigned long) *(unsigned char *)(t++); - if (!k) break; - v = ~y; - w = y<<13; - x = v>>6; - y = w ^ x; - y += k; - } - y ^= (y>>13); - y &= HASH_MASK; - return y; -} -/*}}}*/ -static State * create_state(Block *b, char *name)/*{{{*/ -{ - State *result; - int hash; - Stateset *ss; - hash = hashfn(name); - maybe_grow_states(b, hash); - ss = b->state_hash + hash; - result = b->states[b->nstates++] = ss->states[ss->nstates++] = new(State); - result->name = new_string(name); - result->parent = b; - result->index = b->nstates - 1; - result->transitions = NULL; - result->tags = NULL; - result->entries = NULL; - result->ordered_trans = NULL; - result->n_transitions = 0; - result->removed = 0; - return result; -} -/*}}}*/ -State * lookup_state(Block *b, char *name, int create)/*{{{*/ -{ - State *found = NULL; - int i; - int hash; - Stateset *ss; - - hash = hashfn(name); - ss = b->state_hash + hash; - - for (i=0; i<ss->nstates; i++) { - if (!strcmp(ss->states[i]->name, name)) { - found = ss->states[i]; - break; - } - } - - switch (create) { - case USE_OLD_MUST_EXIST: - if (!found) { - fprintf(stderr, "Could not find a state '%s' in block '%s' to transition to\n", name, b->name); - exit(1); - } - break; - case CREATE_MUST_NOT_EXIST: - if (found) { - fprintf(stderr, "Warning : already have a state '%s' in block '%s'\n", name, b->name); - } else { - found = create_state(b, name); - } - break; - case CREATE_OR_USE_OLD: - if (!found) { - found = create_state(b, name); - } - break; - } - - return found; -} -/*}}}*/ -void add_entry_to_state(State *curstate, const char *entry_tag)/*{{{*/ -{ - struct Entrylist *new_entries = new(struct Entrylist); - new_entries->entry_name = new_string(entry_tag); - new_entries->state = curstate; - new_entries->next = entries; - entries = new_entries; - curstate->entries = add_string_to_list(curstate->entries, entry_tag); -} -/*}}}*/ -/* ================================================================= */ -static void add_transition(Block *curblock, State *curstate, Stimulus *stimulus, char *destination); -/* ================================================================= */ -Stringlist * add_string_to_list(Stringlist *existing, const char *token)/*{{{*/ -{ - Stringlist *result = new(Stringlist); - if (token) { - result->string = new_string(token); - } else { - result->string = NULL; - } - result->next = existing; - return result; -} -/*}}}*/ -static TransList *new_translist(struct TransList *existing, char *destination)/*{{{*/ -{ - TransList *result; - result = new(TransList); - result->next = existing; - result->ds_name = new_string(destination); - return result; -} -/*}}}*/ -static void add_epsilon_transition(State *curstate, char *destination)/*{{{*/ -{ - TransList *tl = new_translist(curstate->transitions, destination); - tl->type = TT_EPSILON; - curstate->transitions = tl; -} -/*}}}*/ -static void add_token_transition(State *curstate, int token, char *destination)/*{{{*/ -{ - TransList *tl = new_translist(curstate->transitions, destination); - tl->type = TT_TOKEN; - tl->x.token = token; - curstate->transitions = tl; -} -/*}}}*/ -static void add_abbrev_transition(Block *curblock, State *curstate, struct Abbrev *abbrev, char *destination)/*{{{*/ -{ - StimulusList *stimuli; - for (stimuli = abbrev->stimuli; stimuli; stimuli = stimuli->next) { - add_transition(curblock, curstate, stimuli->stimulus, destination); - } -} -/*}}}*/ -static void add_inline_block_transition(Block *curblock, State *curstate, InlineBlock *ib, char *destination)/*{{{*/ -{ - char block_name[1024]; - char input_name[1024]; - char output_name[1024]; - State *output_state; - - sprintf(block_name, "%s#%d", ib->type, curblock->subblockcount++); - instantiate_block(curblock, ib->type, block_name); - sprintf(input_name, "%s.%s", block_name, ib->in); - sprintf(output_name, "%s.%s", block_name, ib->out); - output_state = lookup_state(curblock, output_name, CREATE_OR_USE_OLD); - add_epsilon_transition(curstate, input_name); - add_epsilon_transition(output_state, destination); -} -/*}}}*/ -static void add_char_class_transition(State *curstate, CharClass *cc, char *destination)/*{{{*/ -{ - TransList *tl = new_translist(curstate->transitions, destination); - tl->type = TT_CHARCLASS; - tl->x.char_class = cc; - curstate->transitions = tl; -} -/*}}}*/ -static void add_transition(Block *curblock, State *curstate, Stimulus *stimulus, char *destination)/*{{{*/ -/* Add a single transition to the state. Allow definitions to be - recursive */ -{ - switch (stimulus->type) { - case T_EPSILON: - add_epsilon_transition(curstate, destination); - break; - case T_TOKEN: - add_token_transition(curstate, stimulus->x.token, destination); - break; - case T_ABBREV: - add_abbrev_transition(curblock, curstate, stimulus->x.abbrev, destination); - break; - case T_INLINEBLOCK: - add_inline_block_transition(curblock, curstate, stimulus->x.inline_block, destination); - break; - case T_CHARCLASS: - add_char_class_transition(curstate, stimulus->x.char_class, destination); - break; - } - -} -/*}}}*/ -void add_transitions(Block *curblock, State *curstate, StimulusList *stimuli, char *destination)/*{{{*/ -{ - StimulusList *sl; - for (sl=stimuli; sl; sl=sl->next) { - add_transition(curblock, curstate, sl->stimulus, destination); - } -} -/*}}}*/ -State * add_transitions_to_internal(Block *curblock, State *addtostate, StimulusList *stimuli)/*{{{*/ -{ - char buffer[1024]; - State *result; - sprintf(buffer, "#%d", curblock->subcount++); - result = lookup_state(curblock, buffer, CREATE_MUST_NOT_EXIST); - add_transitions(curblock, addtostate, stimuli, result->name); - return result; -} -/*}}}*/ -void add_tags(State *curstate, Stringlist *sl)/*{{{*/ -{ - if (curstate->tags) { - /* If we already have some, stick them on the end of the new list */ - Stringlist *xsl = sl; - while (xsl->next) xsl = xsl->next; - xsl->next = curstate->tags; - } - curstate->tags = sl; -} -/*}}}*/ -/* ================================================================= */ -void fixup_state_refs(Block *b)/*{{{*/ -{ - int i; - for (i=0; i<b->nstates; i++) { - State *s = b->states[i]; - TransList *tl; - for (tl=s->transitions; tl; tl=tl->next) { - tl->ds_ref = lookup_state(b, tl->ds_name, CREATE_OR_USE_OLD); - } - } -} -/*}}}*/ -/* ================================================================= */ -void expand_charclass_transitions(Block *b)/*{{{*/ -{ - int i; - for (i=0; i<b->nstates; i++) { - State *s = b->states[i]; - TransList *tl; - for (tl=s->transitions; tl; tl=tl->next) { - if (tl->type == TT_CHARCLASS) { - int i, first; - CharClass *cc = tl->x.char_class; - first = 1; - for (i=0; i<256; i++) { - /* Insert separate transitions for each subclass of the charclass */ - if (cc_test_bit(cc->group_bitmap, i)) { - if (first) { - tl->type = TT_TOKEN; - tl->x.token = ntokens + i; - } else { - TransList *ntl = new(TransList); - ntl->next = tl->next; - ntl->ds_name = new_string(tl->ds_name); - ntl->ds_ref = tl->ds_ref; - ntl->type = TT_TOKEN; - ntl->x.token = ntokens + i; - tl->next = ntl; - } - first = 0; - } - } - } - } - } -} -/*}}}*/ -/* ================================================================= */ diff --git a/src/mairix/dfasyn/stimulus.c b/src/mairix/dfasyn/stimulus.c @@ -1,87 +0,0 @@ -/*************************************** - Handle stimulus-related stuff - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "dfasyn.h" - -Stimulus *stimulus_from_epsilon(void)/*{{{*/ -{ - Stimulus *result; - result = new(Stimulus); - result->type = T_EPSILON; - return result; -} -/*}}}*/ -Stimulus *stimulus_from_string(char *str)/*{{{*/ -{ - struct Abbrev *abbrev; - Stimulus *result; - - result = new(Stimulus); - - /* See if an abbrev exists with the name */ - abbrev = lookup_abbrev(str); - - if (abbrev) { - result->type = T_ABBREV; - result->x.abbrev = abbrev; - } else { - /* Token */ - int token; - token = lookup_token(str, USE_OLD_MUST_EXIST); - /* lookup_token will have bombed if it wasn't found. */ - result->type = T_TOKEN; - result->x.token = token; - } - - return result; - -} -/*}}}*/ -Stimulus *stimulus_from_inline_block(InlineBlock *block)/*{{{*/ -{ - Stimulus *result; - result = new(Stimulus); - result->type = T_INLINEBLOCK; - result->x.inline_block = block; - return result; -} -/*}}}*/ -Stimulus *stimulus_from_char_class(CharClass *char_class)/*{{{*/ -{ - Stimulus *result; - result = new(Stimulus); - result->type = T_CHARCLASS; - result->x.char_class = char_class; - return result; -} -/*}}}*/ -StimulusList *append_stimulus_to_list(StimulusList *existing, Stimulus *stim)/*{{{*/ -{ - StimulusList *result; - result = new(StimulusList); - result->next = existing; - result->stimulus = stim; - return result; -} -/*}}}*/ diff --git a/src/mairix/dfasyn/tabcompr.c b/src/mairix/dfasyn/tabcompr.c @@ -1,181 +0,0 @@ -/*************************************** - Routines to compress the DFA transition tables, by identifying where two DFA - states have a lot of transitions the same. - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2001-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "dfasyn.h" - -/* ================================================================= */ -/* Treat 'x' as a set of 16 bit pairs, with field (0..15) specifying - which. Increment the field'th bit pair as a gray code, in the - pattern 00->01->11->10->00 */ - -unsigned long increment(unsigned long x, int field) -{ - int f2 = field + field; - static unsigned char transxor[4] = {1, 2, 2, 1}; - unsigned long g = x >> f2; - unsigned long h = transxor[g&3]; - return x ^ (h<<f2); -} - -/* ================================================================= */ -/* Calculate the number of bits set in an unsigned long. */ - -unsigned long count_bits_set(unsigned long x) -{ - unsigned long y = x; - unsigned long c; - c = 0x55555555UL; - y = ((y>>1) & c) + (y & c); - c = 0x33333333UL; - y = ((y>>2) & c) + (y & c); - y = (y>>4) + y; - c = 0x0f0f0f0fUL; - y &= c; - y = (y>>8) + y; - y = (y>>16) + y; - return y & 0x1f; -} - -/* ================================================================= */ -/* Compute 'signatures' of the transitions out of a particular state. - The signature is given by considering the destination state numbers mod 16, - and counting how many transitions there are in each resulting equivalence - class. The number is encoded using the gray code implied by the increment - fn. */ - -static void -compute_transition_sigs(struct DFA *dfa, int ntokens) -{ - int i, j; - for (i=0; i<dfa->n; i++) { - unsigned long ts = 0UL; /* transition signature */ - for (j=0; j<ntokens; j++) { - unsigned long dest = dfa->s[i]->map[j]; - dest &= 0xf; /* 16 bit pairs in 'ts' */ - ts = increment(ts, dest); - } - dfa->s[i]->transition_sig = ts; - } -} - - -/* ================================================================= */ - -#define REQUIRED_BENEFIT 2 - -static void -find_default_states(struct DFA *dfa, int ntokens) -{ - int i, j, t; - int best_index; - int best_diff; - int trans_count; /* Number of transitions in working state */ - unsigned long tsi; - - for (i=0; i<dfa->n; i++) { - trans_count = 0; - for (t=0; t<ntokens; t++) { - if (dfa->s[i]->map[t] >= 0) trans_count++; - } - - dfa->s[i]->defstate = -1; /* not defaulted */ - best_index = -1; - best_diff = ntokens + 1; /* Worse than any computed value */ - tsi = dfa->s[i]->transition_sig; - for (j=0; j<i; j++) { - unsigned long tsj; - unsigned long sigdiff; - int diffsize; - - if (dfa->s[j]->defstate >= 0) continue; /* Avoid chains of defstates */ - tsj = dfa->s[j]->transition_sig; - - /* This is the heart of the technique : if we xor two vectors of bit - pairs encoded with the gray code above, and count the number of bits - set in the result, we get the sum of absolute differences of the bit - pairs. The number of outgoing transitions that differ between the - states must be _at_least_ this value. It may in fact be much greater - (i.e. we may get 'false matches'). However, this algorithm is a quick - way of filtering most of the useless potential default states out. */ - - sigdiff = tsi ^ tsj; - diffsize = count_bits_set(sigdiff); - if (diffsize >= best_diff) continue; - if (diffsize >= trans_count) continue; /* Else pointless! */ - - /* Otherwise, do an exact check (i.e. see how much false matching we - suffered). */ - diffsize = 0; - for (t=0; t<ntokens; t++) { - if (dfa->s[i]->map[t] != dfa->s[j]->map[t]) { - diffsize++; - } - } - - if (((best_index < 0) || (diffsize < best_diff)) - && - (diffsize < (trans_count - REQUIRED_BENEFIT))) { - best_index = j; - best_diff = diffsize; - } - } - - dfa->s[i]->defstate = best_index; - dfa->s[i]->best_diff = best_diff; - } -} - -/* ================================================================= */ - -void -compress_transition_table(struct DFA *dfa, int ntokens) -{ - compute_transition_sigs(dfa, ntokens); - find_default_states(dfa, ntokens); -} - -/* ================================================================= */ - -#ifdef TEST -int main () { - unsigned long x = 0; - unsigned long x1, x2, x3, x4; - x1 = increment(x, 2); - x2 = increment(x1, 2); - x3 = increment(x2, 2); - x4 = increment(x3, 2); - printf("%d %d %d %d %d\n", x, x1, x2, x3, x4); - - printf("1=%d\n", count_bits_set(0x00000001)); - printf("2=%d\n", count_bits_set(0x00000003)); - printf("3=%d\n", count_bits_set(0x00000007)); - printf("4=%d\n", count_bits_set(0x0000000f)); - printf("4=%d\n", count_bits_set(0xf0000000)); - - return 0; -} -#endif - - diff --git a/src/mairix/dfasyn/tokens.c b/src/mairix/dfasyn/tokens.c @@ -1,85 +0,0 @@ -/*************************************** - Handle token-related stuff - ***************************************/ - -/* - ********************************************************************** - * Copyright (C) Richard P. Curnow 2000-2003,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "dfasyn.h" - -char **toktable=NULL; -int ntokens = 0; -static int maxtokens = 0; -/* ================================================================= */ -static void grow_tokens(void)/*{{{*/ -{ - maxtokens += 32; - toktable = resize_array(char *, toktable, maxtokens); -} -/*}}}*/ -static int create_token(char *name)/*{{{*/ -{ - int result; - if (ntokens == maxtokens) { - grow_tokens(); - } - result = ntokens++; - toktable[result] = new_string(name); - return result; -} -/*}}}*/ -int lookup_token(char *name, int create)/*{{{*/ -{ - int found = -1; - int i; - for (i=0; i<ntokens; i++) { - if (!strcmp(toktable[i], name)) { - found = i; - break; - } - } - - switch (create) { - case USE_OLD_MUST_EXIST: - if (found < 0) { - fprintf(stderr, "Token '%s' was never declared\n", name); - exit(1); - } - break; - case CREATE_MUST_NOT_EXIST: - if (found >= 0) { - fprintf(stderr, "Token '%s' already declared\n", name); - exit(1); - } else { - found = create_token(name); - } - break; - case CREATE_OR_USE_OLD: - if (found < 0) { - found = create_token(name); - } - break; - } - - return found; -} -/*}}}*/ - - diff --git a/src/mairix/dirscan.c b/src/mairix/dirscan.c @@ -1,420 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002,2003,2004,2005,2006,2007 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -/* Traverse a directory tree and find maildirs, then list files in them. */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <ctype.h> -#include <unistd.h> -#include <dirent.h> -#include <assert.h> -#include "mairix.h" - -struct msgpath_array *new_msgpath_array(void)/*{{{*/ -{ - struct msgpath_array *result; - result = new(struct msgpath_array); - result->paths = NULL; - result->type = NULL; - result->n = 0; - result->max = 0; - return result; -} -/*}}}*/ -void free_msgpath_array(struct msgpath_array *x)/*{{{*/ -{ - int i; - if (x->paths) { - for (i=0; i<x->n; i++) { - switch (x->type[i]) { - case MTY_FILE: - free(x->paths[i].src.mpf.path); - break; - case MTY_MBOX: - break; - case MTY_DEAD: - break; - } - } - free(x->type); - free(x->paths); - } - free(x); -} -/*}}}*/ -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; - arr->paths = grow_array(struct msgpath, arr->max, arr->paths); - arr->type = grow_array(enum message_type, arr->max, arr->type); - } - arr->type[arr->n] = MTY_FILE; - arr->paths[arr->n].src.mpf.path = y; - ++arr->n; - return; -} -/*}}}*/ -static void get_maildir_message_paths(char *folder, struct msgpath_array *arr)/*{{{*/ -{ - char *subdir, *fname; - int i; - static char *subdirs[] = {"new", "cur"}; - DIR *d; - struct dirent *de; - int folder_len = strlen(folder); - - /* FIXME : just store mdir-rooted paths in array and have common prefix elsewhere. */ - - subdir = new_array(char, folder_len + 6); - fname = new_array(char, folder_len + 8 + NAME_MAX); - for (i=0; i<2; i++) { - strcpy(subdir, folder); - strcat(subdir, "/"); - strcat(subdir, subdirs[i]); - d = opendir(subdir); - if (d) { - 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); - add_file_to_list(fname, arr); - } - closedir(d); - } - } - free(subdir); - free(fname); - return; -} -/*}}}*/ -int valid_mh_filename_p(const char *x)/*{{{*/ -{ - const char *p; - - if (!*x) return 0; /* Must not be empty */ - p = x; - while (*p) { - if (!isdigit(*p)) { - /* Handle MH folders generated by Evolution, which have '.' on the ends - * of the numerical filenames for the messages. */ - if ((p[0] == '.') && (p[1] == 0)) return 1; - else return 0; - } - p++; - } - return 1; -} -/*}}}*/ -static void get_mh_message_paths(char *folder, struct msgpath_array *arr)/*{{{*/ -{ - char *fname; - DIR *d; - struct dirent *de; - int folder_len = strlen(folder); - - fname = new_array(char, folder_len + 8 + NAME_MAX); - d = opendir(folder); - if (d) { - while ((de = readdir(d))) { - if (!strcmp(de->d_name, ".") || - !strcmp(de->d_name, "..")) { - continue; - } - strcpy(fname, folder); - strcat(fname, "/"); - strcat(fname, de->d_name); - if (valid_mh_filename_p(de->d_name)) { - add_file_to_list(fname, arr); - } - } - closedir(d); - } - free(fname); - return; -} -/*}}}*/ -static int child_stat(const char *base, const char *child, struct stat *sb)/*{{{*/ -{ - int result = 0; - char *scratch; - int len; - - len = strlen(base) + strlen(child) + 2; - scratch = new_array(char, len); - - strcpy(scratch, base); - strcat(scratch, "/"); - strcat(scratch, child); - - result = stat(scratch, sb); - free(scratch); - return result; -} -/*}}}*/ -static int has_child_file(const char *base, const char *child)/*{{{*/ -{ - int result = 0; - int status; - struct stat sb; - - status = child_stat(base, child, &sb); - if ((status >= 0) && S_ISREG(sb.st_mode)) { - result = 1; - } - - return result; -} -/*}}}*/ -static int has_child_dir(const char *base, const char *child)/*{{{*/ -{ - int result = 0; - int status; - struct stat sb; - - status = child_stat(base, child, &sb); - if ((status >= 0) && S_ISDIR(sb.st_mode)) { - result = 1; - } - - return result; -} -/*}}}*/ -static enum traverse_check scrutinize_maildir_entry(int parent_is_maildir, const char *de_name)/*{{{*/ -{ - if (parent_is_maildir) { - /* Process any subdirectory that's not part of this maildir itself. */ - if (!strcmp(de_name, "new") || - !strcmp(de_name, "cur") || - !strcmp(de_name, "tmp")) { - return TRAV_IGNORE; - } else { - return TRAV_PROCESS; - } - } else { - return TRAV_PROCESS; - } -} -/*}}}*/ -static int filter_is_maildir(const char *path, const struct stat *sb)/*{{{*/ -{ - if (S_ISDIR(sb->st_mode)) { - if (has_child_dir(path, "new") && - has_child_dir(path, "tmp") && - has_child_dir(path, "cur")) { - return 1; - } - } - return 0; -} -/*}}}*/ -struct traverse_methods maildir_traverse_methods = {/*{{{*/ - .filter = filter_is_maildir, - .scrutinize = scrutinize_maildir_entry -}; -/*}}}*/ -static enum traverse_check scrutinize_mh_entry(int parent_is_mh, const char *de_name)/*{{{*/ -{ - /* Have to allow sub-folders within a folder until we think of a better - * solution. */ - if (valid_mh_filename_p(de_name)) { - return TRAV_IGNORE; - } else { - return TRAV_PROCESS; - } -} -/*}}}*/ -static int filter_is_mh(const char *path, const struct stat *sb)/*{{{*/ -{ - int result = 0; - if (S_ISDIR(sb->st_mode)) { - /* TODO : find a way of making this more scalable? e.g. if a folder of a - * particular subtype is found once, try that subtype first later, since - * the user presumably uses a consistent MH-subtype (i.e. a single MUA). */ - if (has_child_file(path, ".xmhcache") || - has_child_file(path, ".mh_sequences") || - /* Sylpheed */ - has_child_file(path, ".sylpheed_cache") || - has_child_file(path, ".sylpheed_mark") || - /* claws-mail */ - has_child_file(path, ".claws_cache") || - has_child_file(path, ".claws_mark") || - /* NNML (Gnus) */ - has_child_file(path, ".marks") || - has_child_file(path, ".overview") || - /* Evolution */ - has_child_file(path, "cmeta") || - has_child_file(path, "summary") || - /* Mew */ - has_child_file(path, ".mew-summary") || - /* ezmlm/archive */ - has_child_file(path, "index") - ) { - result = 1; - } - } - return result; -} -/*}}}*/ -struct traverse_methods mh_traverse_methods = {/*{{{*/ - .filter = filter_is_mh, - .scrutinize = scrutinize_mh_entry -}; -/*}}}*/ -#if 0 -static void scan_directory(char *folder_base, char *this_folder, enum folder_type ft, struct msgpath_array *arr)/*{{{*/ -{ - DIR *d; - struct dirent *de; - struct stat sb; - char *fname, *sname; - char *name; - int folder_base_len = strlen(folder_base); - int this_folder_len = strlen(this_folder); - - name = new_array(char, folder_base_len + this_folder_len + 2); - strcpy(name, folder_base); - strcat(name, "/"); - strcat(name, this_folder); - - switch (ft) { - case FT_MAILDIR: - if (looks_like_maildir(folder_base, this_folder)) { - get_maildir_message_paths(folder_base, this_folder, arr); - } - break; - case FT_MH: - get_mh_message_paths(folder_base, this_folder, arr); - break; - default: - break; - } - - fname = new_array(char, strlen(name) + 2 + NAME_MAX); - sname = new_array(char, this_folder_len + 2 + NAME_MAX); - - d = opendir(name); - if (d) { - while ((de = readdir(d))) { - if (!strcmp(de->d_name, ".") || - !strcmp(de->d_name, "..")) { - continue; - } - - strcpy(fname, name); - strcat(fname, "/"); - strcat(fname, de->d_name); - - strcpy(sname, this_folder); - strcat(sname, "/"); - strcat(sname, de->d_name); - - if (stat(fname, &sb) >= 0) { - if (S_ISDIR(sb.st_mode)) { - scan_directory(folder_base, sname, ft, arr); - } - } - } - closedir(d); - } - - free(fname); - free(sname); - free(name); - return; -} -/*}}}*/ -#endif -static int message_compare(const void *a, const void *b)/*{{{*/ -{ - /* FIXME : Is this a sensible way to do this with mbox messages in the picture? */ - struct msgpath *aa = (struct msgpath *) a; - struct msgpath *bb = (struct msgpath *) b; - /* This should only get called on 'file' type messages - TBC! */ - return strcmp(aa->src.mpf.path, bb->src.mpf.path); -} -/*}}}*/ -static void sort_message_list(struct msgpath_array *arr)/*{{{*/ -{ - qsort(arr->paths, arr->n, sizeof(struct msgpath), message_compare); -} -/*}}}*/ -/*{{{ void build_message_list */ -void build_message_list(char *folder_base, char *folders, enum folder_type ft, - struct msgpath_array *msgs, - struct globber_array *omit_globs) -{ - char **raw_paths, **paths; - int n_raw_paths, n_paths, i; - - split_on_colons(folders, &n_raw_paths, &raw_paths); - switch (ft) { - case FT_MAILDIR: - glob_and_expand_paths(folder_base, raw_paths, n_raw_paths, &paths, &n_paths, &maildir_traverse_methods, omit_globs); - for (i=0; i<n_paths; i++) { - get_maildir_message_paths(paths[i], msgs); - } - break; - case FT_MH: - glob_and_expand_paths(folder_base, raw_paths, n_raw_paths, &paths, &n_paths, &mh_traverse_methods, omit_globs); - for (i=0; i<n_paths; i++) { - get_mh_message_paths(paths[i], msgs); - } - break; - default: - assert(0); - break; - } - - if (paths) free(paths); - - sort_message_list(msgs); - return; -} -/*}}}*/ - -#ifdef TEST -int main (int argc, char **argv) -{ - int i; - struct msgpath_array *arr; - - arr = build_message_list("."); - - for (i=0; i<arr->n; i++) { - printf("%08lx %s\n", arr->paths[i].mtime, arr->paths[i].path); - } - - free_msgpath_array(arr); - - return 0; -} -#endif - - diff --git a/src/mairix/dotlock.c b/src/mairix/dotlock.c @@ -1,116 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2005 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "mairix.h" -#include <sys/utsname.h> -#include <sys/types.h> -#include <pwd.h> -#include <unistd.h> - -static char *lock_file_name = NULL; - -/* This locking code was originally written for tdl */ - -void lock_database(char *path, int forced_unlock)/*{{{*/ -{ - struct utsname uu; - struct passwd *pw; - int pid; - int len; - char *tname; - struct stat sb; - FILE *out; - - if (uname(&uu) < 0) { - perror("uname"); - exit(1); - } - pw = getpwuid(getuid()); - if (!pw) { - perror("getpwuid"); - exit(1); - } - pid = getpid(); - len = 1 + strlen(path) + 5; - lock_file_name = new_array(char, len); - sprintf(lock_file_name, "%s.lock", path); - - if (forced_unlock) { - unlock_database(); - forced_unlock = 0; - } - - len += strlen(uu.nodename); - /* add on max width of pid field (allow up to 32 bit pid_t) + 2 '.' chars */ - len += (10 + 2); - tname = new_array(char, len); - sprintf(tname, "%s.%d.%s", lock_file_name, pid, uu.nodename); - out = fopen(tname, "w"); - if (!out) { - fprintf(stderr, "Cannot open lock file %s for writing\n", tname); - exit(1); - } - fprintf(out, "%d,%s,%s\n", pid, uu.nodename, pw->pw_name); - fclose(out); - - if (link(tname, lock_file_name) < 0) { - /* check if link count==2 */ - if (stat(tname, &sb) < 0) { - fprintf(stderr, "Could not stat the lock file\n"); - unlink(tname); - exit(1); - } else { - if (sb.st_nlink != 2) { - FILE *in; - in = fopen(lock_file_name, "r"); - if (in) { - char line[2048]; - fgets(line, sizeof(line), in); - line[strlen(line)-1] = 0; /* strip trailing newline */ - fprintf(stderr, "Database %s appears to be locked by (pid,node,user)=(%s)\n", path, line); - unlink(tname); - exit(1); - } - } else { - /* lock succeeded apparently */ - } - } - } else { - /* lock succeeded apparently */ - } - unlink(tname); - free(tname); - return; -} -/*}}}*/ -void unlock_database(void)/*{{{*/ -{ - if (lock_file_name) unlink(lock_file_name); - return; -} -/*}}}*/ -void unlock_and_exit(int code)/*{{{*/ -{ - unlock_database(); - exit(code); -} -/*}}}*/ diff --git a/src/mairix/dotmairixrc.eg b/src/mairix/dotmairixrc.eg @@ -1,41 +0,0 @@ -####################################################################### -# -# Example ~/.mairixrc file -# -# Any line starting with # is a comment. -# -####################################################################### -# Set this to the directory where your maildir folders live -base=/home/richard/mail - -####################################################################### -# You need to define at least one of maildir, mh and mbox. You probably don't -# need to define all three! You can use >1 line for any of these. - -# Set this to a list of maildir folders within 'base'. 3 dots at the end means -# there are sub-folders within this folder. -maildir=inbox:archive... -maildir=lists... - -# Set this to a list of MH folders within 'base'. 3 dots at the end means -# there are sub-folders within this folder. -mh=mh_archive... - -# Set this to a list of mbox folders within 'base'. -mbox=mboxen/folder1:mboxen/folder2:mboxen/foobar - -####################################################################### -# Set this to the folder within 'base' where you want the search mode -# to write its output. -mfolder=mfolder - -# Set this if you want the format of mfolder to be mh or mbox (the default is -# maildir). -# -# mformat=mh -# mformat=mbox - -####################################################################### -# Set this to the path where the index database file will be kept -database=/home/richard/mail/mairix_database - diff --git a/src/mairix/dumper.c b/src/mairix/dumper.c @@ -1,151 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2004, 2005 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -/* Database dumper */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <assert.h> -#include <sys/mman.h> - -#include "mairix.h" -#include "reader.h" -#include "memmac.h" - -static void dump_token_chain(struct read_db *db, unsigned int n, unsigned int *tok_offsets, unsigned int *enc_offsets) -{ - int i, j, incr; - int on_line; - unsigned char *foo; - printf("%d entries\n", n); - for (i=0; i<n; i++) { - printf("Word %d : <%s>\n", i, db->data + tok_offsets[i]); - foo = (unsigned char *) db->data + enc_offsets[i]; - j = 0; - on_line = 0; - printf(" "); - while (*foo != 0xff) { - if (on_line > 15) { - printf("\n"); - on_line = 0; - } - incr = read_increment(&foo); - j += incr; - printf("%d ", j); - on_line++; - } - printf("\n"); - } -} - -static void dump_toktable(struct read_db *db, struct toktable_db *tbl, const char *title) -{ - printf("Contents of <%s> table\n", title); - dump_token_chain( db, tbl->n, tbl->tok_offsets, tbl->enc_offsets); -} - -static void dump_toktable2(struct read_db *db, struct toktable2_db *tbl, const char *title) -{ - unsigned int n; - n = tbl->n; - printf("Contents of <%s> table\n", title); - printf("Chain 0\n"); - dump_token_chain( db, n, tbl->tok_offsets, tbl->enc0_offsets); - printf("Chain 1\n"); - dump_token_chain( db, n, tbl->tok_offsets, tbl->enc1_offsets); -} - -void dump_database(char *filename) -{ - struct read_db *db; - int i; - - db = open_db(filename); - - printf("Dump of %s\n", filename); - printf("%d messages\n", db->n_msgs); - for (i=0; i<db->n_msgs; i++) { - printf("%6d: ", i); - switch (rd_msg_type(db, i)) { - case DB_MSG_DEAD: - printf("DEAD"); - break; - case DB_MSG_FILE: - printf("FILE %s, size=%d, tid=%d", - db->data + db->path_offsets[i], db->size_table[i], db->tid_table[i]); - break; - case DB_MSG_MBOX: - { - unsigned int mbix, msgix; - decode_mbox_indices(db->path_offsets[i], &mbix, &msgix); - - printf("MBOX %d, msg %d, offset=%d, size=%d, tid=%d", - mbix, msgix, db->mtime_table[i], db->size_table[i], db->tid_table[i]); - } - 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"); - if (db->n_mboxen > 0) { - printf("\nMBOX INFORMATION\n"); - printf("%d mboxen\n", db->n_mboxen); - for (i=0; i<db->n_mboxen; i++) { - if (db->mbox_paths_table[i]) { - printf("%4d: %d msgs in %s\n", i, db->mbox_entries_table[i], db->data + db->mbox_paths_table[i]); - } else { - printf("%4d: dead\n", i); - } - } - printf("\n"); - } - - printf("Hash key %08x\n\n", db->hash_key); - printf("--------------------------------\n"); - dump_toktable(db, &db->to, "To"); - printf("--------------------------------\n"); - dump_toktable(db, &db->cc, "Cc"); - printf("--------------------------------\n"); - dump_toktable(db, &db->from, "From"); - printf("--------------------------------\n"); - dump_toktable(db, &db->subject, "Subject"); - printf("--------------------------------\n"); - dump_toktable(db, &db->body, "Body"); - printf("--------------------------------\n"); - dump_toktable(db, &db->attachment_name, "Attachment names"); - printf("--------------------------------\n"); - dump_toktable2(db, &db->msg_ids, "Message Ids"); - printf("--------------------------------\n"); - - close_db(db); - return; -} - diff --git a/src/mairix/expandstr.c b/src/mairix/expandstr.c @@ -1,196 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2004 - * Copyright (C) Andreas Amann 2010 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "mairix.h" -#include <stdlib.h> -#include <sys/types.h> -#include <pwd.h> -#include <ctype.h> -#include <unistd.h> - -static int isenv(unsigned char x)/*{{{*/ -{ - /* Return true if x is valid as part of an environment variable name. */ - if (isalnum(x)) - return 1; - else if (x == '_') - return 1; - else - return 0; -} -/*}}}*/ -static int home_dir_len(void)/*{{{*/ -{ - struct passwd *foo; - char *lookup; - lookup = getenv("HOME"); - if (lookup) { - return strlen(lookup); - } - foo = getpwuid(getuid()); - return strlen(foo->pw_dir); -} -/*}}}*/ -static char *env_lookup(const char *p, const char *q)/*{{{*/ -{ - char *var; - char *lookup, *result; - char *s; - var = new_array(char, (q-p)+1); - for (s=var; p<q; p++, s++) { - *s = *p; - } - *s = 0; - lookup = getenv(var); - if (lookup) { - result = new_string(lookup); - } else { - result = NULL; - } - free(var); - return result; -} -/*}}}*/ -static int env_lookup_len(const char *p, const char *q) {/*{{{*/ - char *foo; - int len; - foo = env_lookup(p, q); - if (!foo) len = 0; - else { - len = strlen(foo); - free(foo); - } - return len; -} -/*}}}*/ -static int compute_length(const char *p)/*{{{*/ -{ - const char *q; - int first; - int len; - first = 1; - len = 0; - while (*p) { - if (first && (*p == '~') && (p[1] == '/')) { - /* Make no attempt to expand ~other_user form */ - len += home_dir_len(); - p++; - } else if ((*p == '$') && (p[1] == '{')) { - p += 2; - q = p; - while (*q && (*q != '}')) q++; - len += env_lookup_len(p, q); - p = *q ? (q + 1) : q; - } else if (*p == '$') { - p++; - q = p; - while (*q && isenv(*(unsigned char*)q)) q++; - len += env_lookup_len(p, q); - p = q; - } else { - len++; - p++; - } - first = 0; - } - return len; -} -/*}}}*/ -static char *append_home_dir(char *to)/*{{{*/ -{ - struct passwd *foo; - int len; - char *lookup; - lookup = getenv("HOME"); - if (lookup) { - len = strlen(lookup); - strcpy(to, lookup); - } else { - foo = getpwuid(getuid()); - len = strlen(foo->pw_dir); - strcpy(to, foo->pw_dir); - } - return to + len; -} -/*}}}*/ -static char *append_env(char *to, const char *p, const char *q)/*{{{*/ -{ - char *foo; - int len; - foo = env_lookup(p, q); - if (foo) { - len = strlen(foo); - strcpy(to, foo); - free(foo); - } else { - len = 0; - } - return (to + len); -} -/*}}}*/ -static void do_expand(const char *p, char *result)/*{{{*/ -{ - const char *q; - int first; - first = 1; - while (*p) { - if (first && (*p == '~') && (p[1] == '/')) { - result = append_home_dir(result); - p++; - } else if ((*p == '$') && (p[1] == '{')) { - p += 2; - q = p; - while (*q && (*q != '}')) q++; - result = append_env(result, p, q); - p = *q ? (q + 1) : q; - } else if (*p == '$') { - p++; - q = p; - while (*q && isenv(*(unsigned char*)q)) q++; - result = append_env(result, p, q); - p = q; - } else { - *result++ = *p++; - } - first = 0; - } - *result = 0; -} -/*}}}*/ -char *expand_string(const char *p)/*{{{*/ -{ - /* Return a copy of p, but with - - ~ expanded to the user's home directory - $env expanded to the value of that environment variable - */ - - int len; - char *result; - - len = compute_length(p); - result = new_array(char, len+1); - do_expand(p, result); - return result; -} -/*}}}*/ diff --git a/src/mairix/from.h b/src/mairix/from.h @@ -1,32 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002-2004,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#ifndef _FROM_H -#define _FROM_H - -enum fromcheck_result { - FROMCHECK_PASS, - FROMCHECK_FAIL -}; - -#endif - diff --git a/src/mairix/fromcheck.nfa b/src/mairix/fromcheck.nfa @@ -1,218 +0,0 @@ -######################################################################### -# -# mairix - message index builder and finder for maildir folders. -# -# Copyright (C) Richard P. Curnow 2002-2004,2006 -# Copyright (C) Jonathan Kamens 2010 -# -# 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., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# ======================================================================= - -%{ -#include "from.h" -%} - - -# Define tokens -# CR : \n -# DIGIT : [0-9] -# AT : @ -# COLON : : -# WHITE : ' ', \t -# LOWER : [a-z] -# UPPER : [A-Z] -# PLUSMINUS : [+-] -# OTHER_EMAIL : other stuff valid in the LHS of an address -# DOMAIN : stuff valid in the RHS of an address - -Abbrev LF = [\n] -Abbrev CR = [\r] -Abbrev DIGIT = [0-9] -Abbrev PERIOD = [.] -Abbrev AT = [@] -Abbrev LOWER = [a-z] -Abbrev UPPER = [A-Z] -Abbrev COLON = [:] -Abbrev WHITE = [ \t] -Abbrev PLUSMINUS = [+\-] -# Explained clearly at -# http://en.wikipedia.org/wiki/E-mail_address#RFC_specification -Abbrev OTHER_EMAIL = [.!#$%&'*/=?^_`{|}~] -Abbrev LT = [<] -Abbrev GT = [>] -Abbrev EMAIL = LOWER | UPPER | DIGIT | PLUSMINUS | OTHER_EMAIL -Abbrev OTHER_DOMAIN = [\-_.] -Abbrev DOMAIN = LOWER | UPPER | DIGIT | OTHER_DOMAIN -Abbrev DQUOTE = ["] -Abbrev OTHER_QUOTED = [@:<>] -Abbrev LEFTSQUARE = [[] -Abbrev RIGHTSQUARE = [\]] - -BLOCK email { - STATE in - EMAIL -> in, before_at - DQUOTE -> quoted_before_at - AT -> domain_route - - STATE domain_route - DOMAIN -> domain_route - COLON -> in - - STATE quoted_before_at - EMAIL | WHITE | OTHER_QUOTED -> quoted_before_at - DQUOTE -> before_at - - STATE before_at - EMAIL -> before_at - DQUOTE -> quoted_before_at - # Local part only : >=1 characters will suffice, which we've already - # matched. - -> out - AT -> start_of_domain - - STATE start_of_domain - LEFTSQUARE -> dotted_quad - DOMAIN -> after_at - - STATE dotted_quad - DIGIT | PERIOD -> dotted_quad - RIGHTSQUARE -> out - - STATE after_at - DOMAIN -> after_at, out - -} - -BLOCK angled_email { - STATE in - LT -> in_angles - - STATE in_angles - <email:in->out> -> before_gt - - STATE before_gt - GT -> out -} - -BLOCK zone { - # Make this pretty lenient - STATE in - UPPER -> zone2 - UPPER -> out - PLUSMINUS -> zone2 - - STATE zone2 - UPPER | LOWER -> zone2, out - DIGIT -> zone2, out -} - -BLOCK date { - STATE in - WHITE -> in, before_weekday - - STATE before_weekday - UPPER ; LOWER ; LOWER ; WHITE -> after_weekday - - STATE after_weekday - WHITE -> after_weekday - UPPER ; LOWER ; LOWER ; WHITE -> after_month - - STATE after_month - WHITE -> after_month - DIGIT ; WHITE -> after_day - DIGIT ; DIGIT ; WHITE -> after_day - - STATE after_day - WHITE -> after_day - # Accept HH:MM:SS - DIGIT ; DIGIT ; COLON ; DIGIT ; DIGIT ; COLON ; DIGIT ; DIGIT ; WHITE -> after_time - # Accept HH:MM - DIGIT ; DIGIT ; COLON ; DIGIT ; DIGIT ; WHITE -> after_time - - # Allow either 1 or 2 words of timezone - STATE after_time - WHITE -> after_time - -> after_timezone - <zone:in->out> ; WHITE -> after_timezone - <zone:in->out> ; WHITE -> after_timezone_1 - - # It appears that Pine puts the timezone after the year - DIGIT ; DIGIT ; DIGIT ; DIGIT -> after_year_before_zone - - STATE after_year_before_zone - WHITE -> after_year_before_zone - <zone:in->out> -> after_timezone_after_year - <zone:in->out> ; WHITE -> after_timezone_after_year_1 - - STATE after_timezone_after_year_1 - WHITE -> after_timezone_after_year_1 - <zone:in->out> -> after_timezone_after_year - - STATE after_timezone_after_year - WHITE -> after_timezone_after_year - -> out - - STATE after_timezone_1 - WHITE -> after_timezone_1 - <zone:in->out> ; WHITE -> after_timezone - - STATE after_timezone - WHITE -> after_timezone - DIGIT ; DIGIT ; DIGIT ; DIGIT -> after_year - - STATE after_year - WHITE -> after_year - -> out - -} - -# Assume the earlier code has identified the '\nFrom ' sequence, -# and the validator starts scanning from the character beyond the space - -BLOCK main { - - STATE in - # Real return address. - WHITE -> in - <email:in->out> -> before_date - <angled_email:in->out> -> before_date - - # Cope with Mozilla mbox folder format which just uses a '-' as - # the return address field. - PLUSMINUS -> before_date - - # Empty return address - -> before_date - - STATE before_date - <date:in->out> ; LF = FROMCHECK_PASS - - # Cope with mozilla mbox format - <date:in->out> ; CR ; LF = FROMCHECK_PASS - - # Mention this state last : the last mentioned state in the last defined - # block becomes the entry state of the scanner. - - STATE in - -} - -ATTR FROMCHECK_PASS -ATTR FROMCHECK_FAIL -DEFATTR FROMCHECK_FAIL -PREFIX fromcheck -TYPE "enum fromcheck_result" - -# vim:ft=txt:et:sw=4:sts=4:ht=4 diff --git a/src/mairix/fromcheck.report b/src/mairix/fromcheck.report @@ -1,3222 +0,0 @@ -NFA state 0 = in - [(epsilon)] -> before_date - 5:[+] -> before_date - 6:[\055] -> before_date - [(epsilon)] -> angled_email#2.in - [(epsilon)] -> email#1.in - 0:[\t ] -> in - Epsilon closure : - (self) - email#1.in - angled_email#2.in - before_date - date#3.in - date#4.in - -NFA state 1 = email#1.in - 3:[!#-'*/=?^`{-~] -> email#1.in - 16:[_] -> email#1.in - 7:[.] -> email#1.in - 5:[+] -> email#1.in - 6:[\055] -> email#1.in - 8:[0-9] -> email#1.in - 13:[A-Z] -> email#1.in - 17:[a-z] -> email#1.in - 3:[!#-'*/=?^`{-~] -> email#1.before_at - 16:[_] -> email#1.before_at - 7:[.] -> email#1.before_at - 5:[+] -> email#1.before_at - 6:[\055] -> email#1.before_at - 8:[0-9] -> email#1.before_at - 13:[A-Z] -> email#1.before_at - 17:[a-z] -> email#1.before_at - 4:["] -> email#1.quoted_before_at - 12:[@] -> email#1.domain_route - Epsilon closure : - (self) - -NFA state 2 = email#1.domain_route - 6:[\055] -> email#1.domain_route - 16:[_] -> email#1.domain_route - 7:[.] -> email#1.domain_route - 8:[0-9] -> email#1.domain_route - 13:[A-Z] -> email#1.domain_route - 17:[a-z] -> email#1.domain_route - 9:[:] -> email#1.in - Epsilon closure : - (self) - -NFA state 3 = email#1.quoted_before_at - 9:[:] -> email#1.quoted_before_at - 12:[@] -> email#1.quoted_before_at - 11:[>] -> email#1.quoted_before_at - 10:[<] -> email#1.quoted_before_at - 0:[\t ] -> email#1.quoted_before_at - 3:[!#-'*/=?^`{-~] -> email#1.quoted_before_at - 16:[_] -> email#1.quoted_before_at - 7:[.] -> email#1.quoted_before_at - 5:[+] -> email#1.quoted_before_at - 6:[\055] -> email#1.quoted_before_at - 8:[0-9] -> email#1.quoted_before_at - 13:[A-Z] -> email#1.quoted_before_at - 17:[a-z] -> email#1.quoted_before_at - 4:["] -> email#1.before_at - Epsilon closure : - (self) - -NFA state 4 = email#1.before_at - 3:[!#-'*/=?^`{-~] -> email#1.before_at - 16:[_] -> email#1.before_at - 7:[.] -> email#1.before_at - 5:[+] -> email#1.before_at - 6:[\055] -> email#1.before_at - 8:[0-9] -> email#1.before_at - 13:[A-Z] -> email#1.before_at - 17:[a-z] -> email#1.before_at - 4:["] -> email#1.quoted_before_at - [(epsilon)] -> email#1.out - 12:[@] -> email#1.start_of_domain - Epsilon closure : - (self) - email#1.out - before_date - date#3.in - date#4.in - -NFA state 5 = email#1.start_of_domain - 14:[[] -> email#1.dotted_quad - 6:[\055] -> email#1.after_at - 16:[_] -> email#1.after_at - 7:[.] -> email#1.after_at - 8:[0-9] -> email#1.after_at - 13:[A-Z] -> email#1.after_at - 17:[a-z] -> email#1.after_at - Epsilon closure : - (self) - -NFA state 6 = email#1.dotted_quad - 7:[.] -> email#1.dotted_quad - 8:[0-9] -> email#1.dotted_quad - 15:[]] -> email#1.out - Epsilon closure : - (self) - -NFA state 7 = email#1.after_at - 6:[\055] -> email#1.after_at - 16:[_] -> email#1.after_at - 7:[.] -> email#1.after_at - 8:[0-9] -> email#1.after_at - 13:[A-Z] -> email#1.after_at - 17:[a-z] -> email#1.after_at - 6:[\055] -> email#1.out - 16:[_] -> email#1.out - 7:[.] -> email#1.out - 8:[0-9] -> email#1.out - 13:[A-Z] -> email#1.out - 17:[a-z] -> email#1.out - Epsilon closure : - (self) - -NFA state 8 = email#1.out - [(epsilon)] -> before_date - Epsilon closure : - (self) - before_date - date#3.in - date#4.in - -NFA state 9 = angled_email#2.in - 10:[<] -> angled_email#2.in_angles - Epsilon closure : - (self) - -NFA state 10 = angled_email#2.in_angles - [(epsilon)] -> angled_email#2.email#1.in - Epsilon closure : - (self) - angled_email#2.email#1.in - -NFA state 11 = angled_email#2.email#1.in - 12:[@] -> angled_email#2.email#1.domain_route - 4:["] -> angled_email#2.email#1.quoted_before_at - 17:[a-z] -> angled_email#2.email#1.before_at - 13:[A-Z] -> angled_email#2.email#1.before_at - 8:[0-9] -> angled_email#2.email#1.before_at - 5:[+] -> angled_email#2.email#1.before_at - 6:[\055] -> angled_email#2.email#1.before_at - 3:[!#-'*/=?^`{-~] -> angled_email#2.email#1.before_at - 16:[_] -> angled_email#2.email#1.before_at - 7:[.] -> angled_email#2.email#1.before_at - 17:[a-z] -> angled_email#2.email#1.in - 13:[A-Z] -> angled_email#2.email#1.in - 8:[0-9] -> angled_email#2.email#1.in - 5:[+] -> angled_email#2.email#1.in - 6:[\055] -> angled_email#2.email#1.in - 3:[!#-'*/=?^`{-~] -> angled_email#2.email#1.in - 16:[_] -> angled_email#2.email#1.in - 7:[.] -> angled_email#2.email#1.in - Epsilon closure : - (self) - -NFA state 12 = angled_email#2.email#1.domain_route - 9:[:] -> angled_email#2.email#1.in - 17:[a-z] -> angled_email#2.email#1.domain_route - 13:[A-Z] -> angled_email#2.email#1.domain_route - 8:[0-9] -> angled_email#2.email#1.domain_route - 6:[\055] -> angled_email#2.email#1.domain_route - 16:[_] -> angled_email#2.email#1.domain_route - 7:[.] -> angled_email#2.email#1.domain_route - Epsilon closure : - (self) - -NFA state 13 = angled_email#2.email#1.quoted_before_at - 4:["] -> angled_email#2.email#1.before_at - 17:[a-z] -> angled_email#2.email#1.quoted_before_at - 13:[A-Z] -> angled_email#2.email#1.quoted_before_at - 8:[0-9] -> angled_email#2.email#1.quoted_before_at - 5:[+] -> angled_email#2.email#1.quoted_before_at - 6:[\055] -> angled_email#2.email#1.quoted_before_at - 3:[!#-'*/=?^`{-~] -> angled_email#2.email#1.quoted_before_at - 16:[_] -> angled_email#2.email#1.quoted_before_at - 7:[.] -> angled_email#2.email#1.quoted_before_at - 0:[\t ] -> angled_email#2.email#1.quoted_before_at - 9:[:] -> angled_email#2.email#1.quoted_before_at - 12:[@] -> angled_email#2.email#1.quoted_before_at - 11:[>] -> angled_email#2.email#1.quoted_before_at - 10:[<] -> angled_email#2.email#1.quoted_before_at - Epsilon closure : - (self) - -NFA state 14 = angled_email#2.email#1.before_at - 12:[@] -> angled_email#2.email#1.start_of_domain - [(epsilon)] -> angled_email#2.email#1.out - 4:["] -> angled_email#2.email#1.quoted_before_at - 17:[a-z] -> angled_email#2.email#1.before_at - 13:[A-Z] -> angled_email#2.email#1.before_at - 8:[0-9] -> angled_email#2.email#1.before_at - 5:[+] -> angled_email#2.email#1.before_at - 6:[\055] -> angled_email#2.email#1.before_at - 3:[!#-'*/=?^`{-~] -> angled_email#2.email#1.before_at - 16:[_] -> angled_email#2.email#1.before_at - 7:[.] -> angled_email#2.email#1.before_at - Epsilon closure : - (self) - angled_email#2.email#1.out - angled_email#2.before_gt - -NFA state 15 = angled_email#2.email#1.start_of_domain - 17:[a-z] -> angled_email#2.email#1.after_at - 13:[A-Z] -> angled_email#2.email#1.after_at - 8:[0-9] -> angled_email#2.email#1.after_at - 6:[\055] -> angled_email#2.email#1.after_at - 16:[_] -> angled_email#2.email#1.after_at - 7:[.] -> angled_email#2.email#1.after_at - 14:[[] -> angled_email#2.email#1.dotted_quad - Epsilon closure : - (self) - -NFA state 16 = angled_email#2.email#1.dotted_quad - 15:[]] -> angled_email#2.email#1.out - 8:[0-9] -> angled_email#2.email#1.dotted_quad - 7:[.] -> angled_email#2.email#1.dotted_quad - Epsilon closure : - (self) - -NFA state 17 = angled_email#2.email#1.after_at - 17:[a-z] -> angled_email#2.email#1.out - 13:[A-Z] -> angled_email#2.email#1.out - 8:[0-9] -> angled_email#2.email#1.out - 6:[\055] -> angled_email#2.email#1.out - 16:[_] -> angled_email#2.email#1.out - 7:[.] -> angled_email#2.email#1.out - 17:[a-z] -> angled_email#2.email#1.after_at - 13:[A-Z] -> angled_email#2.email#1.after_at - 8:[0-9] -> angled_email#2.email#1.after_at - 6:[\055] -> angled_email#2.email#1.after_at - 16:[_] -> angled_email#2.email#1.after_at - 7:[.] -> angled_email#2.email#1.after_at - Epsilon closure : - (self) - -NFA state 18 = angled_email#2.email#1.out - [(epsilon)] -> angled_email#2.before_gt - Epsilon closure : - (self) - angled_email#2.before_gt - -NFA state 19 = angled_email#2.before_gt - 11:[>] -> angled_email#2.out - Epsilon closure : - (self) - -NFA state 20 = angled_email#2.out - [(epsilon)] -> before_date - Epsilon closure : - (self) - before_date - date#3.in - date#4.in - -NFA state 21 = before_date - [(epsilon)] -> date#4.in - [(epsilon)] -> date#3.in - Epsilon closure : - (self) - date#3.in - date#4.in - -NFA state 22 = #1 - 1:[\n] -> #2 - Epsilon closure : - (self) - -NFA state 23 = date#3.in - 0:[\t ] -> date#3.in - 0:[\t ] -> date#3.before_weekday - Epsilon closure : - (self) - -NFA state 24 = date#3.before_weekday - 13:[A-Z] -> date#3.#1 - Epsilon closure : - (self) - -NFA state 25 = date#3.#1 - 17:[a-z] -> date#3.#2 - Epsilon closure : - (self) - -NFA state 26 = date#3.#2 - 17:[a-z] -> date#3.#3 - Epsilon closure : - (self) - -NFA state 27 = date#3.#3 - 0:[\t ] -> date#3.after_weekday - Epsilon closure : - (self) - -NFA state 28 = date#3.after_weekday - 0:[\t ] -> date#3.after_weekday - 13:[A-Z] -> date#3.#4 - Epsilon closure : - (self) - -NFA state 29 = date#3.#4 - 17:[a-z] -> date#3.#5 - Epsilon closure : - (self) - -NFA state 30 = date#3.#5 - 17:[a-z] -> date#3.#6 - Epsilon closure : - (self) - -NFA state 31 = date#3.#6 - 0:[\t ] -> date#3.after_month - Epsilon closure : - (self) - -NFA state 32 = date#3.after_month - 0:[\t ] -> date#3.after_month - 8:[0-9] -> date#3.#7 - 8:[0-9] -> date#3.#8 - Epsilon closure : - (self) - -NFA state 33 = date#3.#7 - 0:[\t ] -> date#3.after_day - Epsilon closure : - (self) - -NFA state 34 = date#3.#8 - 8:[0-9] -> date#3.#9 - Epsilon closure : - (self) - -NFA state 35 = date#3.#9 - 0:[\t ] -> date#3.after_day - Epsilon closure : - (self) - -NFA state 36 = date#3.after_day - 0:[\t ] -> date#3.after_day - 8:[0-9] -> date#3.#10 - 8:[0-9] -> date#3.#18 - Epsilon closure : - (self) - -NFA state 37 = date#3.#10 - 8:[0-9] -> date#3.#11 - Epsilon closure : - (self) - -NFA state 38 = date#3.#11 - 9:[:] -> date#3.#12 - Epsilon closure : - (self) - -NFA state 39 = date#3.#12 - 8:[0-9] -> date#3.#13 - Epsilon closure : - (self) - -NFA state 40 = date#3.#13 - 8:[0-9] -> date#3.#14 - Epsilon closure : - (self) - -NFA state 41 = date#3.#14 - 9:[:] -> date#3.#15 - Epsilon closure : - (self) - -NFA state 42 = date#3.#15 - 8:[0-9] -> date#3.#16 - Epsilon closure : - (self) - -NFA state 43 = date#3.#16 - 8:[0-9] -> date#3.#17 - Epsilon closure : - (self) - -NFA state 44 = date#3.#17 - 0:[\t ] -> date#3.after_time - Epsilon closure : - (self) - -NFA state 45 = date#3.#18 - 8:[0-9] -> date#3.#19 - Epsilon closure : - (self) - -NFA state 46 = date#3.#19 - 9:[:] -> date#3.#20 - Epsilon closure : - (self) - -NFA state 47 = date#3.#20 - 8:[0-9] -> date#3.#21 - Epsilon closure : - (self) - -NFA state 48 = date#3.#21 - 8:[0-9] -> date#3.#22 - Epsilon closure : - (self) - -NFA state 49 = date#3.#22 - 0:[\t ] -> date#3.after_time - Epsilon closure : - (self) - -NFA state 50 = date#3.after_time - 0:[\t ] -> date#3.after_time - [(epsilon)] -> date#3.after_timezone - [(epsilon)] -> date#3.zone#1.in - [(epsilon)] -> date#3.zone#2.in - 8:[0-9] -> date#3.#25 - Epsilon closure : - (self) - date#3.zone#1.in - date#3.zone#2.in - date#3.after_timezone - -NFA state 51 = date#3.#23 - 0:[\t ] -> date#3.after_timezone - Epsilon closure : - (self) - -NFA state 52 = date#3.zone#1.in - 5:[+] -> date#3.zone#1.zone2 - 6:[\055] -> date#3.zone#1.zone2 - 13:[A-Z] -> date#3.zone#1.out - 13:[A-Z] -> date#3.zone#1.zone2 - Epsilon closure : - (self) - -NFA state 53 = date#3.zone#1.zone2 - 8:[0-9] -> date#3.zone#1.out - 8:[0-9] -> date#3.zone#1.zone2 - 13:[A-Z] -> date#3.zone#1.out - 17:[a-z] -> date#3.zone#1.out - 13:[A-Z] -> date#3.zone#1.zone2 - 17:[a-z] -> date#3.zone#1.zone2 - Epsilon closure : - (self) - -NFA state 54 = date#3.zone#1.out - [(epsilon)] -> date#3.#23 - Epsilon closure : - (self) - date#3.#23 - -NFA state 55 = date#3.#24 - 0:[\t ] -> date#3.after_timezone_1 - Epsilon closure : - (self) - -NFA state 56 = date#3.zone#2.in - 5:[+] -> date#3.zone#2.zone2 - 6:[\055] -> date#3.zone#2.zone2 - 13:[A-Z] -> date#3.zone#2.out - 13:[A-Z] -> date#3.zone#2.zone2 - Epsilon closure : - (self) - -NFA state 57 = date#3.zone#2.zone2 - 8:[0-9] -> date#3.zone#2.out - 8:[0-9] -> date#3.zone#2.zone2 - 13:[A-Z] -> date#3.zone#2.out - 17:[a-z] -> date#3.zone#2.out - 13:[A-Z] -> date#3.zone#2.zone2 - 17:[a-z] -> date#3.zone#2.zone2 - Epsilon closure : - (self) - -NFA state 58 = date#3.zone#2.out - [(epsilon)] -> date#3.#24 - Epsilon closure : - (self) - date#3.#24 - -NFA state 59 = date#3.#25 - 8:[0-9] -> date#3.#26 - Epsilon closure : - (self) - -NFA state 60 = date#3.#26 - 8:[0-9] -> date#3.#27 - Epsilon closure : - (self) - -NFA state 61 = date#3.#27 - 8:[0-9] -> date#3.after_year_before_zone - Epsilon closure : - (self) - -NFA state 62 = date#3.after_year_before_zone - 0:[\t ] -> date#3.after_year_before_zone - [(epsilon)] -> date#3.zone#3.in - [(epsilon)] -> date#3.zone#4.in - Epsilon closure : - (self) - date#3.zone#3.in - date#3.zone#4.in - -NFA state 63 = date#3.zone#3.in - 5:[+] -> date#3.zone#3.zone2 - 6:[\055] -> date#3.zone#3.zone2 - 13:[A-Z] -> date#3.zone#3.out - 13:[A-Z] -> date#3.zone#3.zone2 - Epsilon closure : - (self) - -NFA state 64 = date#3.zone#3.zone2 - 8:[0-9] -> date#3.zone#3.out - 8:[0-9] -> date#3.zone#3.zone2 - 13:[A-Z] -> date#3.zone#3.out - 17:[a-z] -> date#3.zone#3.out - 13:[A-Z] -> date#3.zone#3.zone2 - 17:[a-z] -> date#3.zone#3.zone2 - Epsilon closure : - (self) - -NFA state 65 = date#3.zone#3.out - [(epsilon)] -> date#3.after_timezone_after_year - Epsilon closure : - (self) - #1 - date#3.after_timezone_after_year - date#3.out - -NFA state 66 = date#3.#28 - 0:[\t ] -> date#3.after_timezone_after_year_1 - Epsilon closure : - (self) - -NFA state 67 = date#3.zone#4.in - 5:[+] -> date#3.zone#4.zone2 - 6:[\055] -> date#3.zone#4.zone2 - 13:[A-Z] -> date#3.zone#4.out - 13:[A-Z] -> date#3.zone#4.zone2 - Epsilon closure : - (self) - -NFA state 68 = date#3.zone#4.zone2 - 8:[0-9] -> date#3.zone#4.out - 8:[0-9] -> date#3.zone#4.zone2 - 13:[A-Z] -> date#3.zone#4.out - 17:[a-z] -> date#3.zone#4.out - 13:[A-Z] -> date#3.zone#4.zone2 - 17:[a-z] -> date#3.zone#4.zone2 - Epsilon closure : - (self) - -NFA state 69 = date#3.zone#4.out - [(epsilon)] -> date#3.#28 - Epsilon closure : - (self) - date#3.#28 - -NFA state 70 = date#3.after_timezone_after_year_1 - 0:[\t ] -> date#3.after_timezone_after_year_1 - [(epsilon)] -> date#3.zone#5.in - Epsilon closure : - (self) - date#3.zone#5.in - -NFA state 71 = date#3.zone#5.in - 5:[+] -> date#3.zone#5.zone2 - 6:[\055] -> date#3.zone#5.zone2 - 13:[A-Z] -> date#3.zone#5.out - 13:[A-Z] -> date#3.zone#5.zone2 - Epsilon closure : - (self) - -NFA state 72 = date#3.zone#5.zone2 - 8:[0-9] -> date#3.zone#5.out - 8:[0-9] -> date#3.zone#5.zone2 - 13:[A-Z] -> date#3.zone#5.out - 17:[a-z] -> date#3.zone#5.out - 13:[A-Z] -> date#3.zone#5.zone2 - 17:[a-z] -> date#3.zone#5.zone2 - Epsilon closure : - (self) - -NFA state 73 = date#3.zone#5.out - [(epsilon)] -> date#3.after_timezone_after_year - Epsilon closure : - (self) - #1 - date#3.after_timezone_after_year - date#3.out - -NFA state 74 = date#3.after_timezone_after_year - 0:[\t ] -> date#3.after_timezone_after_year - [(epsilon)] -> date#3.out - Epsilon closure : - (self) - #1 - date#3.out - -NFA state 75 = date#3.after_timezone_1 - 0:[\t ] -> date#3.after_timezone_1 - [(epsilon)] -> date#3.zone#6.in - Epsilon closure : - (self) - date#3.zone#6.in - -NFA state 76 = date#3.#29 - 0:[\t ] -> date#3.after_timezone - Epsilon closure : - (self) - -NFA state 77 = date#3.zone#6.in - 5:[+] -> date#3.zone#6.zone2 - 6:[\055] -> date#3.zone#6.zone2 - 13:[A-Z] -> date#3.zone#6.out - 13:[A-Z] -> date#3.zone#6.zone2 - Epsilon closure : - (self) - -NFA state 78 = date#3.zone#6.zone2 - 8:[0-9] -> date#3.zone#6.out - 8:[0-9] -> date#3.zone#6.zone2 - 13:[A-Z] -> date#3.zone#6.out - 17:[a-z] -> date#3.zone#6.out - 13:[A-Z] -> date#3.zone#6.zone2 - 17:[a-z] -> date#3.zone#6.zone2 - Epsilon closure : - (self) - -NFA state 79 = date#3.zone#6.out - [(epsilon)] -> date#3.#29 - Epsilon closure : - (self) - date#3.#29 - -NFA state 80 = date#3.after_timezone - 0:[\t ] -> date#3.after_timezone - 8:[0-9] -> date#3.#30 - Epsilon closure : - (self) - -NFA state 81 = date#3.#30 - 8:[0-9] -> date#3.#31 - Epsilon closure : - (self) - -NFA state 82 = date#3.#31 - 8:[0-9] -> date#3.#32 - Epsilon closure : - (self) - -NFA state 83 = date#3.#32 - 8:[0-9] -> date#3.after_year - Epsilon closure : - (self) - -NFA state 84 = date#3.after_year - 0:[\t ] -> date#3.after_year - [(epsilon)] -> date#3.out - Epsilon closure : - (self) - #1 - date#3.out - -NFA state 85 = date#3.out - [(epsilon)] -> #1 - Epsilon closure : - (self) - #1 - -NFA state 86 = #2 - Tags : FROMCHECK_PASS - Epsilon closure : - (self) - -NFA state 87 = #3 - 2:[\r] -> #4 - Epsilon closure : - (self) - -NFA state 88 = date#4.in - 0:[\t ] -> date#4.in - 0:[\t ] -> date#4.before_weekday - Epsilon closure : - (self) - -NFA state 89 = date#4.before_weekday - 13:[A-Z] -> date#4.#1 - Epsilon closure : - (self) - -NFA state 90 = date#4.#1 - 17:[a-z] -> date#4.#2 - Epsilon closure : - (self) - -NFA state 91 = date#4.#2 - 17:[a-z] -> date#4.#3 - Epsilon closure : - (self) - -NFA state 92 = date#4.#3 - 0:[\t ] -> date#4.after_weekday - Epsilon closure : - (self) - -NFA state 93 = date#4.after_weekday - 0:[\t ] -> date#4.after_weekday - 13:[A-Z] -> date#4.#4 - Epsilon closure : - (self) - -NFA state 94 = date#4.#4 - 17:[a-z] -> date#4.#5 - Epsilon closure : - (self) - -NFA state 95 = date#4.#5 - 17:[a-z] -> date#4.#6 - Epsilon closure : - (self) - -NFA state 96 = date#4.#6 - 0:[\t ] -> date#4.after_month - Epsilon closure : - (self) - -NFA state 97 = date#4.after_month - 0:[\t ] -> date#4.after_month - 8:[0-9] -> date#4.#7 - 8:[0-9] -> date#4.#8 - Epsilon closure : - (self) - -NFA state 98 = date#4.#7 - 0:[\t ] -> date#4.after_day - Epsilon closure : - (self) - -NFA state 99 = date#4.#8 - 8:[0-9] -> date#4.#9 - Epsilon closure : - (self) - -NFA state 100 = date#4.#9 - 0:[\t ] -> date#4.after_day - Epsilon closure : - (self) - -NFA state 101 = date#4.after_day - 0:[\t ] -> date#4.after_day - 8:[0-9] -> date#4.#10 - 8:[0-9] -> date#4.#18 - Epsilon closure : - (self) - -NFA state 102 = date#4.#10 - 8:[0-9] -> date#4.#11 - Epsilon closure : - (self) - -NFA state 103 = date#4.#11 - 9:[:] -> date#4.#12 - Epsilon closure : - (self) - -NFA state 104 = date#4.#12 - 8:[0-9] -> date#4.#13 - Epsilon closure : - (self) - -NFA state 105 = date#4.#13 - 8:[0-9] -> date#4.#14 - Epsilon closure : - (self) - -NFA state 106 = date#4.#14 - 9:[:] -> date#4.#15 - Epsilon closure : - (self) - -NFA state 107 = date#4.#15 - 8:[0-9] -> date#4.#16 - Epsilon closure : - (self) - -NFA state 108 = date#4.#16 - 8:[0-9] -> date#4.#17 - Epsilon closure : - (self) - -NFA state 109 = date#4.#17 - 0:[\t ] -> date#4.after_time - Epsilon closure : - (self) - -NFA state 110 = date#4.#18 - 8:[0-9] -> date#4.#19 - Epsilon closure : - (self) - -NFA state 111 = date#4.#19 - 9:[:] -> date#4.#20 - Epsilon closure : - (self) - -NFA state 112 = date#4.#20 - 8:[0-9] -> date#4.#21 - Epsilon closure : - (self) - -NFA state 113 = date#4.#21 - 8:[0-9] -> date#4.#22 - Epsilon closure : - (self) - -NFA state 114 = date#4.#22 - 0:[\t ] -> date#4.after_time - Epsilon closure : - (self) - -NFA state 115 = date#4.after_time - 0:[\t ] -> date#4.after_time - [(epsilon)] -> date#4.after_timezone - [(epsilon)] -> date#4.zone#1.in - [(epsilon)] -> date#4.zone#2.in - 8:[0-9] -> date#4.#25 - Epsilon closure : - (self) - date#4.zone#1.in - date#4.zone#2.in - date#4.after_timezone - -NFA state 116 = date#4.#23 - 0:[\t ] -> date#4.after_timezone - Epsilon closure : - (self) - -NFA state 117 = date#4.zone#1.in - 5:[+] -> date#4.zone#1.zone2 - 6:[\055] -> date#4.zone#1.zone2 - 13:[A-Z] -> date#4.zone#1.out - 13:[A-Z] -> date#4.zone#1.zone2 - Epsilon closure : - (self) - -NFA state 118 = date#4.zone#1.zone2 - 8:[0-9] -> date#4.zone#1.out - 8:[0-9] -> date#4.zone#1.zone2 - 13:[A-Z] -> date#4.zone#1.out - 17:[a-z] -> date#4.zone#1.out - 13:[A-Z] -> date#4.zone#1.zone2 - 17:[a-z] -> date#4.zone#1.zone2 - Epsilon closure : - (self) - -NFA state 119 = date#4.zone#1.out - [(epsilon)] -> date#4.#23 - Epsilon closure : - (self) - date#4.#23 - -NFA state 120 = date#4.#24 - 0:[\t ] -> date#4.after_timezone_1 - Epsilon closure : - (self) - -NFA state 121 = date#4.zone#2.in - 5:[+] -> date#4.zone#2.zone2 - 6:[\055] -> date#4.zone#2.zone2 - 13:[A-Z] -> date#4.zone#2.out - 13:[A-Z] -> date#4.zone#2.zone2 - Epsilon closure : - (self) - -NFA state 122 = date#4.zone#2.zone2 - 8:[0-9] -> date#4.zone#2.out - 8:[0-9] -> date#4.zone#2.zone2 - 13:[A-Z] -> date#4.zone#2.out - 17:[a-z] -> date#4.zone#2.out - 13:[A-Z] -> date#4.zone#2.zone2 - 17:[a-z] -> date#4.zone#2.zone2 - Epsilon closure : - (self) - -NFA state 123 = date#4.zone#2.out - [(epsilon)] -> date#4.#24 - Epsilon closure : - (self) - date#4.#24 - -NFA state 124 = date#4.#25 - 8:[0-9] -> date#4.#26 - Epsilon closure : - (self) - -NFA state 125 = date#4.#26 - 8:[0-9] -> date#4.#27 - Epsilon closure : - (self) - -NFA state 126 = date#4.#27 - 8:[0-9] -> date#4.after_year_before_zone - Epsilon closure : - (self) - -NFA state 127 = date#4.after_year_before_zone - 0:[\t ] -> date#4.after_year_before_zone - [(epsilon)] -> date#4.zone#3.in - [(epsilon)] -> date#4.zone#4.in - Epsilon closure : - (self) - date#4.zone#3.in - date#4.zone#4.in - -NFA state 128 = date#4.zone#3.in - 5:[+] -> date#4.zone#3.zone2 - 6:[\055] -> date#4.zone#3.zone2 - 13:[A-Z] -> date#4.zone#3.out - 13:[A-Z] -> date#4.zone#3.zone2 - Epsilon closure : - (self) - -NFA state 129 = date#4.zone#3.zone2 - 8:[0-9] -> date#4.zone#3.out - 8:[0-9] -> date#4.zone#3.zone2 - 13:[A-Z] -> date#4.zone#3.out - 17:[a-z] -> date#4.zone#3.out - 13:[A-Z] -> date#4.zone#3.zone2 - 17:[a-z] -> date#4.zone#3.zone2 - Epsilon closure : - (self) - -NFA state 130 = date#4.zone#3.out - [(epsilon)] -> date#4.after_timezone_after_year - Epsilon closure : - (self) - #3 - date#4.after_timezone_after_year - date#4.out - -NFA state 131 = date#4.#28 - 0:[\t ] -> date#4.after_timezone_after_year_1 - Epsilon closure : - (self) - -NFA state 132 = date#4.zone#4.in - 5:[+] -> date#4.zone#4.zone2 - 6:[\055] -> date#4.zone#4.zone2 - 13:[A-Z] -> date#4.zone#4.out - 13:[A-Z] -> date#4.zone#4.zone2 - Epsilon closure : - (self) - -NFA state 133 = date#4.zone#4.zone2 - 8:[0-9] -> date#4.zone#4.out - 8:[0-9] -> date#4.zone#4.zone2 - 13:[A-Z] -> date#4.zone#4.out - 17:[a-z] -> date#4.zone#4.out - 13:[A-Z] -> date#4.zone#4.zone2 - 17:[a-z] -> date#4.zone#4.zone2 - Epsilon closure : - (self) - -NFA state 134 = date#4.zone#4.out - [(epsilon)] -> date#4.#28 - Epsilon closure : - (self) - date#4.#28 - -NFA state 135 = date#4.after_timezone_after_year_1 - 0:[\t ] -> date#4.after_timezone_after_year_1 - [(epsilon)] -> date#4.zone#5.in - Epsilon closure : - (self) - date#4.zone#5.in - -NFA state 136 = date#4.zone#5.in - 5:[+] -> date#4.zone#5.zone2 - 6:[\055] -> date#4.zone#5.zone2 - 13:[A-Z] -> date#4.zone#5.out - 13:[A-Z] -> date#4.zone#5.zone2 - Epsilon closure : - (self) - -NFA state 137 = date#4.zone#5.zone2 - 8:[0-9] -> date#4.zone#5.out - 8:[0-9] -> date#4.zone#5.zone2 - 13:[A-Z] -> date#4.zone#5.out - 17:[a-z] -> date#4.zone#5.out - 13:[A-Z] -> date#4.zone#5.zone2 - 17:[a-z] -> date#4.zone#5.zone2 - Epsilon closure : - (self) - -NFA state 138 = date#4.zone#5.out - [(epsilon)] -> date#4.after_timezone_after_year - Epsilon closure : - (self) - #3 - date#4.after_timezone_after_year - date#4.out - -NFA state 139 = date#4.after_timezone_after_year - 0:[\t ] -> date#4.after_timezone_after_year - [(epsilon)] -> date#4.out - Epsilon closure : - (self) - #3 - date#4.out - -NFA state 140 = date#4.after_timezone_1 - 0:[\t ] -> date#4.after_timezone_1 - [(epsilon)] -> date#4.zone#6.in - Epsilon closure : - (self) - date#4.zone#6.in - -NFA state 141 = date#4.#29 - 0:[\t ] -> date#4.after_timezone - Epsilon closure : - (self) - -NFA state 142 = date#4.zone#6.in - 5:[+] -> date#4.zone#6.zone2 - 6:[\055] -> date#4.zone#6.zone2 - 13:[A-Z] -> date#4.zone#6.out - 13:[A-Z] -> date#4.zone#6.zone2 - Epsilon closure : - (self) - -NFA state 143 = date#4.zone#6.zone2 - 8:[0-9] -> date#4.zone#6.out - 8:[0-9] -> date#4.zone#6.zone2 - 13:[A-Z] -> date#4.zone#6.out - 17:[a-z] -> date#4.zone#6.out - 13:[A-Z] -> date#4.zone#6.zone2 - 17:[a-z] -> date#4.zone#6.zone2 - Epsilon closure : - (self) - -NFA state 144 = date#4.zone#6.out - [(epsilon)] -> date#4.#29 - Epsilon closure : - (self) - date#4.#29 - -NFA state 145 = date#4.after_timezone - 0:[\t ] -> date#4.after_timezone - 8:[0-9] -> date#4.#30 - Epsilon closure : - (self) - -NFA state 146 = date#4.#30 - 8:[0-9] -> date#4.#31 - Epsilon closure : - (self) - -NFA state 147 = date#4.#31 - 8:[0-9] -> date#4.#32 - Epsilon closure : - (self) - -NFA state 148 = date#4.#32 - 8:[0-9] -> date#4.after_year - Epsilon closure : - (self) - -NFA state 149 = date#4.after_year - 0:[\t ] -> date#4.after_year - [(epsilon)] -> date#4.out - Epsilon closure : - (self) - #3 - date#4.out - -NFA state 150 = date#4.out - [(epsilon)] -> #3 - Epsilon closure : - (self) - #3 - -NFA state 151 = #4 - 1:[\n] -> #5 - Epsilon closure : - (self) - -NFA state 152 = #5 - Tags : FROMCHECK_PASS - Epsilon closure : - (self) - --------------------------------- -DFA structure before compression --------------------------------- -DFA state 0 - NFA states : - in - email#1.in - angled_email#2.in - before_date - date#3.in - date#4.in - - Forward route : - (START)->(HERE) - Transitions : - 0:[\t ] -> 1 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 10:[<] -> 4 - 12:[@] -> 5 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 2 - -DFA state 1 - NFA states : - in - email#1.in - angled_email#2.in - before_date - date#3.in - date#3.before_weekday - date#4.in - date#4.before_weekday - - Forward route : (from state 0) - (START)->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 1 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 10:[<] -> 4 - 12:[@] -> 5 - 13:[A-Z] -> 6 - 16:[_] -> 2 - 17:[a-z] -> 2 - -DFA state 2 - NFA states : - email#1.in - email#1.before_at - email#1.out - before_date - date#3.in - date#4.in - - Forward route : (from state 0) - (START)->3:[!#-'*/=?^`{-~]->(HERE) - Transitions : - 0:[\t ] -> 7 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 12:[@] -> 8 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 2 - -DFA state 3 - NFA states : - email#1.quoted_before_at - - Forward route : (from state 0) - (START)->4:["]->(HERE) - Transitions : - 0:[\t ] -> 3 - 3:[!#-'*/=?^`{-~] -> 3 - 4:["] -> 9 - 5:[+] -> 3 - 6:[\055] -> 3 - 7:[.] -> 3 - 8:[0-9] -> 3 - 9:[:] -> 3 - 10:[<] -> 3 - 11:[>] -> 3 - 12:[@] -> 3 - 13:[A-Z] -> 3 - 16:[_] -> 3 - 17:[a-z] -> 3 - -DFA state 4 - NFA states : - angled_email#2.in_angles - angled_email#2.email#1.in - - Forward route : (from state 0) - (START)->10:[<]->(HERE) - Transitions : - 3:[!#-'*/=?^`{-~] -> 10 - 4:["] -> 11 - 5:[+] -> 10 - 6:[\055] -> 10 - 7:[.] -> 10 - 8:[0-9] -> 10 - 12:[@] -> 12 - 13:[A-Z] -> 10 - 16:[_] -> 10 - 17:[a-z] -> 10 - -DFA state 5 - NFA states : - email#1.domain_route - - Forward route : (from state 0) - (START)->12:[@]->(HERE) - Transitions : - 6:[\055] -> 5 - 7:[.] -> 5 - 8:[0-9] -> 5 - 9:[:] -> 13 - 13:[A-Z] -> 5 - 16:[_] -> 5 - 17:[a-z] -> 5 - -DFA state 6 - NFA states : - email#1.in - email#1.before_at - email#1.out - before_date - date#3.in - date#3.#1 - date#4.in - date#4.#1 - - Forward route : (from state 1) - (START)->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 0:[\t ] -> 7 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 12:[@] -> 8 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 14 - -DFA state 7 - NFA states : - date#3.in - date#3.before_weekday - date#4.in - date#4.before_weekday - - Forward route : (from state 2) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 7 - 13:[A-Z] -> 15 - -DFA state 8 - NFA states : - email#1.domain_route - email#1.start_of_domain - - Forward route : (from state 2) - (START)->3:[!#-'*/=?^`{-~]->12:[@]->(HERE) - Transitions : - 6:[\055] -> 16 - 7:[.] -> 16 - 8:[0-9] -> 16 - 9:[:] -> 13 - 13:[A-Z] -> 16 - 14:[[] -> 17 - 16:[_] -> 16 - 17:[a-z] -> 16 - -DFA state 9 - NFA states : - email#1.before_at - email#1.out - before_date - date#3.in - date#4.in - - Forward route : (from state 3) - (START)->4:["]->4:["]->(HERE) - Transitions : - 0:[\t ] -> 7 - 3:[!#-'*/=?^`{-~] -> 9 - 4:["] -> 3 - 5:[+] -> 9 - 6:[\055] -> 9 - 7:[.] -> 9 - 8:[0-9] -> 9 - 12:[@] -> 18 - 13:[A-Z] -> 9 - 16:[_] -> 9 - 17:[a-z] -> 9 - -DFA state 10 - NFA states : - angled_email#2.email#1.in - angled_email#2.email#1.before_at - angled_email#2.email#1.out - angled_email#2.before_gt - - Forward route : (from state 4) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->(HERE) - Transitions : - 3:[!#-'*/=?^`{-~] -> 10 - 4:["] -> 11 - 5:[+] -> 10 - 6:[\055] -> 10 - 7:[.] -> 10 - 8:[0-9] -> 10 - 11:[>] -> 19 - 12:[@] -> 20 - 13:[A-Z] -> 10 - 16:[_] -> 10 - 17:[a-z] -> 10 - -DFA state 11 - NFA states : - angled_email#2.email#1.quoted_before_at - - Forward route : (from state 4) - (START)->10:[<]->4:["]->(HERE) - Transitions : - 0:[\t ] -> 11 - 3:[!#-'*/=?^`{-~] -> 11 - 4:["] -> 21 - 5:[+] -> 11 - 6:[\055] -> 11 - 7:[.] -> 11 - 8:[0-9] -> 11 - 9:[:] -> 11 - 10:[<] -> 11 - 11:[>] -> 11 - 12:[@] -> 11 - 13:[A-Z] -> 11 - 16:[_] -> 11 - 17:[a-z] -> 11 - -DFA state 12 - NFA states : - angled_email#2.email#1.domain_route - - Forward route : (from state 4) - (START)->10:[<]->12:[@]->(HERE) - Transitions : - 6:[\055] -> 12 - 7:[.] -> 12 - 8:[0-9] -> 12 - 9:[:] -> 22 - 13:[A-Z] -> 12 - 16:[_] -> 12 - 17:[a-z] -> 12 - -DFA state 13 - NFA states : - email#1.in - - Forward route : (from state 5) - (START)->12:[@]->9:[:]->(HERE) - Transitions : - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 12:[@] -> 5 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 2 - -DFA state 14 - NFA states : - email#1.in - email#1.before_at - email#1.out - before_date - date#3.in - date#3.#2 - date#4.in - date#4.#2 - - Forward route : (from state 6) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->(HERE) - Transitions : - 0:[\t ] -> 7 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 12:[@] -> 8 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 23 - -DFA state 15 - NFA states : - date#3.#1 - date#4.#1 - - Forward route : (from state 7) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 17:[a-z] -> 24 - -DFA state 16 - NFA states : - email#1.domain_route - email#1.after_at - - Forward route : (from state 8) - (START)->3:[!#-'*/=?^`{-~]->12:[@]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 25 - 7:[.] -> 25 - 8:[0-9] -> 25 - 9:[:] -> 13 - 13:[A-Z] -> 25 - 16:[_] -> 25 - 17:[a-z] -> 25 - -DFA state 17 - NFA states : - email#1.dotted_quad - - Forward route : (from state 8) - (START)->3:[!#-'*/=?^`{-~]->12:[@]->14:[[]->(HERE) - Transitions : - 7:[.] -> 17 - 8:[0-9] -> 17 - 15:[]] -> 26 - -DFA state 18 - NFA states : - email#1.start_of_domain - - Forward route : (from state 9) - (START)->4:["]->4:["]->12:[@]->(HERE) - Transitions : - 6:[\055] -> 27 - 7:[.] -> 27 - 8:[0-9] -> 27 - 13:[A-Z] -> 27 - 14:[[] -> 17 - 16:[_] -> 27 - 17:[a-z] -> 27 - -DFA state 19 - NFA states : - angled_email#2.out - before_date - date#3.in - date#4.in - - Forward route : (from state 10) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->11:[>]->(HERE) - Transitions : - 0:[\t ] -> 7 - -DFA state 20 - NFA states : - angled_email#2.email#1.domain_route - angled_email#2.email#1.start_of_domain - - Forward route : (from state 10) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->12:[@]->(HERE) - Transitions : - 6:[\055] -> 28 - 7:[.] -> 28 - 8:[0-9] -> 28 - 9:[:] -> 22 - 13:[A-Z] -> 28 - 14:[[] -> 29 - 16:[_] -> 28 - 17:[a-z] -> 28 - -DFA state 21 - NFA states : - angled_email#2.email#1.before_at - angled_email#2.email#1.out - angled_email#2.before_gt - - Forward route : (from state 11) - (START)->10:[<]->4:["]->4:["]->(HERE) - Transitions : - 3:[!#-'*/=?^`{-~] -> 21 - 4:["] -> 11 - 5:[+] -> 21 - 6:[\055] -> 21 - 7:[.] -> 21 - 8:[0-9] -> 21 - 11:[>] -> 19 - 12:[@] -> 30 - 13:[A-Z] -> 21 - 16:[_] -> 21 - 17:[a-z] -> 21 - -DFA state 22 - NFA states : - angled_email#2.email#1.in - - Forward route : (from state 12) - (START)->10:[<]->12:[@]->9:[:]->(HERE) - Transitions : - 3:[!#-'*/=?^`{-~] -> 10 - 4:["] -> 11 - 5:[+] -> 10 - 6:[\055] -> 10 - 7:[.] -> 10 - 8:[0-9] -> 10 - 12:[@] -> 12 - 13:[A-Z] -> 10 - 16:[_] -> 10 - 17:[a-z] -> 10 - -DFA state 23 - NFA states : - email#1.in - email#1.before_at - email#1.out - before_date - date#3.in - date#3.#3 - date#4.in - date#4.#3 - - Forward route : (from state 14) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->(HERE) - Transitions : - 0:[\t ] -> 31 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 12:[@] -> 8 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 2 - -DFA state 24 - NFA states : - date#3.#2 - date#4.#2 - - Forward route : (from state 15) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->(HERE) - Transitions : - 17:[a-z] -> 32 - -DFA state 25 - NFA states : - email#1.domain_route - email#1.after_at - email#1.out - before_date - date#3.in - date#4.in - - Forward route : (from state 16) - (START)->3:[!#-'*/=?^`{-~]->12:[@]->6:[\055]->6:[\055]->(HERE) - Transitions : - 0:[\t ] -> 7 - 6:[\055] -> 25 - 7:[.] -> 25 - 8:[0-9] -> 25 - 9:[:] -> 13 - 13:[A-Z] -> 25 - 16:[_] -> 25 - 17:[a-z] -> 25 - -DFA state 26 - NFA states : - email#1.out - before_date - date#3.in - date#4.in - - Forward route : (from state 17) - (START)->3:[!#-'*/=?^`{-~]->12:[@]->14:[[]->15:[]]->(HERE) - Transitions : - 0:[\t ] -> 7 - -DFA state 27 - NFA states : - email#1.after_at - - Forward route : (from state 18) - (START)->4:["]->4:["]->12:[@]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 33 - 7:[.] -> 33 - 8:[0-9] -> 33 - 13:[A-Z] -> 33 - 16:[_] -> 33 - 17:[a-z] -> 33 - -DFA state 28 - NFA states : - angled_email#2.email#1.domain_route - angled_email#2.email#1.after_at - - Forward route : (from state 20) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->12:[@]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 34 - 7:[.] -> 34 - 8:[0-9] -> 34 - 9:[:] -> 22 - 13:[A-Z] -> 34 - 16:[_] -> 34 - 17:[a-z] -> 34 - -DFA state 29 - NFA states : - angled_email#2.email#1.dotted_quad - - Forward route : (from state 20) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->12:[@]->14:[[]->(HERE) - Transitions : - 7:[.] -> 29 - 8:[0-9] -> 29 - 15:[]] -> 35 - -DFA state 30 - NFA states : - angled_email#2.email#1.start_of_domain - - Forward route : (from state 21) - (START)->10:[<]->4:["]->4:["]->12:[@]->(HERE) - Transitions : - 6:[\055] -> 36 - 7:[.] -> 36 - 8:[0-9] -> 36 - 13:[A-Z] -> 36 - 14:[[] -> 29 - 16:[_] -> 36 - 17:[a-z] -> 36 - -DFA state 31 - NFA states : - date#3.in - date#3.before_weekday - date#3.after_weekday - date#4.in - date#4.before_weekday - date#4.after_weekday - - Forward route : (from state 23) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 31 - 13:[A-Z] -> 37 - -DFA state 32 - NFA states : - date#3.#3 - date#4.#3 - - Forward route : (from state 24) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->(HERE) - Transitions : - 0:[\t ] -> 38 - -DFA state 33 - NFA states : - email#1.after_at - email#1.out - before_date - date#3.in - date#4.in - - Forward route : (from state 27) - (START)->4:["]->4:["]->12:[@]->6:[\055]->6:[\055]->(HERE) - Transitions : - 0:[\t ] -> 7 - 6:[\055] -> 33 - 7:[.] -> 33 - 8:[0-9] -> 33 - 13:[A-Z] -> 33 - 16:[_] -> 33 - 17:[a-z] -> 33 - -DFA state 34 - NFA states : - angled_email#2.email#1.domain_route - angled_email#2.email#1.after_at - angled_email#2.email#1.out - angled_email#2.before_gt - - Forward route : (from state 28) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->12:[@]->6:[\055]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 34 - 7:[.] -> 34 - 8:[0-9] -> 34 - 9:[:] -> 22 - 11:[>] -> 19 - 13:[A-Z] -> 34 - 16:[_] -> 34 - 17:[a-z] -> 34 - -DFA state 35 - NFA states : - angled_email#2.email#1.out - angled_email#2.before_gt - - Forward route : (from state 29) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->12:[@]->14:[[]->15:[]]->(HERE) - Transitions : - 11:[>] -> 19 - -DFA state 36 - NFA states : - angled_email#2.email#1.after_at - - Forward route : (from state 30) - (START)->10:[<]->4:["]->4:["]->12:[@]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 39 - 7:[.] -> 39 - 8:[0-9] -> 39 - 13:[A-Z] -> 39 - 16:[_] -> 39 - 17:[a-z] -> 39 - -DFA state 37 - NFA states : - date#3.#1 - date#3.#4 - date#4.#1 - date#4.#4 - - Forward route : (from state 31) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 17:[a-z] -> 40 - -DFA state 38 - NFA states : - date#3.after_weekday - date#4.after_weekday - - Forward route : (from state 32) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 38 - 13:[A-Z] -> 41 - -DFA state 39 - NFA states : - angled_email#2.email#1.after_at - angled_email#2.email#1.out - angled_email#2.before_gt - - Forward route : (from state 36) - (START)->10:[<]->4:["]->4:["]->12:[@]->6:[\055]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 39 - 7:[.] -> 39 - 8:[0-9] -> 39 - 11:[>] -> 19 - 13:[A-Z] -> 39 - 16:[_] -> 39 - 17:[a-z] -> 39 - -DFA state 40 - NFA states : - date#3.#2 - date#3.#5 - date#4.#2 - date#4.#5 - - Forward route : (from state 37) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->(HERE) - Transitions : - 17:[a-z] -> 42 - -DFA state 41 - NFA states : - date#3.#4 - date#4.#4 - - Forward route : (from state 38) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 17:[a-z] -> 43 - -DFA state 42 - NFA states : - date#3.#3 - date#3.#6 - date#4.#3 - date#4.#6 - - Forward route : (from state 40) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->(HERE) - Transitions : - 0:[\t ] -> 44 - -DFA state 43 - NFA states : - date#3.#5 - date#4.#5 - - Forward route : (from state 41) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->(HERE) - Transitions : - 17:[a-z] -> 45 - -DFA state 44 - NFA states : - date#3.after_weekday - date#3.after_month - date#4.after_weekday - date#4.after_month - - Forward route : (from state 42) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 44 - 8:[0-9] -> 46 - 13:[A-Z] -> 41 - -DFA state 45 - NFA states : - date#3.#6 - date#4.#6 - - Forward route : (from state 43) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->(HERE) - Transitions : - 0:[\t ] -> 47 - -DFA state 46 - NFA states : - date#3.#7 - date#3.#8 - date#4.#7 - date#4.#8 - - Forward route : (from state 44) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 48 - 8:[0-9] -> 49 - -DFA state 47 - NFA states : - date#3.after_month - date#4.after_month - - Forward route : (from state 45) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 47 - 8:[0-9] -> 46 - -DFA state 48 - NFA states : - date#3.after_day - date#4.after_day - - Forward route : (from state 46) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 48 - 8:[0-9] -> 50 - -DFA state 49 - NFA states : - date#3.#9 - date#4.#9 - - Forward route : (from state 46) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 48 - -DFA state 50 - NFA states : - date#3.#10 - date#3.#18 - date#4.#10 - date#4.#18 - - Forward route : (from state 48) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 51 - -DFA state 51 - NFA states : - date#3.#11 - date#3.#19 - date#4.#11 - date#4.#19 - - Forward route : (from state 50) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 9:[:] -> 52 - -DFA state 52 - NFA states : - date#3.#12 - date#3.#20 - date#4.#12 - date#4.#20 - - Forward route : (from state 51) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->(HERE) - Transitions : - 8:[0-9] -> 53 - -DFA state 53 - NFA states : - date#3.#13 - date#3.#21 - date#4.#13 - date#4.#21 - - Forward route : (from state 52) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 54 - -DFA state 54 - NFA states : - date#3.#14 - date#3.#22 - date#4.#14 - date#4.#22 - - Forward route : (from state 53) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 55 - 9:[:] -> 56 - -DFA state 55 - NFA states : - date#3.after_time - date#3.zone#1.in - date#3.zone#2.in - date#3.after_timezone - date#4.after_time - date#4.zone#1.in - date#4.zone#2.in - date#4.after_timezone - - Forward route : (from state 54) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 55 - 5:[+] -> 57 - 6:[\055] -> 57 - 8:[0-9] -> 58 - 13:[A-Z] -> 59 - -DFA state 56 - NFA states : - date#3.#15 - date#4.#15 - - Forward route : (from state 54) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->9:[:]->(HERE) - Transitions : - 8:[0-9] -> 60 - -DFA state 57 - NFA states : - date#3.zone#1.zone2 - date#3.zone#2.zone2 - date#4.zone#1.zone2 - date#4.zone#2.zone2 - - Forward route : (from state 55) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->5:[+]->(HERE) - Transitions : - 8:[0-9] -> 59 - 13:[A-Z] -> 59 - 17:[a-z] -> 59 - -DFA state 58 - NFA states : - date#3.#25 - date#3.#30 - date#4.#25 - date#4.#30 - - Forward route : (from state 55) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 61 - -DFA state 59 - NFA states : - date#3.#23 - date#3.zone#1.zone2 - date#3.zone#1.out - date#3.#24 - date#3.zone#2.zone2 - date#3.zone#2.out - date#4.#23 - date#4.zone#1.zone2 - date#4.zone#1.out - date#4.#24 - date#4.zone#2.zone2 - date#4.zone#2.out - - Forward route : (from state 55) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 0:[\t ] -> 62 - 8:[0-9] -> 59 - 13:[A-Z] -> 59 - 17:[a-z] -> 59 - -DFA state 60 - NFA states : - date#3.#16 - date#4.#16 - - Forward route : (from state 56) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 63 - -DFA state 61 - NFA states : - date#3.#26 - date#3.#31 - date#4.#26 - date#4.#31 - - Forward route : (from state 58) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 64 - -DFA state 62 - NFA states : - date#3.after_timezone_1 - date#3.zone#6.in - date#3.after_timezone - date#4.after_timezone_1 - date#4.zone#6.in - date#4.after_timezone - - Forward route : (from state 59) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 62 - 5:[+] -> 65 - 6:[\055] -> 65 - 8:[0-9] -> 66 - 13:[A-Z] -> 67 - -DFA state 63 - NFA states : - date#3.#17 - date#4.#17 - - Forward route : (from state 60) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 55 - -DFA state 64 - NFA states : - date#3.#27 - date#3.#32 - date#4.#27 - date#4.#32 - - Forward route : (from state 61) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 68 - -DFA state 65 - NFA states : - date#3.zone#6.zone2 - date#4.zone#6.zone2 - - Forward route : (from state 62) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->5:[+]->(HERE) - Transitions : - 8:[0-9] -> 67 - 13:[A-Z] -> 67 - 17:[a-z] -> 67 - -DFA state 66 - NFA states : - date#3.#30 - date#4.#30 - - Forward route : (from state 62) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 69 - -DFA state 67 - NFA states : - date#3.#29 - date#3.zone#6.zone2 - date#3.zone#6.out - date#4.#29 - date#4.zone#6.zone2 - date#4.zone#6.out - - Forward route : (from state 62) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 0:[\t ] -> 70 - 8:[0-9] -> 67 - 13:[A-Z] -> 67 - 17:[a-z] -> 67 - -DFA state 68 - NFA states : - #1 - date#3.after_year_before_zone - date#3.zone#3.in - date#3.zone#4.in - date#3.after_year - date#3.out - #3 - date#4.after_year_before_zone - date#4.zone#3.in - date#4.zone#4.in - date#4.after_year - date#4.out - - Forward route : (from state 64) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 68 - 1:[\n] -> 71 - 2:[\r] -> 72 - 5:[+] -> 73 - 6:[\055] -> 73 - 13:[A-Z] -> 74 - -DFA state 69 - NFA states : - date#3.#31 - date#4.#31 - - Forward route : (from state 66) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 75 - -DFA state 70 - NFA states : - date#3.after_timezone - date#4.after_timezone - - Forward route : (from state 67) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->13:[A-Z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 70 - 8:[0-9] -> 66 - -DFA state 71 - NFA states : - #2 - - Forward route : (from state 68) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->1:[\n]->(HERE) - Transitions : - NFA exit tags applying : - FROMCHECK_PASS - Attributes for <(DEFAULT)> : FROMCHECK_PASS - -DFA state 72 - NFA states : - #4 - - Forward route : (from state 68) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->2:[\r]->(HERE) - Transitions : - 1:[\n] -> 76 - -DFA state 73 - NFA states : - date#3.zone#3.zone2 - date#3.zone#4.zone2 - date#4.zone#3.zone2 - date#4.zone#4.zone2 - - Forward route : (from state 68) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->5:[+]->(HERE) - Transitions : - 8:[0-9] -> 74 - 13:[A-Z] -> 74 - 17:[a-z] -> 74 - -DFA state 74 - NFA states : - #1 - date#3.zone#3.zone2 - date#3.zone#3.out - date#3.#28 - date#3.zone#4.zone2 - date#3.zone#4.out - date#3.after_timezone_after_year - date#3.out - #3 - date#4.zone#3.zone2 - date#4.zone#3.out - date#4.#28 - date#4.zone#4.zone2 - date#4.zone#4.out - date#4.after_timezone_after_year - date#4.out - - Forward route : (from state 68) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->13:[A-Z]->(HERE) - Transitions : - 0:[\t ] -> 77 - 1:[\n] -> 71 - 2:[\r] -> 72 - 8:[0-9] -> 74 - 13:[A-Z] -> 74 - 17:[a-z] -> 74 - -DFA state 75 - NFA states : - date#3.#32 - date#4.#32 - - Forward route : (from state 69) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 78 - -DFA state 76 - NFA states : - #5 - - Forward route : (from state 72) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->2:[\r]->1:[\n]->(HERE) - Transitions : - NFA exit tags applying : - FROMCHECK_PASS - Attributes for <(DEFAULT)> : FROMCHECK_PASS - -DFA state 77 - NFA states : - #1 - date#3.after_timezone_after_year_1 - date#3.zone#5.in - date#3.after_timezone_after_year - date#3.out - #3 - date#4.after_timezone_after_year_1 - date#4.zone#5.in - date#4.after_timezone_after_year - date#4.out - - Forward route : (from state 74) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->13:[A-Z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 77 - 1:[\n] -> 71 - 2:[\r] -> 72 - 5:[+] -> 79 - 6:[\055] -> 79 - 13:[A-Z] -> 80 - -DFA state 78 - NFA states : - #1 - date#3.after_year - date#3.out - #3 - date#4.after_year - date#4.out - - Forward route : (from state 75) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 78 - 1:[\n] -> 71 - 2:[\r] -> 72 - -DFA state 79 - NFA states : - date#3.zone#5.zone2 - date#4.zone#5.zone2 - - Forward route : (from state 77) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->13:[A-Z]->0:[\t ]->5:[+]->(HERE) - Transitions : - 8:[0-9] -> 80 - 13:[A-Z] -> 80 - 17:[a-z] -> 80 - -DFA state 80 - NFA states : - #1 - date#3.zone#5.zone2 - date#3.zone#5.out - date#3.after_timezone_after_year - date#3.out - #3 - date#4.zone#5.zone2 - date#4.zone#5.out - date#4.after_timezone_after_year - date#4.out - - Forward route : (from state 77) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->13:[A-Z]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 0:[\t ] -> 81 - 1:[\n] -> 71 - 2:[\r] -> 72 - 8:[0-9] -> 80 - 13:[A-Z] -> 80 - 17:[a-z] -> 80 - -DFA state 81 - NFA states : - #1 - date#3.after_timezone_after_year - date#3.out - #3 - date#4.after_timezone_after_year - date#4.out - - Forward route : (from state 80) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->13:[A-Z]->0:[\t ]->13:[A-Z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 81 - 1:[\n] -> 71 - 2:[\r] -> 72 - - -Entry states in DFA: -Entry <(ONLY ENTRY)> : 0 -Searching for dead states... -(no dead states found) - ------------------------------ ------- COMPRESSING DFA ------ ------------------------------ -Old DFA state 0 becomes 0 -Old DFA state 1 becomes 1 -Old DFA state 2 becomes 2 -Old DFA state 3 becomes 3 -Old DFA state 4 becomes 4 -Old DFA state 5 becomes 5 -Old DFA state 6 becomes 6 -Old DFA state 7 becomes 7 -Old DFA state 8 becomes 8 -Old DFA state 9 becomes 9 -Old DFA state 10 becomes 10 -Old DFA state 11 becomes 11 -Old DFA state 12 becomes 12 -Old DFA state 13 becomes 13 -Old DFA state 14 becomes 14 -Old DFA state 15 becomes 15 -Old DFA state 16 becomes 16 -Old DFA state 17 becomes 17 -Old DFA state 18 becomes 18 -Old DFA state 19 becomes 19 -Old DFA state 20 becomes 20 -Old DFA state 21 becomes 21 -Old DFA state 22 becomes 4 (formerly 4) -Old DFA state 23 becomes 22 -Old DFA state 24 becomes 23 -Old DFA state 25 becomes 24 -Old DFA state 26 becomes 19 (formerly 19) -Old DFA state 27 becomes 25 -Old DFA state 28 becomes 26 -Old DFA state 29 becomes 27 -Old DFA state 30 becomes 28 -Old DFA state 31 becomes 29 -Old DFA state 32 becomes 30 -Old DFA state 33 becomes 31 -Old DFA state 34 becomes 32 -Old DFA state 35 becomes 33 -Old DFA state 36 becomes 34 -Old DFA state 37 becomes 35 -Old DFA state 38 becomes 36 -Old DFA state 39 becomes 37 -Old DFA state 40 becomes 38 -Old DFA state 41 becomes 39 -Old DFA state 42 becomes 40 -Old DFA state 43 becomes 41 -Old DFA state 44 becomes 42 -Old DFA state 45 becomes 43 -Old DFA state 46 becomes 44 -Old DFA state 47 becomes 45 -Old DFA state 48 becomes 46 -Old DFA state 49 becomes 47 -Old DFA state 50 becomes 48 -Old DFA state 51 becomes 49 -Old DFA state 52 becomes 50 -Old DFA state 53 becomes 51 -Old DFA state 54 becomes 52 -Old DFA state 55 becomes 53 -Old DFA state 56 becomes 54 -Old DFA state 57 becomes 55 -Old DFA state 58 becomes 56 -Old DFA state 59 becomes 57 -Old DFA state 60 becomes 58 -Old DFA state 61 becomes 59 -Old DFA state 62 becomes 60 -Old DFA state 63 becomes 61 -Old DFA state 64 becomes 62 -Old DFA state 65 becomes 63 -Old DFA state 66 becomes 64 -Old DFA state 67 becomes 65 -Old DFA state 68 becomes 66 -Old DFA state 69 becomes 67 -Old DFA state 70 becomes 68 -Old DFA state 71 becomes 69 -Old DFA state 72 becomes 70 -Old DFA state 73 becomes 71 -Old DFA state 74 becomes 72 -Old DFA state 75 becomes 73 -Old DFA state 76 becomes 69 (formerly 71) -Old DFA state 77 becomes 74 -Old DFA state 78 becomes 75 -Old DFA state 79 becomes 76 -Old DFA state 80 becomes 77 -Old DFA state 81 becomes 75 (formerly 78) -Entry <(ONLY ENTRY)>, formerly state 0, now state 0 -------------------------------- -DFA structure after compression -------------------------------- -DFA state 0 - Forward route : - (START)->(HERE) - Transitions : - 0:[\t ] -> 1 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 10:[<] -> 4 - 12:[@] -> 5 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 2 - -DFA state 1 - Forward route : (from state 0) - (START)->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 1 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 10:[<] -> 4 - 12:[@] -> 5 - 13:[A-Z] -> 6 - 16:[_] -> 2 - 17:[a-z] -> 2 - Use state 0 as basis (1 fixups) - -DFA state 2 - Forward route : (from state 0) - (START)->3:[!#-'*/=?^`{-~]->(HERE) - Transitions : - 0:[\t ] -> 7 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 12:[@] -> 8 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 2 - Use state 0 as basis (3 fixups) - -DFA state 3 - Forward route : (from state 0) - (START)->4:["]->(HERE) - Transitions : - 0:[\t ] -> 3 - 3:[!#-'*/=?^`{-~] -> 3 - 4:["] -> 9 - 5:[+] -> 3 - 6:[\055] -> 3 - 7:[.] -> 3 - 8:[0-9] -> 3 - 9:[:] -> 3 - 10:[<] -> 3 - 11:[>] -> 3 - 12:[@] -> 3 - 13:[A-Z] -> 3 - 16:[_] -> 3 - 17:[a-z] -> 3 - -DFA state 4 - Forward route : (from state 0) - (START)->10:[<]->(HERE) - Transitions : - 3:[!#-'*/=?^`{-~] -> 10 - 4:["] -> 11 - 5:[+] -> 10 - 6:[\055] -> 10 - 7:[.] -> 10 - 8:[0-9] -> 10 - 12:[@] -> 12 - 13:[A-Z] -> 10 - 16:[_] -> 10 - 17:[a-z] -> 10 - -DFA state 5 - Forward route : (from state 0) - (START)->12:[@]->(HERE) - Transitions : - 6:[\055] -> 5 - 7:[.] -> 5 - 8:[0-9] -> 5 - 9:[:] -> 13 - 13:[A-Z] -> 5 - 16:[_] -> 5 - 17:[a-z] -> 5 - -DFA state 6 - Forward route : (from state 1) - (START)->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 0:[\t ] -> 7 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 12:[@] -> 8 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 14 - Use state 0 as basis (4 fixups) - -DFA state 7 - Forward route : (from state 2) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 7 - 13:[A-Z] -> 15 - -DFA state 8 - Forward route : (from state 2) - (START)->3:[!#-'*/=?^`{-~]->12:[@]->(HERE) - Transitions : - 6:[\055] -> 16 - 7:[.] -> 16 - 8:[0-9] -> 16 - 9:[:] -> 13 - 13:[A-Z] -> 16 - 14:[[] -> 17 - 16:[_] -> 16 - 17:[a-z] -> 16 - -DFA state 9 - Forward route : (from state 3) - (START)->4:["]->4:["]->(HERE) - Transitions : - 0:[\t ] -> 7 - 3:[!#-'*/=?^`{-~] -> 9 - 4:["] -> 3 - 5:[+] -> 9 - 6:[\055] -> 9 - 7:[.] -> 9 - 8:[0-9] -> 9 - 12:[@] -> 18 - 13:[A-Z] -> 9 - 16:[_] -> 9 - 17:[a-z] -> 9 - -DFA state 10 - Forward route : (from state 4) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->(HERE) - Transitions : - 3:[!#-'*/=?^`{-~] -> 10 - 4:["] -> 11 - 5:[+] -> 10 - 6:[\055] -> 10 - 7:[.] -> 10 - 8:[0-9] -> 10 - 11:[>] -> 19 - 12:[@] -> 20 - 13:[A-Z] -> 10 - 16:[_] -> 10 - 17:[a-z] -> 10 - Use state 4 as basis (2 fixups) - -DFA state 11 - Forward route : (from state 4) - (START)->10:[<]->4:["]->(HERE) - Transitions : - 0:[\t ] -> 11 - 3:[!#-'*/=?^`{-~] -> 11 - 4:["] -> 21 - 5:[+] -> 11 - 6:[\055] -> 11 - 7:[.] -> 11 - 8:[0-9] -> 11 - 9:[:] -> 11 - 10:[<] -> 11 - 11:[>] -> 11 - 12:[@] -> 11 - 13:[A-Z] -> 11 - 16:[_] -> 11 - 17:[a-z] -> 11 - -DFA state 12 - Forward route : (from state 4) - (START)->10:[<]->12:[@]->(HERE) - Transitions : - 6:[\055] -> 12 - 7:[.] -> 12 - 8:[0-9] -> 12 - 9:[:] -> 4 - 13:[A-Z] -> 12 - 16:[_] -> 12 - 17:[a-z] -> 12 - -DFA state 13 - Forward route : (from state 5) - (START)->12:[@]->9:[:]->(HERE) - Transitions : - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 12:[@] -> 5 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 2 - Use state 0 as basis (2 fixups) - -DFA state 14 - Forward route : (from state 6) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->(HERE) - Transitions : - 0:[\t ] -> 7 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 12:[@] -> 8 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 22 - Use state 0 as basis (4 fixups) - -DFA state 15 - Forward route : (from state 7) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 17:[a-z] -> 23 - -DFA state 16 - Forward route : (from state 8) - (START)->3:[!#-'*/=?^`{-~]->12:[@]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 24 - 7:[.] -> 24 - 8:[0-9] -> 24 - 9:[:] -> 13 - 13:[A-Z] -> 24 - 16:[_] -> 24 - 17:[a-z] -> 24 - -DFA state 17 - Forward route : (from state 8) - (START)->3:[!#-'*/=?^`{-~]->12:[@]->14:[[]->(HERE) - Transitions : - 7:[.] -> 17 - 8:[0-9] -> 17 - 15:[]] -> 19 - -DFA state 18 - Forward route : (from state 9) - (START)->4:["]->4:["]->12:[@]->(HERE) - Transitions : - 6:[\055] -> 25 - 7:[.] -> 25 - 8:[0-9] -> 25 - 13:[A-Z] -> 25 - 14:[[] -> 17 - 16:[_] -> 25 - 17:[a-z] -> 25 - -DFA state 19 - Forward route : (from state 10) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->11:[>]->(HERE) - Transitions : - 0:[\t ] -> 7 - -DFA state 20 - Forward route : (from state 10) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->12:[@]->(HERE) - Transitions : - 6:[\055] -> 26 - 7:[.] -> 26 - 8:[0-9] -> 26 - 9:[:] -> 4 - 13:[A-Z] -> 26 - 14:[[] -> 27 - 16:[_] -> 26 - 17:[a-z] -> 26 - -DFA state 21 - Forward route : (from state 11) - (START)->10:[<]->4:["]->4:["]->(HERE) - Transitions : - 3:[!#-'*/=?^`{-~] -> 21 - 4:["] -> 11 - 5:[+] -> 21 - 6:[\055] -> 21 - 7:[.] -> 21 - 8:[0-9] -> 21 - 11:[>] -> 19 - 12:[@] -> 28 - 13:[A-Z] -> 21 - 16:[_] -> 21 - 17:[a-z] -> 21 - -DFA state 22 - Forward route : (from state 14) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->(HERE) - Transitions : - 0:[\t ] -> 29 - 3:[!#-'*/=?^`{-~] -> 2 - 4:["] -> 3 - 5:[+] -> 2 - 6:[\055] -> 2 - 7:[.] -> 2 - 8:[0-9] -> 2 - 12:[@] -> 8 - 13:[A-Z] -> 2 - 16:[_] -> 2 - 17:[a-z] -> 2 - Use state 0 as basis (3 fixups) - -DFA state 23 - Forward route : (from state 15) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->(HERE) - Transitions : - 17:[a-z] -> 30 - -DFA state 24 - Forward route : (from state 16) - (START)->3:[!#-'*/=?^`{-~]->12:[@]->6:[\055]->6:[\055]->(HERE) - Transitions : - 0:[\t ] -> 7 - 6:[\055] -> 24 - 7:[.] -> 24 - 8:[0-9] -> 24 - 9:[:] -> 13 - 13:[A-Z] -> 24 - 16:[_] -> 24 - 17:[a-z] -> 24 - Use state 16 as basis (1 fixups) - -DFA state 25 - Forward route : (from state 18) - (START)->4:["]->4:["]->12:[@]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 31 - 7:[.] -> 31 - 8:[0-9] -> 31 - 13:[A-Z] -> 31 - 16:[_] -> 31 - 17:[a-z] -> 31 - -DFA state 26 - Forward route : (from state 20) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->12:[@]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 32 - 7:[.] -> 32 - 8:[0-9] -> 32 - 9:[:] -> 4 - 13:[A-Z] -> 32 - 16:[_] -> 32 - 17:[a-z] -> 32 - -DFA state 27 - Forward route : (from state 20) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->12:[@]->14:[[]->(HERE) - Transitions : - 7:[.] -> 27 - 8:[0-9] -> 27 - 15:[]] -> 33 - -DFA state 28 - Forward route : (from state 21) - (START)->10:[<]->4:["]->4:["]->12:[@]->(HERE) - Transitions : - 6:[\055] -> 34 - 7:[.] -> 34 - 8:[0-9] -> 34 - 13:[A-Z] -> 34 - 14:[[] -> 27 - 16:[_] -> 34 - 17:[a-z] -> 34 - -DFA state 29 - Forward route : (from state 22) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 29 - 13:[A-Z] -> 35 - -DFA state 30 - Forward route : (from state 23) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->(HERE) - Transitions : - 0:[\t ] -> 36 - -DFA state 31 - Forward route : (from state 25) - (START)->4:["]->4:["]->12:[@]->6:[\055]->6:[\055]->(HERE) - Transitions : - 0:[\t ] -> 7 - 6:[\055] -> 31 - 7:[.] -> 31 - 8:[0-9] -> 31 - 13:[A-Z] -> 31 - 16:[_] -> 31 - 17:[a-z] -> 31 - Use state 25 as basis (1 fixups) - -DFA state 32 - Forward route : (from state 26) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->12:[@]->6:[\055]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 32 - 7:[.] -> 32 - 8:[0-9] -> 32 - 9:[:] -> 4 - 11:[>] -> 19 - 13:[A-Z] -> 32 - 16:[_] -> 32 - 17:[a-z] -> 32 - Use state 26 as basis (1 fixups) - -DFA state 33 - Forward route : (from state 27) - (START)->10:[<]->3:[!#-'*/=?^`{-~]->12:[@]->14:[[]->15:[]]->(HERE) - Transitions : - 11:[>] -> 19 - -DFA state 34 - Forward route : (from state 28) - (START)->10:[<]->4:["]->4:["]->12:[@]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 37 - 7:[.] -> 37 - 8:[0-9] -> 37 - 13:[A-Z] -> 37 - 16:[_] -> 37 - 17:[a-z] -> 37 - -DFA state 35 - Forward route : (from state 29) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 17:[a-z] -> 38 - -DFA state 36 - Forward route : (from state 30) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 36 - 13:[A-Z] -> 39 - -DFA state 37 - Forward route : (from state 34) - (START)->10:[<]->4:["]->4:["]->12:[@]->6:[\055]->6:[\055]->(HERE) - Transitions : - 6:[\055] -> 37 - 7:[.] -> 37 - 8:[0-9] -> 37 - 11:[>] -> 19 - 13:[A-Z] -> 37 - 16:[_] -> 37 - 17:[a-z] -> 37 - Use state 34 as basis (1 fixups) - -DFA state 38 - Forward route : (from state 35) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->(HERE) - Transitions : - 17:[a-z] -> 40 - -DFA state 39 - Forward route : (from state 36) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 17:[a-z] -> 41 - -DFA state 40 - Forward route : (from state 38) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->(HERE) - Transitions : - 0:[\t ] -> 42 - -DFA state 41 - Forward route : (from state 39) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->(HERE) - Transitions : - 17:[a-z] -> 43 - -DFA state 42 - Forward route : (from state 40) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 42 - 8:[0-9] -> 44 - 13:[A-Z] -> 39 - -DFA state 43 - Forward route : (from state 41) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->(HERE) - Transitions : - 0:[\t ] -> 45 - -DFA state 44 - Forward route : (from state 42) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 46 - 8:[0-9] -> 47 - -DFA state 45 - Forward route : (from state 43) - (START)->3:[!#-'*/=?^`{-~]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 45 - 8:[0-9] -> 44 - -DFA state 46 - Forward route : (from state 44) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 46 - 8:[0-9] -> 48 - -DFA state 47 - Forward route : (from state 44) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 46 - -DFA state 48 - Forward route : (from state 46) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 49 - -DFA state 49 - Forward route : (from state 48) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 9:[:] -> 50 - -DFA state 50 - Forward route : (from state 49) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->(HERE) - Transitions : - 8:[0-9] -> 51 - -DFA state 51 - Forward route : (from state 50) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 52 - -DFA state 52 - Forward route : (from state 51) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 53 - 9:[:] -> 54 - -DFA state 53 - Forward route : (from state 52) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 53 - 5:[+] -> 55 - 6:[\055] -> 55 - 8:[0-9] -> 56 - 13:[A-Z] -> 57 - -DFA state 54 - Forward route : (from state 52) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->9:[:]->(HERE) - Transitions : - 8:[0-9] -> 58 - -DFA state 55 - Forward route : (from state 53) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->5:[+]->(HERE) - Transitions : - 8:[0-9] -> 57 - 13:[A-Z] -> 57 - 17:[a-z] -> 57 - -DFA state 56 - Forward route : (from state 53) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 59 - -DFA state 57 - Forward route : (from state 53) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 0:[\t ] -> 60 - 8:[0-9] -> 57 - 13:[A-Z] -> 57 - 17:[a-z] -> 57 - Use state 55 as basis (1 fixups) - -DFA state 58 - Forward route : (from state 54) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 61 - -DFA state 59 - Forward route : (from state 56) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 62 - -DFA state 60 - Forward route : (from state 57) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 60 - 5:[+] -> 63 - 6:[\055] -> 63 - 8:[0-9] -> 64 - 13:[A-Z] -> 65 - -DFA state 61 - Forward route : (from state 58) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 53 - -DFA state 62 - Forward route : (from state 59) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 66 - -DFA state 63 - Forward route : (from state 60) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->5:[+]->(HERE) - Transitions : - 8:[0-9] -> 65 - 13:[A-Z] -> 65 - 17:[a-z] -> 65 - -DFA state 64 - Forward route : (from state 60) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 67 - -DFA state 65 - Forward route : (from state 60) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 0:[\t ] -> 68 - 8:[0-9] -> 65 - 13:[A-Z] -> 65 - 17:[a-z] -> 65 - Use state 63 as basis (1 fixups) - -DFA state 66 - Forward route : (from state 62) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 66 - 1:[\n] -> 69 - 2:[\r] -> 70 - 5:[+] -> 71 - 6:[\055] -> 71 - 13:[A-Z] -> 72 - -DFA state 67 - Forward route : (from state 64) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 73 - -DFA state 68 - Forward route : (from state 65) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->13:[A-Z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 68 - 8:[0-9] -> 64 - -DFA state 69 - Forward route : (from state 66) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->1:[\n]->(HERE) - Transitions : - NFA exit tags applying : - FROMCHECK_PASS - Attributes for <(DEFAULT)> : FROMCHECK_PASS - -DFA state 70 - Forward route : (from state 66) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->2:[\r]->(HERE) - Transitions : - 1:[\n] -> 69 - -DFA state 71 - Forward route : (from state 66) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->5:[+]->(HERE) - Transitions : - 8:[0-9] -> 72 - 13:[A-Z] -> 72 - 17:[a-z] -> 72 - -DFA state 72 - Forward route : (from state 66) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->13:[A-Z]->(HERE) - Transitions : - 0:[\t ] -> 74 - 1:[\n] -> 69 - 2:[\r] -> 70 - 8:[0-9] -> 72 - 13:[A-Z] -> 72 - 17:[a-z] -> 72 - Use state 71 as basis (3 fixups) - -DFA state 73 - Forward route : (from state 67) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 8:[0-9] -> 75 - -DFA state 74 - Forward route : (from state 72) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->13:[A-Z]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 74 - 1:[\n] -> 69 - 2:[\r] -> 70 - 5:[+] -> 76 - 6:[\055] -> 76 - 13:[A-Z] -> 77 - -DFA state 75 - Forward route : (from state 73) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->13:[A-Z]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 75 - 1:[\n] -> 69 - 2:[\r] -> 70 - -DFA state 76 - Forward route : (from state 74) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->13:[A-Z]->0:[\t ]->5:[+]->(HERE) - Transitions : - 8:[0-9] -> 77 - 13:[A-Z] -> 77 - 17:[a-z] -> 77 - -DFA state 77 - Forward route : (from state 74) - (START)->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->13:[A-Z]->17:[a-z]->17:[a-z]->0:[\t ]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->9:[:]->8:[0-9]->8:[0-9]->0:[\t ]->8:[0-9]->8:[0-9]->8:[0-9]->8:[0-9]->13:[A-Z]->0:[\t ]->13:[A-Z]->(HERE) - Transitions : - 0:[\t ] -> 75 - 1:[\n] -> 69 - 2:[\r] -> 70 - 8:[0-9] -> 77 - 13:[A-Z] -> 77 - 17:[a-z] -> 77 - Use state 75 as basis (3 fixups) - - -Entry states in DFA: -Entry <(ONLY ENTRY)> : 0 diff --git a/src/mairix/glob.c b/src/mairix/glob.c @@ -1,393 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2003,2004,2005 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include <string.h> -#include <stdlib.h> -#include <assert.h> -#include <ctype.h> -#include "mairix.h" - - -struct globber { - unsigned int pat[256]; - unsigned int starpat; - unsigned int twostarpat; - unsigned int hit; -}; - -struct globber_array { - int n; - struct globber **globs; -}; - -static const char *parse_charclass(const char *in, struct globber *result, unsigned int mask)/*{{{*/ -{ - int first = 1; - int prev = -1; - in++; /* Advance over '[' */ - while (*in) { - if (*in == ']') { - if (first) { - result->pat[(int)']'] |= mask; - } else { - return in; - } - } else if (*in == '-') { - /* Maybe range */ - if ((prev < 0) || !in[1] || (in[1]==']')) { - /* - at either end of string (or right after an earlier range) means - * normal - */ - result->pat['-'] |= mask; - } else { - int next = in[1]; - int hi, lo; - int i; - /* Cope with range being inverted */ - if (prev < next) { - lo = prev, hi = next; - } else { - lo = next, hi = prev; - } - for (i=lo; i<=hi; i++) { - int index = 0xff & i; - result->pat[index] |= mask; - } - /* require 1 extra increment */ - in++; - prev = -1; /* Avoid junk like [a-e-z] */ - } - } else { - int index = 0xff & (int)*in; - result->pat[index] |= mask; - } - prev = *in; - first = 0; - in++; - } - return in; -} -/*}}}*/ - -struct globber *make_globber(const char *wildstring)/*{{{*/ -{ - struct globber *result; - int n, i; - const char *p; - char c; - int index; - unsigned int mask; - - result = new(struct globber); - memset(&result->pat, 0x00, 256*sizeof(unsigned int)); - memset(&result->starpat, 0x00, sizeof(unsigned int)); - memset(&result->twostarpat, 0x00, sizeof(unsigned int)); - mask = 0x1; - - n = 0; - for (p=wildstring; *p; p++) { - mask = 1<<n; - c = *p; - switch (c) { - case '*':/*{{{*/ - if (p[1] == '*') { - result->twostarpat |= mask; - p++; - } else { - /* Match zero or more of anything */ - result->starpat |= mask; - } - break; -/*}}}*/ - case '[':/*{{{*/ - p = parse_charclass(p, result, mask); - n++; - break; -/*}}}*/ - case '?':/*{{{*/ - for (i=0; i<256; i++) { - result->pat[i] |= mask; - } - n++; - break; -/*}}}*/ - default:/*{{{*/ - index = 0xff & (int)c; - result->pat[index] |= mask; - n++; - break; -/*}}}*/ - } - } - - result->hit = (1<<n); - return result; - -} -/*}}}*/ -void free_globber(struct globber *old)/*{{{*/ -{ - free(old); -} -/*}}}*/ - -#define DODEBUG 0 - -int is_glob_match(struct globber *g, const char *s)/*{{{*/ -{ - unsigned int reg; - unsigned int stars; - unsigned int twostars; - unsigned int stars2; - int index; - - reg = 0x1; - while (*s) { - index = 0xff & (int) *s; -#if DODEBUG - printf("*s=%c index=%02x old_reg=%08lx pat=%08lx //", - *s, index, reg, g->pat[index]); -#endif - stars = (reg & g->starpat); - twostars = (reg & g->twostarpat); - if (index != '/') { - stars2 = stars | twostars; - } else { - stars2 = twostars; - } - reg &= g->pat[index]; - reg <<= 1; - reg |= stars2; -#if DODEBUG - printf(" new_reg=%08lx ", reg); - printf("starpat=%08lx stars=%08lx stars2=%08lx\n", g->starpat, stars, stars2); -#endif - s++; - } - -#if DODEBUG - printf("reg=%08lx hit=%08lx\n", reg, g->hit); -#endif - reg &= g->hit; - if (reg) { - return 1; - } else { - return 0; - } -} -/*}}}*/ - -struct globber_array *colon_sep_string_to_globber_array(const char *in)/*{{{*/ -{ - char **strings; - int n_strings; - int i; - struct globber_array *result; - - split_on_colons(in, &n_strings, &strings); - result = new(struct globber_array); - result->n = n_strings; - result->globs = new_array(struct globber *, n_strings); - for (i=0; i<n_strings; i++) { - result->globs[i] = make_globber(strings[i]); - free(strings[i]); - } - free(strings); - return result; -} -/*}}}*/ -int is_globber_array_match(struct globber_array *ga, const char *s)/*{{{*/ -{ - int i; - if (!ga) return 0; - for (i=0; i<ga->n; i++) { - if (is_glob_match(ga->globs[i], s)) return 1; - } - return 0; -} -/*}}}*/ -void free_globber_array(struct globber_array *in)/*{{{*/ -{ - int i; - for (i=0; i<in->n; i++) { - free_globber(in->globs[i]); - } - free(in); -} -/*}}}*/ - -static char *copy_folder_name(const char *start, const char *end)/*{{{*/ -{ - /* 'start' points to start of string to copy. - Any '\:' sequence is replaced by ':' . - Otherwise \ is treated normally. - 'end' can be 1 beyond the end of the string to copy. Otherwise it can be - null, meaning treat 'start' as the start of a normal null-terminated - string. */ - char *p; - const char *q; - int len; - char *result; - if (end) { - len = end - start; - } else { - len = strlen(start); - } - result = new_array(char, len + 1); - for (p=result, q=start; - end ? (q < end) : *q; - q++) { - if ((q[0] == '\\') && (q[1] == ':')) { - /* Escaped colon : drop the backslash */ - } else { - *p++ = *q; - } - } - *p = '\0'; - return result; -} -/*}}}*/ -void string_list_to_array(struct string_list *list, int *n, char ***arr)/*{{{*/ -{ - int N, i; - struct string_list *a, *next_a; - char **result; - for (N=0, a=list->next; a!=list; a=a->next, N++) ; - - result = new_array(char *, N); - for (i=0, a=list->next; i<N; a=next_a, i++) { - result[i] = a->data; - next_a = a->next; - free(a); - } - - *n = N; - *arr = result; -} -/*}}}*/ -void split_on_colons(const char *str, int *n, char ***arr)/*{{{*/ -{ - struct string_list list, *new_cell; - const char *left_to_do; - - list.next = list.prev = &list; - left_to_do = str; - do { - char *colon; - char *xx; - - colon = strchr(left_to_do, ':'); - /* Allow backslash-escaped colons in filenames */ - if (colon && (colon > left_to_do) && (colon[-1]=='\\')) { - int is_escaped; - do { - colon = strchr(colon + 1, ':'); - is_escaped = (colon && (colon[-1] == '\\')); - } while (colon && is_escaped); - } - /* 'colon' now points to the first non-escaped colon or is null if there - were no more such colons in the rest of the line. */ - - xx = copy_folder_name(left_to_do, colon); - if (colon) { - left_to_do = colon + 1; - } else { - while (*left_to_do) ++left_to_do; - } - - new_cell = new(struct string_list); - new_cell->data = xx; - new_cell->next = &list; - new_cell->prev = list.prev; - list.prev->next = new_cell; - list.prev = new_cell; - } while (*left_to_do); - - string_list_to_array(&list, n, arr); - -} -/*}}}*/ - -#if defined (TEST) -void run1(char *ref, char *s, int expected)/*{{{*/ -{ - struct globber *g; - int result; - g = make_globber(ref); - result = is_glob_match(g, s); - - printf("ref=%s, str=%s, %s %s\n", ref, s, result ? "MATCHED" : "not matched", (expected==result) ? "" : "??????"); - free_globber(g); -} -/*}}}*/ -int main (int argc, char **argv)/*{{{*/ -{ - - run1("ab?de", "abdde", 1); - run1("ab?de", "abcde", 1); - run1("ab?de", "Abcde", 0); - run1("ab?de", "abcd", 0); - run1("ab?de", "abc", 0); - run1("ab[cd]de", "abdde", 1); - run1("ab[cd]de", "abbde", 0); - run1("ab[cd]de", "abcde", 1); - run1("ab*de", "ade", 0); - run1("ab*de", "abde", 1); - run1("ab*de", "abcde", 1); - run1("ab*de", "abccde", 1); - run1("ab*de", "abccdfde", 1); - run1("ab*de", "abccdedf", 0); - run1("ab[b-d]de", "abade",0); - run1("ab[b-d]de", "abcDe",0); - run1("ab[b-d]de", "abcde",1); - run1("ab[b-d]de", "abdde",1); - run1("ab[b-d]de", "abEde", 0); - run1("[a-z][0-9A-F][]a-f-]", "yE]", 1); - run1("[a-z][0-9A-F][]a-f-]", "uE[", 0); - run1("[a-z][0-9A-F][]a-f-]", "vG-", 0); - run1("[a-z][0-9A-F][]a-f-]", "w8-", 1); - run1("*", "a", 1); - run1("*", "", 1); - run1("a*", "a", 1); - run1("a*", "aa", 1); - run1("a*", "aaA", 1); - run1("*a", "aaa", 1); - run1("*a", "a", 1); - run1("x*abc", "xabdxabc", 1); - run1("*", "", 1); - run1("a*", "", 0); - run1("*a", "", 0); - run1("a", "", 0); - - run1("*abc*", "x/abc/y", 0); - run1("**abc**", "x/abc/y", 1); - run1("x/*/abc**", "x/z/abc/y", 1); - run1("x/*/abc**", "x/z/w/abc/y", 0); - run1("x/*/abc**", "x/zz/w/abc/y", 0); - run1("x/*/abc**", "x/z/ww/abc/y", 0); - run1("x/**/abc**", "x/z/w/abc/y", 1); - run1("x/**/abc**", "x/zz/w/abc/y", 1); - - return 0; -} -/*}}}*/ -#endif - diff --git a/src/mairix/hash.c b/src/mairix/hash.c @@ -1,143 +0,0 @@ -/* Hash function */ - -#include "mairix.h" - -/* --------------------------------------------------------------------- -lookup2.c, by Bob Jenkins, December 1996, Public Domain. -hash(), hash2(), hash3, and mix() are externally useful functions. -Routines to test the hash are included if SELF_TEST is defined. -You can use this free for any purpose. It has no warranty. --------------------------------------------------------------------- -*/ -#include <stdio.h> -#include <stddef.h> -#include <stdlib.h> - -#define hashsize(n) ((unsigned int)1<<(n)) -#define hashmask(n) (hashsize(n)-1) - -/* --------------------------------------------------------------------- -mix -- mix 3 32-bit values reversibly. -For every delta with one or two bit set, and the deltas of all three - high bits or all three low bits, whether the original value of a,b,c - is almost all zero or is uniformly distributed, -* If mix() is run forward or backward, at least 32 bits in a,b,c - have at least 1/4 probability of changing. -* If mix() is run forward, every bit of c will change between 1/3 and - 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) -mix() was built out of 36 single-cycle latency instructions in a - structure that could supported 2x parallelism, like so: - a -= b; - a -= c; x = (c>>13); - b -= c; a ^= x; - b -= a; x = (a<<8); - c -= a; b ^= x; - c -= b; x = (b>>13); - ... - Unfortunately, superscalar Pentiums and Sparcs can't take advantage - of that parallelism. They've also turned some of those single-cycle - latency instructions into multi-cycle latency instructions. Still, - this is the fastest good hash I could find. There were about 2^^68 - to choose from. I only looked at a billion or so. --------------------------------------------------------------------- -*/ -#define mix(a,b,c) \ -{ \ - a -= b; a -= c; a ^= (c>>13); \ - b -= c; b -= a; b ^= (a<<8); \ - c -= a; c -= b; c ^= (b>>13); \ - a -= b; a -= c; a ^= (c>>12); \ - b -= c; b -= a; b ^= (a<<16); \ - c -= a; c -= b; c ^= (b>>5); \ - a -= b; a -= c; a ^= (c>>3); \ - b -= c; b -= a; b ^= (a<<10); \ - c -= a; c -= b; c ^= (b>>15); \ -} - -/* same, but slower, works on systems that might have 8 byte ub4's */ -#define mix2(a,b,c) \ -{ \ - a -= b; a -= c; a ^= (c>>13); \ - b -= c; b -= a; b ^= (a<< 8); \ - c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \ - a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \ - b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \ - c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \ - a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \ - b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \ - c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \ -} - -/* --------------------------------------------------------------------- -hash() -- hash a variable-length key into a 32-bit value - k : the key (the unaligned variable-length array of bytes) - len : the length of the key, counting by bytes - level : can be any 4-byte value -Returns a 32-bit value. Every bit of the key affects every bit of -the return value. Every 1-bit and 2-bit delta achieves avalanche. -About 36+6len instructions. - -The best hash table sizes are powers of 2. There is no need to do -mod a prime (mod is sooo slow!). If you need less than 32 bits, -use a bitmask. For example, if you need only 10 bits, do - h = (h & hashmask(10)); -In which case, the hash table should have hashsize(10) elements. - -If you are hashing n strings (ub1 **)k, do it like this: - for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h); - -By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this -code any way you wish, private, educational, or commercial. It's free. - -See http://burlteburtle.net/bob/hash/evahash.html -Use for hash table lookup, or anything where one collision in 2^32 is -acceptable. Do NOT use for cryptographic purposes. --------------------------------------------------------------------- -*/ - -unsigned int hashfn( unsigned char *k, unsigned int length, unsigned int initval) -{ - register unsigned int a,b,c,len; - - /* Set up the internal state */ - len = length; - a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ - c = initval; /* the previous hash value */ - - /*---------------------------------------- handle most of the key */ - while (len >= 12) - { - a += (k[0] +((unsigned int)k[1]<<8) +((unsigned int)k[2]<<16) +((unsigned int)k[3]<<24)); - b += (k[4] +((unsigned int)k[5]<<8) +((unsigned int)k[6]<<16) +((unsigned int)k[7]<<24)); - c += (k[8] +((unsigned int)k[9]<<8) +((unsigned int)k[10]<<16)+((unsigned int)k[11]<<24)); - mix(a,b,c); - k += 12; len -= 12; - } - - /*------------------------------------- handle the last 11 bytes */ - c += length; - switch(len) /* all the case statements fall through */ - { - case 11: c+=((unsigned int)k[10]<<24); - case 10: c+=((unsigned int)k[9]<<16); - case 9 : c+=((unsigned int)k[8]<<8); - /* the first byte of c is reserved for the length */ - case 8 : b+=((unsigned int)k[7]<<24); - case 7 : b+=((unsigned int)k[6]<<16); - case 6 : b+=((unsigned int)k[5]<<8); - case 5 : b+=k[4]; - case 4 : a+=((unsigned int)k[3]<<24); - case 3 : a+=((unsigned int)k[2]<<16); - case 2 : a+=((unsigned int)k[1]<<8); - case 1 : a+=k[0]; - /* case 0: nothing left to add */ - } - mix(a,b,c); - /*-------------------------------------------- report the result */ - return c; -} - - diff --git a/src/mairix/mairix.1 b/src/mairix/mairix.1 @@ -1,673 +0,0 @@ -.TH MAIRIX 1 "January 2006" -.de Sx -.PP -.ne \\$1 -.nf -.na -.RS 7 -.. -.de Ex -.RE -.fi -.ad -.PP -.. -.de Sy -.PP -.ne \\$1 -.nf -.na -.RS 12 -.. -.de Ey -.RE -.fi -.ad -.IP "" 7 -.. -.SH NAME -mairix \- index and search mail folders -.SH SYNOPSIS -.SS Indexing -.B mairix -[ -.BR \-v | \-\-verbose -] [ -.BR \-p | \-\-purge -] [ -.BR \-f | \-\-rcfile -.I mairixrc -] [ -.BR \-F | \-\-fast-index -] [ -.BR \-\-force-hash-key-new-database -.I hash -] - -.SS Searching -.B mairix -[ -.BR \-v | \-\-verbose -] [ -.BR \-f | \-\-rcfile -.I mairixrc -] [ -.BR \-r | \-\-raw-output -] [ -.BR \-x | \-\-excerpt-output -] [ -.BR \-H | \-\-force-hardlinks -] [ -.BR \-o | \-\-mfolder -.I mfolder -] [ -.BR \-a | \-\-augment -] [ -.BR \-t | \-\-threads -] -.I search-patterns - -.SS Other -.B mairix -[ -.BR \-h | \-\-help -] - -.B mairix -[ -.BR \-V | \-\-version -] - -.B mairix -[ -.BR \-d | \-\-dump -] - -.SH DESCRIPTION -.I mairix -indexes and searches a collection of email messages. The folders containing -the messages for indexing are defined in the configuration file. The indexing -stage produces a database file. The database file provides rapid access to -details of the indexed messages during searching operations. A search normally -produces a folder (so-called -.BR mfolder ) -containing the matched messages. However, a raw mode -.RB ( \-r ) -exists which just lists the matched messages instead. -.PP -It can operate with the following folder types -.IP * -maildir -.IP * -MH (compatible with the MH folder formats used by xmh, sylpheed, claws-mail, nnml (Gnus) and evolution) -.IP * -mbox (including mboxes that have been compressed with gzip or bzip2) -.PP -If maildir or MH source folders are used, and a search outputs its matches to -an mfolder in maildir or MH format, symbolic links are used to reference the -original messages inside the mfolder. However, if mbox folders are involved, -copies of messages are made instead. - -.SH OPTIONS - -.B mairix -decides whether indexing or searching is required by looking for the presence of any -.I search-patterns -on the command line. - -.SS Special modes -.TP -.B -h, --help -.br -Show usage summary and exit - -.TP -.B -V, --version -Show program version and exit - -.TP -.B -d -.br -Dump the database's contents in human-readable form to stdout. - -.SS General options -.TP -.BI "-f " mairixrc -.br -.ns -.TP -.BI "--rcfile " mairixrc -.br -Specify an alternative configuration file to use. The default configuration file is -.IR ~/.mairixrc . - -.TP -.B -v, --verbose -.br -Make the output more verbose - -.TP -.B -Q, --no-integrity-checks -.br -Normally -.I mairix -will do some internal integrity tests on the database. The -.B -Q -option removes these checks, making -.I mairix -run faster, but it will be less likely to detect internal problems if any bugs creep in. - -The -.I nochecks -directive in the rc file has the same effect. - -.TP -.B \-\-unlock -.br -.I mairix -locks its database file during any indexing or searching operation to prevent -multiple indexing runs interfering with each other, or an indexing run -interfering with search runs. The -.B --unlock -option removes the lockfile before doing the requested indexing or searching -operation. This is a convenient way of cleaning up a stale lockfile if an -earlier run crashed for some reason or was aborted. - -.SS Indexing options - -.TP -.B -p, --purge -.br -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 cost 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. - -.TP -.BI "--force-hash-key-new-database " hash -.br -This option should only be used for debugging. -.br -If a new database is created, -.I hash -is used as hash key, instead of a random hash. - -.SS Search options -.TP -.B -a, --augment -.br -Append newly matches messages to the current mfolder instead of creating the -mfolder from scratch. - -.TP -.B -t, --threads -.br -As well as returning the matched messages, also return every message in the -same thread as one of the real matches. - -.TP -.B -r, --raw-output -.br -Instead of creating an mfolder containing the matched messages, just show their -paths on stdout. - -.TP -.B -x, --excerpt-output -.br -Instead of creating an mfolder containing the matched messages, display an -excerpt from their headers on stdout. The excerpt shows To, Cc, From, Subject -and Date. - -.TP -.B -H, --force-hardlinks -.br -Instead of creating symbolic links, force the use of hardlinks. This helps -mailers such as alpine to realize that there are new mails in the search -folder. - -.TP -.BI "-o " mfolder -.br -.ns -.TP -.BI "--mfolder " mfolder -.br -Specify a temporary alternative path for the mfolder to use, overriding the -.I mfolder -directive in the rc file. - -.B mairix -will refuse to output search results into any folder that appears to be amongst -those that are indexed. This is to prevent accidental deletion of emails. - -.SS Search patterns -.TP -.BI t: word -.br -Match -.I word -in the To: header. - -.TP -.BI c: word -.br -Match -.I word -in the Cc: header. - -.TP -.BI f: word -.br -Match -.I word -in the From: header. - -.TP -.BI s: word -.br -Match -.I word -in the Subject: header. - -.TP -.BI m: word -.br -Match -.I word -in the Message-ID: header. - -.TP -.BI b: word -.br -Match -.I word -in the message body. - -.B Message body -is taken to mean any body part of type text/plain or text/html. For text/html, -text within meta tags is ignored. In particular, the URLs inside <A -HREF="..."> tags are not currently indexed. Non-text attachments are ignored. -If there's an attachment of type message/rfc822, this is parsed and the match -is performed on this sub-message too. If a hit occurs, the enclosing message -is treated as having a hit. - -.TP -.BI d: "[start-datespec]" - "[end-datespec]" -.br -Match messages with Date: headers lying in the specific range. - -.TP -.BI z: "[low-size]" - "[high-size]" -.br -Match messages whose size lies in the specified range. If the -.I low-size -argument is omitted it defaults to zero. If the -.I high-size -argument is omitted it defaults to infinite size. - -For example, to match messages between 10kilobytes and 20kilobytes in size, the -following search term can be used: -.Sy 1 -mairix z:10k-20k -.Ey - -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. - -.TP -.BI tc: word -.br -Match -.I word -in either the To: or Cc: headers (or both). - -.TP -.BI bs: word -.br -Match -.I word -in either the Subject: header or the message body (or both). - -.PP -The -.B a: -search pattern is an abbreviation for -.BR tcf: ; -i.e. match the word in the To:, Cc: or From: headers. ("a" stands for -"address" in this case.) - -.SS Match words -The -.I word -argument to the search strings can take various forms. - -.TP -.I ~word -.br -Match messages -.B not -containing the word. - -.TP -.I word1,word2 -.br -This matches if both the words are matched in the specified message part. - -.TP -.I word1/word2 -.br -This matches if either of the words are matched in the specified message part. - -.TP -.I substring= -.br -Match any word containing -.I substring -as a substring - -.TP -.I substring=N -.br -Match any word containing -.IR substring , -allowing up to -.I N -errors in the match. For example, if -.I N -is 1, a single error is allowed, where an error can be -.IP * -a missing letter -.IP * -an extra letter -.IP * -a different letter. - -.TP -.I ^substring= -.br -Match any word containing -.I substring -as a substring, with the requirement that -.I substring -occurs at the beginning of the matched word. - -.SS Precedence matters - -The binding order of the constructions is: - -.IP "1." -Individual command line arguments define separate conditions which are AND-ed -together - -.IP "2." -Within a single argument, the letters before the colon define which message -parts the expression applies to. If there is no colon, the expression applies -to all the headers listed earlier and the body. - -.IP "3." -After the colon, commas delineate separate disjuncts, which are -OR-ed together. - -.IP "4." -Each disjunct may contain separate conjuncts, which are separated -by plus signs. These conditions are AND-ed together. - -.IP "5." -Each conjunct may start with a tilde to negate it, and may be -followed by a slash to indicate a substring match, optionally -followed by an integer to define the maximum number of errors -allowed. - -.SS Date specification -.PP -This section describes the syntax used for specifying dates when -searching using the `d:' option. - -Dates are specified as a range. The start and end of the range can both be -specified. Alternatively, if the start is omitted, it is treated as being the -beginning of time. If the end is omitted, it is treated as the current time. - -There are 4 basic formats: -.TP -.BI d: start-end -.br -Specify both start and end explicitly -.TP -.BI d: start- -Specify start, end is the current time -.TP -.BI d: -end -Specify end, start is 'a long time ago' (i.e. early enough to include any -message). -.TP -.BI d: period -Specify start and end implicitly, as the start and end of the -period given. - -.PP -The start and end can be specified either absolute or relative. A relative -endpoint is given as a number followed by a single letter defining the scaling: - -.TS -box tab(&); -lb | lb | lb | lb. -letter & short for & example & meaning -= -.T& -l | l | l | l. -d & days & 3d & 3 days -w & weeks & 2w & 2 weeks (14 days) -m & months & 5m & 5 months (150 days) -y & years & 4y & 4 years (4*365 days) -.TE - -.PP -Months are always treated as 30 days, and years as 365 days, for -this purpose. - -Absolute times can be specified in many forms. Some forms have different -meanings when they define a start date from that when they define an end date. -Where a single expression specifies both the start and end (i.e. where the -argument to d: doesn't contain a `-'), it will usually have different -interpretations in the two cases. - -In the examples below, suppose the current date is Sunday May 18th, -2003 (when I started to write this material.) - -.TS -box tab(&); -l | l | l | l. -Example & Start date & End date & Notes -= -d:20030301\-20030425 & March 1st, 2003 & 25th April, 2003 -d:030301\-030425 & March 1st, 2003 & April 25th, 2003 & century assumed -d:mar1\-apr25 & March 1st, 2003 & April 25th, 2003 -d:Mar1\-Apr25 & March 1st, 2003 & April 25th, 2003 & case insensitive -d:MAR1\-APR25 & March 1st, 2003 & April 25th, 2003 & case insensitive -d:1mar\-25apr & March 1st, 2003 & April 25th, 2003 & date and month in either order -d:2002 & January 1st, 2002 & December 31st, 2002 & whole year -d:mar & March 1st, 2003 & March 31st, 2003 & most recent March -d:oct & October 1st, 2002 & October 31st, 2002 & most recent October -d:21oct\-mar & October 21st, 2002 & March 31st, 2003 & start before end -d:21apr\-mar & April 21st, 2002 & March 31st, 2003 & start before end -d:21apr\- & April 21st, 2003 & May 18th, 2003 & end omitted -d:\-21apr & January 1st, 1900 & April 21st, 2003 & start omitted -d:6w\-2w & April 6th, 2003 & May 4th, 2003 & both dates relative -d:21apr\-1w & April 21st, 2003 & May 11th, 2003 & one date relative -d:21apr\-2y & April 21st, 2001 & May 11th, 2001 & start before end -d:99\-11 & January 1st, 1999 & May 11th, 2003 &T{ -2 digits are a day of the month if possible, otherwise a year -T} -d:99oct\-1oct & October 1st, 1999 & October 1st, 2002 &T{ -end before now, single digit is a day of the month -T} -d:99oct\-01oct & October 1st, 1999 & October 31st, 2001 &T{ -2 digits starting with zero treated as a year -T} -d:oct99\-oct1 & October 1st, 1999 & October 1st, 2002 &T{ -day and month in either order -T} -d:oct99\-oct01 & October 1st, 1999 & October 31st, 2001 &T{ -year and month in either order -T} -.TE - -.PP -The principles in the table work as follows. -.IP \(bu -When the expression defines a period of more than a day (i.e. if a month or -year is specified), the earliest day in the period is taken when the start date -is defined, and the last day in the period if the end of the range is being -defined. -.IP \(bu -The end date is always taken to be on or before the current date. -.IP \(bu -The start date is always taken to be on or before the end date. - -.SH "SETTING UP THE MATCH FOLDER" - -If the match folder does not exist when running in search mode, it is -automatically created. For 'mformat=maildir' (the default), this -should be all you need to do. If you use 'mformat=mh', you may have to -run some commands before your mailer will recognize the folder. e.g. -for mutt, you could do -.Sx 2 -mkdir -p /home/richard/Mail/mfolder -touch /home/richard/Mail/mfolder/.mh_sequences -.Ex -which seems to work. Alternatively, within mutt, you could set MBOX_TYPE to -'mh' and save a message to '+mfolder' to have mutt set up the structure for you -in advance. - -If you use Sylpheed, the best way seems to be to create the new folder from -within Sylpheed before letting mairix write into it. - -.SH EXAMPLES -.PP -Suppose my email address is <richard@doesnt.exist>. - -Either of the following will match all messages newer than 3 months from me -with the word 'chrony' in the subject line: -.Sx 2 -mairix d:3m- f:richard+doesnt+exist s:chrony -mairix d:3m- f:richard@doesnt.exist s:chrony -.Ex -Suppose I don't mind a few spurious matches on the address, I want a wider date -range, and I suspect that some messages I replied to might have had the subject -keyword spelt wrongly (let's allow up to 2 errors): -.Sx 1 -mairix d:6m- f:richard s:chrony=2 -.Ex - -.SH NOTES -.PP -.B mairix -works exclusively in terms of -.IR words . -The index that's built -in indexing mode contains a table of which words occur in which -messages. Hence, the search capability is based on finding messages -that contain particular words. -.B mairix -defines a word as any string of alphanumeric characters + underscore. Any -whitespace, punctuation, hyphens etc are treated as word boundaries. - -.B mairix -has special handling for the To:, Cc: and From: headers. -Besides the normal word scan, these headers are scanned a second time, -where the characters '@', '-' and '.' are also treated as word -characters. This allows most (if not all) email addresses to appear in -the database as single words. So if you have a mail from -wibble@foobar.zzz, it will match on both these searches - -.Sx 2 -mairix f:foobar -mairix f:wibble@foobar.zzz -.Ex -It should be clear by now that the searching cannot be used to find messages -matching general regular expressions. This has never been much of a -limitation. Most searches are for particular keywords that were in the -messages, or details of the recipients, or the approximate date. - -It's also worth pointing out that there is no 'locality' information -stored, so you can't search for messages that have one words 'close' to -some other word. For every message and every word, there is a simple -yes/no condition stored - whether the message contains the word in a -particular header or in the body. So far this has proved to be -adequate. -.B mairix -has a similar feel to using an Internet search engine. - -.SH FILES -.I ~/.mairixrc - -.SH AUTHOR -Copyright (C) 2002-2006 Richard P. Curnow <rc@rc0.org.uk> -.SH "SEE ALSO" -mairixrc(5) -.SH BUGS -.PP -We need a plugin scheme to allow more types of attachment to be scanned and indexed. - diff --git a/src/mairix/mairix.c b/src/mairix/mairix.c @@ -1,778 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002,2003,2004,2005,2006,2007,2008 - * Copyright (C) Sanjoy Mahajan 2005 - * - mfolder validation code - * Copyright (C) James Cameron 2005 - * Copyright (C) Paul Fox 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "mairix.h" -#include "version.h" -#include <assert.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <pwd.h> -#include <unistd.h> -#include <ctype.h> -#include <locale.h> -#include <signal.h> - -#ifdef TEST_OOM -int total_bytes=0; -#endif - -int verbose = 0; -int do_hardlinks = 0; -int do_movefiles = 0; - -static char *folder_base = NULL; -static char *maildir_folders = NULL; -static char *mh_folders = NULL; -static char *mboxen = NULL; -static char *mfolder = NULL; -static char *omit = NULL; -static char *database_path = NULL; -static enum folder_type output_folder_type = FT_MAILDIR; -static int skip_integrity_checks = 0; - -enum filetype { - M_NONE, M_FILE, M_DIR, M_OTHER -}; - -static enum filetype classify_file(char *name)/*{{{*/ -{ - struct stat sb; - if (stat(name, &sb) < 0) { - return M_NONE; - } - if (S_ISREG(sb.st_mode)) { - return M_FILE; - } else if (S_ISDIR(sb.st_mode)) { - return M_DIR; - } else { - return M_OTHER; - } -} -/*}}}*/ -/*{{{ member of*/ -/* returns 1 iff COMPLETE_MFOLDER (i.e. the match folder with - folder_base prepended if needed) matches one of the FOLDERS after - expanding the wildcards and recursion. Used to make sure that the - match folder will not overwrite a valuable mail file or - directory. */ -int member_of (const char *complete_mfolder, - const char *folder_base, - const char *folders, - enum folder_type ft, - struct globber_array *omit_globs) { - char **raw_paths, **paths; - int n_raw_paths, n_paths, i; - - if (!folders) - return 0; - split_on_colons(folders, &n_raw_paths, &raw_paths); - switch (ft) { - case FT_MAILDIR: - glob_and_expand_paths(folder_base, raw_paths, n_raw_paths, &paths, &n_paths, &maildir_traverse_methods, omit_globs); - break; - case FT_MH: - glob_and_expand_paths(folder_base, raw_paths, n_raw_paths, &paths, &n_paths, &mh_traverse_methods, omit_globs); - break; - case FT_MBOX: - glob_and_expand_paths(folder_base, raw_paths, n_raw_paths, &paths, &n_paths, &mbox_traverse_methods, omit_globs); - break; - case FT_RAW: /* cannot happen but to keep compiler happy */ - case FT_EXCERPT: - break; - } - for (i=0; i<n_paths; i++) { - struct stat mfolder_sb, src_folder_sb; /* for checking inode numbers */ - - /* if the complete path names are the same, definitely a match */ - if (strcmp (complete_mfolder, paths[i]) == 0) - return 1; - /* also a match if they point to the same file or directory but - via different routes (e.g. absolute path for one but path with - ../.. for the other), so check inode numbers */ - /* if cannot even get stat() info, probably not wrecking any mail - files or dirs, so continue, i.e. skip inode check. */ - if (stat (complete_mfolder, &mfolder_sb) != 0 || - stat (paths[i], &src_folder_sb) != 0) - continue; - if (mfolder_sb.st_ino == src_folder_sb.st_ino) - return 1; - } - return 0; -} -/*}}}*/ -static char *copy_value(char *text)/*{{{*/ -{ - char *p; - char *result; - for (p = text; *p && (*p != '='); p++) ; - if (!*p) return NULL; - p++; - result = expand_string(p); - return result; -} -/*}}}*/ -static void add_folders(char **folders, char *extra_folders)/*{{{*/ -{ - /* note : extra_pointers is stale after this routine exits. */ - - if (!*folders) { - *folders = extra_folders; - } else { - char *old_folders = *folders; - char *new_folders; - int old_len, extra_len; - old_len = strlen(old_folders); - extra_len = strlen(extra_folders); - new_folders = new_array(char, old_len + extra_len + 2); - strcpy(new_folders, old_folders); - strcpy(new_folders + old_len, ":"); - strcpy(new_folders + old_len + 1, extra_folders); - *folders = new_folders; - free(old_folders); - } -} -/*}}}*/ -static void parse_output_folder(char *p)/*{{{*/ -{ - char *temp; - temp = copy_value(p); - if (!strncasecmp(temp, "mh", 2)) { - output_folder_type = FT_MH; - } else if (!strncasecmp(temp, "maildir", 7)) { - output_folder_type = FT_MAILDIR; - } else if (!strncasecmp(temp, "raw", 3)) { - output_folder_type = FT_RAW; - } else if (!strncasecmp(temp, "excerpt", 3)) { - output_folder_type = FT_EXCERPT; - } else if (!strncasecmp(temp, "mbox", 4)) { - output_folder_type = FT_MBOX; - } - else { - fprintf(stderr, "Unrecognized mformat <%s>\n", temp); - } - free(temp); -} -/*}}}*/ -static void parse_rc_file(char *name)/*{{{*/ -{ - FILE *in; - char line[4096], *p; - int len, lineno; - int all_blank; - int used_default_name = 0; - - if (!name) { - /* open default file */ - struct passwd *pw; - char *home; - home = getenv("HOME"); - if (!home) { - pw = getpwuid(getuid()); - if (!pw) { - fprintf(stderr, "Cannot determine home directory\n"); - exit(2); - } - home = pw->pw_dir; - } - name = new_array(char, strlen(home) + 12); - strcpy(name, home); - strcat(name, "/.mairixrc"); - used_default_name = 1; - } - - in = fopen(name, "r"); - if (!in) { - fprintf(stderr, "Cannot open %s, exiting\n", name); - exit(2); - } - - lineno = 0; - while(fgets(line, sizeof(line), in)) { - lineno++; - len = strlen(line); - if (len > sizeof(line) - 4) { - fprintf(stderr, "Line %d in %s too long, exiting\n", lineno, name); - exit(2); - } - - if (line[len-1] == '\n') { - line[len-1] = '\0'; - } - - /* Strip trailing comments. */ - for (p=line; *p && !strchr("#!;%", *p); p++) ; - if (*p) *p = '\0'; - - /* Discard blank lines */ - all_blank = 1; - for (p=line; *p; p++) { - if (!isspace(*(unsigned char *)p)) { - all_blank = 0; - break; - } - } - - if (all_blank) continue; - - /* Now a real line to parse */ - if (!strncasecmp(p, "base", 4)) folder_base = copy_value(p); - else if (!strncasecmp(p, "folders", 7)) { - fprintf(stderr, "'folders=' option in rc file is depracated, use 'maildir='\n"); - add_folders(&maildir_folders, copy_value(p)); - } - else if (!strncasecmp(p, "maildir=", 8)) add_folders(&maildir_folders, copy_value(p)); - else if (!strncasecmp(p, "mh_folders=", 11)) { - fprintf(stderr, "'mh_folders=' option in rc file is depracated, use 'mh='\n"); - add_folders(&mh_folders, copy_value(p)); - } - else if (!strncasecmp(p, "mh=", 3)) add_folders(&mh_folders, copy_value(p)); - else if (!strncasecmp(p, "mbox=", 5)) add_folders(&mboxen, copy_value(p)); - else if (!strncasecmp(p, "omit=", 5)) add_folders(&omit, copy_value(p)); - - else if (!strncasecmp(p, "mformat=", 8)) { - parse_output_folder(p); - } - else if (!strncasecmp(p, "mfolder=", 8)) mfolder = copy_value(p); - else if (!strncasecmp(p, "database=", 9)) database_path = copy_value(p); - else if (!strncasecmp(p, "nochecks", 8)) skip_integrity_checks = 1; - else { - if (verbose) { - fprintf(stderr, "Unrecognized option at line %d in %s\n", lineno, name); - } - } - } - - fclose(in); - - if (used_default_name) free(name); -} -/*}}}*/ -static int compare_strings(const void *a, const void *b)/*{{{*/ -{ - const char **aa = (const char **) a; - const char **bb = (const char **) b; - return strcmp(*aa, *bb); -} -/*}}}*/ -static int check_message_list_for_duplicates(struct msgpath_array *msgs)/*{{{*/ -{ - /* Caveat : only examines the file-per-message case */ - char **sorted_paths; - int i, n, nn; - int result; - - n = msgs->n; - sorted_paths = new_array(char *, n); - for (i=0, nn=0; i<n; i++) { - switch (msgs->type[i]) { - case MTY_MBOX: - break; - case MTY_DEAD: - assert(0); - break; - case MTY_FILE: - sorted_paths[nn++] = msgs->paths[i].src.mpf.path; - break; - } - } - qsort(sorted_paths, nn, sizeof(char *), compare_strings); - - result = 0; - for (i=1; i<nn; i++) { - if (!strcmp(sorted_paths[i-1], sorted_paths[i])) { - result = 1; - break; - } - } - - free(sorted_paths); - return result; -} -/*}}}*/ - -static void emit_int(int x)/*{{{*/ -{ - char buf1[20], buf2[20]; - char *p, *q; - int neg=0; - p = buf1; - *p = '0'; /* In case x is zero */ - if (x < 0) { - neg = 1; - x = -x; - } - while (x) { - *p++ = '0' + (x % 10); - x /= 10; - } - p--; - q = buf2; - if (neg) *q++ = '-'; - while (p >= buf1) { - *q++ = *p--; - } - write(2, buf2, q-buf2); - return; -} -/*}}}*/ -void out_of_mem(char *file, int line, size_t size)/*{{{*/ -{ - /* Hairy coding ahead - can't use any [s]printf, itoa etc because - * those might try to use the heap! */ - - int filelen; - char *p; - - static char msg1[] = "Out of memory (at "; - static char msg2[] = " bytes)\n"; - /* Perhaps even strlen is unsafe in this situation? */ - p = file; - while (*p) p++; - filelen = p - file; - write(2, msg1, sizeof(msg1)); - write(2, file, filelen); - write(2, ":", 1); - emit_int(line); - write(2, ", ", 2); - emit_int(size); - write(2, msg2, sizeof(msg2)); - exit(2); -} -/*}}}*/ -void report_error(const char *str, const char *filename)/*{{{*/ -{ - if (filename) { - int len = strlen(str) + strlen(filename) + 4; - char *t; - t = new_array(char, len); - sprintf(t, "%s '%s'", str, filename); - perror(t); - free(t); - } else { - perror(str); - } -} -/*}}}*/ -static void print_copyright(void)/*{{{*/ -{ - fprintf(stderr, - "mairix %s, Copyright (C) 2002-2010 Richard P. Curnow\n" - "mairix comes with ABSOLUTELY NO WARRANTY.\n" - "This is free software, and you are welcome to redistribute it\n" - "under certain conditions; see the GNU General Public License for details.\n\n", - PROGRAM_VERSION); -} -/*}}}*/ -static void print_version(void)/*{{{*/ -{ - fprintf(stdout, - "mairix %s\n", - PROGRAM_VERSION); -} -/*}}}*/ -static void handlesig(int signo)/*{{{*/ -{ - unlock_and_exit(7); -} -/*}}}*/ -static void usage(void)/*{{{*/ -{ - print_copyright(); - - printf("mairix [-h] : Show help\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" - "-f <rcfile> : use alternative rc file (default ~/.mairixrc)\n" - "-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" - "-x : display excerpt of message headers (default : use match folder)\n" - "-t : include all messages in same threads as matching messages\n" - "-o <mfolder> : override setting of mfolder from mairixrc file\n" - "-r : force raw output regardless of mformat setting in mairixrc file\n" - "-H : force hard links rather than symbolic ones\n" - "-M : force moving files between maildirs, deleting originals\n" - "expr_i : search expression (all expr's AND'ed together):\n" - " word : match word in message body and major headers\n" - " t:word : match word in To: header\n" - " c:word : match word in Cc: header\n" - " f:word : match word in From: header\n" - " a:word : match word in To:, Cc: or From: headers (address)\n" - " 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" - " bs:word : match word in Subject: header or body (or any other group of prefixes)\n" - " s:word1,word2 : match both words in Subject:\n" - " s:word1/word2 : match either word or both words in Subject:\n" - " s:~word : match messages not containing word in Subject:\n" - " s:substring= : match substring in any word in Subject:\n" - " s:^substring= : match left-anchored substring in any word in Subject:\n" - " s:substring=2 : match substring with <=2 errors in any word in Subject:\n" - "\n" - " (See documentation for more examples)\n" - ); -} - /*}}}*/ -/* Notes on folder management: {{{ - - Assumption is that the user wants to keep the 'mfolder' directories under a - common root with the real maildir folders. This allows a common value for - mutt's 'folder' variable => the '+' and '=' prefixes work better. This - means the indexer here can't just scan down all subdirectories of a single - ancestor, because it'll pick up its own mfolders. So, use environment - variables to tailor the folders. - - MAIRIX_FOLDER_BASE is the common parent directory of the folders (aka - mutt's 'folder' variable) - - MAIRIX_MAILDIR_FOLDERS, MAIRIX_MH_FOLDERS, MAIRIX_MBOXEN are - colon-separated lists of folders to index, with '...' after a - component meaning any maildir underneath it. - - MAIRIX_MFOLDER is the folder to put the match data. - - For example, if - MAIRIX_FOLDER_BASE = "/home/foobar/mail" - MAIRIX_FOLDERS = "inbox:lists...:action:archive..." - MAIRIX_MFOLDER = "mf" - - then /home/foobar/mail/mf/{new,cur,tmp} contain the output of the search. - }}} */ - -int main (int argc, char **argv)/*{{{*/ -{ - struct msgpath_array *msgs; - struct database *db = NULL; - - char *arg_rc_file_path = NULL; - char *arg_mfolder = NULL; - char *e; - int do_augment = 0; - int do_threads = 0; - int do_search = 0; - int do_purge = 0; - int any_updates = 0; - int any_purges = 0; - int do_help = 0; - int do_raw_output = 0; - int do_excerpt_output = 0; - int do_dump = 0; - int do_integrity_checks = 1; - int do_forced_unlock = 0; - int do_fast_index = 0; - - unsigned int forced_hash_key = CREATE_RANDOM_DATABASE_HASH; - - struct globber_array *omit_globs; - - int result; - - setlocale(LC_CTYPE, ""); - - while (++argv, --argc) { - if (!*argv) { - break; - } else if (!strcmp(*argv, "-f") || !strcmp(*argv, "--rcfile")) { - ++argv, --argc; - if (!argc) { - fprintf(stderr, "No filename given after -f argument\n"); - exit(1); - } - arg_rc_file_path = *argv; - } else if (!strcmp(*argv, "-t") || !strcmp(*argv, "--threads")) { - do_search = 1; - do_threads = 1; - } else if (!strcmp(*argv, "-a") || !strcmp(*argv, "--augment")) { - do_search = 1; - do_augment = 1; - } else if (!strcmp(*argv, "-o") || !strcmp(*argv, "--mfolder")) { - ++argv, --argc; - if (!argc) { - fprintf(stderr, "No folder name given after -o argument\n"); - exit(1); - } - arg_mfolder = *argv; - } else if (!strcmp(*argv, "-p") || !strcmp(*argv, "--purge")) { - do_purge = 1; - } else if (!strcmp(*argv, "-d") || !strcmp(*argv, "--dump")) { - do_dump = 1; - } else if (!strcmp(*argv, "-r") || !strcmp(*argv, "--raw-output")) { - do_raw_output = 1; - } else if (!strcmp(*argv, "-x") || !strcmp(*argv, "--excerpt-output")) { - do_excerpt_output = 1; - } else if (!strcmp(*argv, "-H") || !strcmp(*argv, "--force-hardlinks")) { - do_hardlinks = 1; - } else if (!strcmp(*argv, "-M") || !strcmp(*argv, "--force-move")) { - do_movefiles = 1; - } else if (!strcmp(*argv, "-Q") || !strcmp(*argv, "--no-integrity-checks")) { - 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, "--force-hash-key-new-database")) { - ++argv, --argc; - if (!argc) { - fprintf(stderr, "No hash key given after --force-hash-key-new-database\n"); - exit(1); - } - if ( 1 != sscanf(*argv, "%u", &forced_hash_key) ) - { - fprintf(stderr, "Hash key given after --force-hash-key-new-database could not be parsed\n"); - exit(1); - } - } else if (!strcmp(*argv, "-v") || !strcmp(*argv, "--verbose")) { - verbose = 1; - } else if (!strcmp(*argv, "-V") || !strcmp(*argv, "--version")) { - print_version(); - exit(0); - } else if (!strcmp(*argv, "-h") || - !strcmp(*argv, "--help")) { - do_help = 1; - } else if ((*argv)[0] == '-') { - fprintf(stderr, "Unrecognized option %s\n", *argv); - } else if (!strcmp(*argv, "--")) { - /* End of args */ - break; - } else { - /* standard args start */ - break; - } - } - - if (do_help) { - usage(); - exit(0); - } - - if (verbose) { - print_copyright(); - } - - if (*argv) { - /* There are still args to process */ - do_search = 1; - } - - parse_rc_file(arg_rc_file_path); - - if (getenv("MAIRIX_FOLDER_BASE")) { - folder_base = getenv("MAIRIX_FOLDER_BASE"); - } - - if (getenv("MAIRIX_MAILDIR_FOLDERS")) { - maildir_folders = getenv("MAIRIX_MAIDIR_FOLDERS"); - } - - if (getenv("MAIRIX_MH_FOLDERS")) { - mh_folders = getenv("MAIRIX_MH_FOLDERS"); - } - - if ((e = getenv("MAIRIX_MBOXEN"))) { - mboxen = e; - } - - if (getenv("MAIRIX_MFOLDER")) { - mfolder = getenv("MAIRIX_MFOLDER"); - } - - if (getenv("MAIRIX_DATABASE")) { - database_path = getenv("MAIRIX_DATABASE"); - } - - if (arg_mfolder) { - mfolder = arg_mfolder; - } - - if (skip_integrity_checks) { - do_integrity_checks = 0; - } - - if (!folder_base) { - fprintf(stderr, "No folder_base/MAIRIX_FOLDER_BASE set\n"); - exit(2); - } - - if (!database_path) { - fprintf(stderr, "No database/MAIRIX_DATABASE set\n"); - exit(2); - } - - if (do_raw_output) { - output_folder_type = FT_RAW; - } else if (do_excerpt_output) { - output_folder_type = FT_EXCERPT; - } - - if (omit) { - omit_globs = colon_sep_string_to_globber_array(omit); - } else { - omit_globs = NULL; - } - - /* Lock database. - * Prevent concurrent updates due to parallel indexing (e.g. due to stuck - * cron jobs). - * Prevent concurrent searching and indexing. */ - - signal(SIGHUP, handlesig); - signal(SIGINT, handlesig); - signal(SIGQUIT, handlesig); - - lock_database(database_path, do_forced_unlock); - - if (do_dump) { - dump_database(database_path); - result = 0; - - } else if (do_search) { - int len; - char *complete_mfolder; - enum filetype ftype; - - if (!mfolder) { - switch (output_folder_type) { - case FT_RAW: - case FT_EXCERPT: - break; - default: - fprintf(stderr, "No mfolder/MAIRIX_MFOLDER set\n"); - unlock_and_exit(2); - } - mfolder = new_string(""); - } - - /* complete_mfolder is needed by search_top() and member_of() so - compute it once here rather than in search_top() as well */ - if ((mfolder[0] == '/') || - ((mfolder[0] == '.') && (mfolder[1] == '/'))) { - complete_mfolder = new_string(mfolder); - } else { - len = strlen(folder_base) + strlen(mfolder) + 2; - complete_mfolder = new_array(char, len); - strcpy(complete_mfolder, folder_base); - strcat(complete_mfolder, "/"); - strcat(complete_mfolder, mfolder); - } - /* check whether mfolder output would destroy a mail folder or mbox */ - switch (output_folder_type) { - case FT_RAW: - case FT_EXCERPT: - break; - default: - if ((member_of(complete_mfolder,folder_base, maildir_folders, FT_MAILDIR, omit_globs)|| - member_of (complete_mfolder, folder_base, mh_folders, FT_MH, omit_globs) || - member_of (complete_mfolder, folder_base, mboxen, FT_MBOX, omit_globs))) { - fprintf (stderr, - "You asked search results to go to the folder '%s'.\n" - "That folder appears to be one of the indexed mail folders!\n" - "For your own good, I refuse to output search results to an indexed mail folder.\n", - mfolder); - unlock_and_exit(3); - } - } - - ftype = classify_file(database_path); - if (ftype != M_FILE) { - fprintf(stderr, "No database file '%s' is present.\nYou need to do an indexing run first.\n", - database_path); - unlock_and_exit(3); - } - result = search_top(do_threads, do_augment, database_path, complete_mfolder, argv, output_folder_type, verbose); - - } else { - enum filetype ftype; - - if (!maildir_folders && !mh_folders && !mboxen) { - fprintf(stderr, "No [mh_]folders/mboxen/MAIRIX_[MH_]FOLDERS set\n"); - unlock_and_exit(2); - } - - if (verbose) printf("Finding all currently existing messages...\n"); - msgs = new_msgpath_array(); - if (maildir_folders) { - build_message_list(folder_base, maildir_folders, FT_MAILDIR, msgs, omit_globs); - } - if (mh_folders) { - build_message_list(folder_base, mh_folders, FT_MH, msgs, omit_globs); - } - - /* The next call sorts the msgs array as part of looking for duplicates. */ - if (check_message_list_for_duplicates(msgs)) { - fprintf(stderr, "Message list contains duplicates - check your 'folders' setting\n"); - unlock_and_exit(2); - } - - /* Try to open existing database */ - ftype = classify_file(database_path); - if (ftype == M_FILE) { - if (verbose) printf("Reading existing database...\n"); - db = new_database_from_file(database_path, do_integrity_checks); - if (verbose) printf("Loaded %d existing messages\n", db->n_msgs); - } else if (ftype == M_NONE) { - if (verbose) printf("Starting new database\n"); - db = new_database( forced_hash_key ); - } else { - fprintf(stderr, "database path %s is not a file; you can't put the database there\n", database_path); - unlock_and_exit(2); - } - - build_mbox_lists(db, folder_base, mboxen, omit_globs); - - any_updates = update_database(db, msgs->paths, msgs->n, do_fast_index); - if (do_purge) { - any_purges = cull_dead_messages(db, do_integrity_checks); - } - if (any_updates || any_purges) { - /* For now write it every time. This is obviously the most reliable method. */ - write_database(db, database_path, do_integrity_checks); - } - -#if 0 - get_db_stats(db); -#endif - - free_database(db); - free_msgpath_array(msgs); - - result = 0; - } - - unlock_database(); - - return result; -} -/*}}}*/ diff --git a/src/mairix/mairix.h b/src/mairix/mairix.h @@ -1,403 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002,2003,2004,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - - -#ifndef MAIRIX_H -#define MAIRIX_H - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "memmac.h" - -struct msgpath {/*{{{*/ - /* The 'selector' for this union is the corresponding entry of type 'enum - * message_type' */ - union { - struct { - char *path; - size_t size; /* size of the message in bytes */ - time_t mtime; /* mtime of message file on disc */ - } mpf; /* message per file */ - struct { - int file_index; /* index into table of mbox files */ - int msg_index; /* index of message within the file */ - } mbox; /* for messages in mbox format folders */ - } src; - - /* 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 */ -}; -/*}}}*/ - -enum message_type {/*{{{*/ - MTY_DEAD, /* msg no longer exists, i.e. don't report in searches, - prune it on a '-p' run. */ - MTY_FILE, /* msg <-> file in 1-1 correspondence e.g. maildir, MH */ - MTY_MBOX /* multiple msgs per file : MBOX format file */ -}; -/*}}}*/ -struct msgpath_array {/*{{{*/ - enum message_type *type; - struct msgpath *paths; - int n; - int max; -}; -/*}}}*/ - -struct matches {/*{{{*/ - unsigned char *msginfo; - int n; /* bytes in use */ - int max; /* bytes allocated */ - unsigned long highest; -}; -/*}}}*/ -struct token {/*{{{*/ - char *text; - unsigned long hashval; - /* to store delta-compressed info of which msgpaths match the token */ - struct matches match0; -}; -/*}}}*/ -struct token2 {/*{{{*/ - char *text; - unsigned long hashval; - /* to store delta-compressed info of which msgpaths match the token */ - struct matches match0; - struct matches match1; -}; -/*}}}*/ -struct toktable {/*{{{*/ - struct token **tokens; - int n; /* # in use */ - int size; /* # allocated */ - unsigned int mask; /* for masking down hash values */ - int hwm; /* number to have before expanding */ -}; -/*}}}*/ -struct toktable2 {/*{{{*/ - struct token2 **tokens; - int n; /* # in use */ - int size; /* # allocated */ - unsigned int mask; /* for masking down hash values */ - int hwm; /* number to have before expanding */ -}; -/*}}}*/ - -enum content_type {/*{{{*/ - CT_TEXT_PLAIN, - CT_TEXT_HTML, - CT_TEXT_OTHER, - CT_MESSAGE_RFC822, - CT_OTHER -}; -/*}}}*/ -struct rfc822; -struct attachment {/*{{{*/ - struct attachment *next; - struct attachment *prev; - enum content_type ct; - char *filename; - union attachment_body { - struct normal_attachment_body { - int len; - char *bytes; - } normal; - struct rfc822 *rfc822; - } data; -}; -/*}}}*/ -struct headers {/*{{{*/ - char *to; - char *cc; - char *from; - char *subject; - - /* The following are needed to support threading */ - char *message_id; - char *in_reply_to; - char *references; - - struct { - unsigned int seen:1; - unsigned int replied:1; - unsigned int flagged:1; - } flags; - - time_t date; -}; -/*}}}*/ -struct rfc822 {/*{{{*/ - struct headers hdrs; - struct attachment atts; -}; -/*}}}*/ - -typedef char checksum_t[16]; - -struct message_list {/*{{{*/ - struct message_list *next; - off_t start; - size_t len; -}; -/*}}}*/ -struct mbox {/*{{{*/ - /* If path==NULL, this indicates that the mbox is dead, i.e. no longer - * exists. */ - char *path; - /* As read in from database (i.e. current last time mairix scan was run.) */ - time_t file_mtime; - size_t file_size; - /* As found in the filesystem now. */ - time_t current_mtime; - size_t current_size; - /* After reconciling a loaded database with what's on the disc, this entry - stores how many of the msgs that used to be there last time are still - present at the head of the file. Thus, all messages beyond that are - treated as dead, and scanning starts at that point to find 'new' messages - (whch may actually be old ones that have moved, but they're treated as - new.) */ - int n_old_msgs_valid; - - /* Hold list of new messages and their number. Number is temporary - - * eventually just list walking in case >=2 have to be reattached. */ - struct message_list *new_msgs; - int n_new_msgs; - - int n_so_far; /* Used during database load. */ - - int n_msgs; /* Number of entries in 'start' and 'len' */ - int max_msgs; /* Allocated size of 'start' and 'len' */ - /* File offset to the start of each message (first line of real header, not to mbox 'From ' line) */ - off_t *start; - /* Length of each message */ - size_t *len; - /* Checksums on whole messages. */ - checksum_t *check_all; - -}; -/*}}}*/ -struct database {/*{{{*/ - /* Used to hold an entire mapping between an array of filenames, each - containing a single message, and the sets of tokens that occur in various - parts of those messages */ - - enum message_type *type; - struct msgpath *msgs; /* Paths to messages */ - int n_msgs; /* Number in use */ - int max_msgs; /* Space allocated */ - - struct mbox *mboxen; - int n_mboxen; /* number in use. */ - int max_mboxen; /* space allocated */ - - /* Seed for hashing in the token tables. Randomly created for - * each new database - avoid DoS attacks through carefully - * crafted messages. */ - unsigned int hash_key; - - /* Token tables */ - struct toktable *to; - struct toktable *cc; - 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. - * Encoding chain 1 stores just the Message-Id. Used for search by message ID. - */ - struct toktable2 *msg_ids; -}; -/*}}}*/ - -enum folder_type {/*{{{*/ - FT_MAILDIR, - FT_MH, - FT_MBOX, - FT_RAW, - FT_EXCERPT -}; -/*}}}*/ - -struct string_list {/*{{{*/ - struct string_list *next; - struct string_list *prev; - char *data; -}; -/*}}}*/ - -struct msg_src { - enum {MS_FILE, MS_MBOX} type; - char *filename; - off_t start; - size_t len; -}; - -/* Outcomes of checking a filename/dirname to see whether to keep on looking - * at filenames within this dir. */ -enum traverse_check { - TRAV_PROCESS, /* Continue looking at this entry */ - TRAV_IGNORE, /* Ignore just this dir entry */ - TRAV_FINISH /* Ignore this dir entry and don't bother looking at the rest of the directory */ -}; - -struct traverse_methods { - int (*filter)(const char *, const struct stat *); - enum traverse_check (*scrutinize)(int, const char *); -}; - -extern struct traverse_methods maildir_traverse_methods; -extern struct traverse_methods mh_traverse_methods; -extern struct traverse_methods mbox_traverse_methods; - -extern int verbose; /* cmd line -v switch */ -extern int do_hardlinks; /* cmd line -H switch */ -extern int do_movefiles; /* cmd line -M switch */ - -/* Lame fix for systems where NAME_MAX isn't defined after including the above - * set of .h files (Solaris, FreeBSD so far). Probably grossly oversized but - * it'll do. */ - -#if !defined(NAME_MAX) -#define NAME_MAX 4096 -#endif - -/* In glob.c */ -struct globber; -struct globber_array; - -struct globber *make_globber(const char *wildstring); -void free_globber(struct globber *old); -int is_glob_match(struct globber *g, const char *s); -struct globber_array *colon_sep_string_to_globber_array(const char *in); -int is_globber_array_match(struct globber_array *ga, const char *s); -void free_globber_array(struct globber_array *in); - -/* In hash.c */ -unsigned int hashfn( unsigned char *k, unsigned int length, unsigned int initval); - -/* In dirscan.c */ -struct msgpath_array *new_msgpath_array(void); -int valid_mh_filename_p(const char *x); -void free_msgpath_array(struct msgpath_array *x); -void string_list_to_array(struct string_list *list, int *n, char ***arr); -void split_on_colons(const char *str, int *n, char ***arr); -void build_message_list(char *folder_base, char *folders, enum folder_type ft, - struct msgpath_array *msgs, struct globber_array *omit_globs); - -/* In rfc822.c */ -struct rfc822 *make_rfc822(char *filename); -void free_rfc822(struct rfc822 *msg); -enum data_to_rfc822_error { - DTR8_OK, - DTR8_MISSING_END, /* missing endpoint marker. */ - DTR8_MULTIPART_SANS_BOUNDARY, /* multipart with no boundary string defined */ - DTR8_BAD_HEADERS, /* corrupt headers */ - DTR8_BAD_ATTACHMENT /* corrupt attachment (e.g. no body part) */ -}; -struct rfc822 *data_to_rfc822(struct msg_src *src, char *data, int length, enum data_to_rfc822_error *error); -void create_ro_mapping(const char *filename, unsigned char **data, int *len); -void free_ro_mapping(unsigned char *data, int len); -char *format_msg_src(struct msg_src *src); - -/* In tok.c */ -struct toktable *new_toktable(void); -struct toktable2 *new_toktable2(void); -void free_token(struct token *x); -void free_token2(struct token2 *x); -void free_toktable(struct toktable *x); -void free_toktable2(struct toktable2 *x); -void add_token_in_file(int file_index, unsigned int hash_key, char *tok_text, struct toktable *table); -void check_and_enlarge_encoding(struct matches *m); -void insert_index_on_encoding(struct matches *m, int idx); -void add_token2_in_file(int file_index, unsigned int hash_key, char *tok_text, struct toktable2 *table, int add_to_chain1); - -/* In db.c */ -#define CREATE_RANDOM_DATABASE_HASH 0 -struct database *new_database(unsigned int hash_key); -struct database *new_database_from_file(char *db_filename, int do_integrity_checks); -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 do_fast_index); -void check_database_integrity(struct database *db); -int cull_dead_messages(struct database *db, int do_integrity_checks); - -/* In mbox.c */ -void build_mbox_lists(struct database *db, const char *folder_base, - const char *mboxen_paths, struct globber_array *omit_globs); -int add_mbox_messages(struct database *db); -void compute_checksum(const char *data, size_t len, checksum_t *csum); -void cull_dead_mboxen(struct database *db); -unsigned int encode_mbox_indices(unsigned int mb, unsigned int msg); -void decode_mbox_indices(unsigned int index, unsigned int *mb, unsigned int *msg); -int verify_mbox_size_constraints(struct database *db); -void glob_and_expand_paths(const char *folder_base, char **paths_in, int n_in, char ***paths_out, int *n_out, const struct traverse_methods *methods, struct globber_array *omit_globs); - -/* In glob.c */ -struct globber; - -struct globber *make_globber(const char *wildstring); -void free_globber(struct globber *old); -int is_glob_match(struct globber *g, const char *s); - -/* In writer.c */ -void write_database(struct database *db, char *filename, int do_integrity_checks); - -/* In search.c */ -int search_top(int do_threads, int do_augment, char *database_path, char *complete_mfolder, char **argv, enum folder_type ft, int verbose); - -/* In stats.c */ -void get_db_stats(struct database *db); - -/* In dates.c */ -int scan_date_string(char *in, time_t *start, int *has_start, time_t *end, int *has_end); - -/* In dumper.c */ -void dump_database(char *filename); - -/* In strexpand.c */ -char *expand_string(const char *p); - -/* In dotlock.c */ -void lock_database(char *path, int forced_unlock); -void unlock_database(void); -void unlock_and_exit(int code); - -/* In mairix.c */ -void report_error(const char *str, const char *filename); - -#endif /* MAIRIX_H */ diff --git a/src/mairix/mairix.spec b/src/mairix/mairix.spec @@ -1,45 +0,0 @@ -Name: mairix -Summary: A maildir indexer and searcher -Version: 0.23 -Release: 1 -Source: %{name}-%{version}.tar.gz -License: GPL -Group: Application/Internet -Packager: Richard P. Curnow -BuildRoot: %{_tmppath}/%{name}-%{version}-root-%(id -u -n) -Requires: info -URL: http://www.rc0.org.uk/mairix - -%description -mairix is a tool for indexing email messages stored in maildir format folders -and performing fast searches on the resulting index. The output is a new -maildir folder containing symbolic links to the matched messages. - -%prep -%setup -q - -%build -CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{_prefix} -make - -%install -rm -rf $RPM_BUILD_ROOT -cd $RPM_BUILD_DIR/mairix-%{version} -make install DESTDIR=$RPM_BUILD_ROOT mandir=$RPM_BUILD_ROOT/%{_mandir} -cp README dotmairixrc.eg .. - -%files -%{_bindir}/mairix -%doc README -%doc dotmairixrc.eg -%doc %{_mandir}/man1/mairix.1.gz -%doc %{_mandir}/man5/mairixrc.5.gz - -%changelog -* Fri Mar 24 2006 Andre Costa <blueser@gmail.com> - 0.18 -- Updated to version 0.18 -- Included URL on header -- removed references to 'mairix.txt', 'mairix.html' and 'mairix.info' -- .info files have been deprecated -- removed useless 'post' section -- makefile's "mandir" is pointing to /usr/man instead of /usr/share/man diff --git a/src/mairix/mairixrc.5 b/src/mairix/mairixrc.5 @@ -1,405 +0,0 @@ -.TH MAIRIXRC 5 "January 2006" -.de Sx -.PP -.ne \\$1 -.nf -.na -.RS 12 -.. -.de Ex -.RE -.fi -.ad -.IP "" 7 -.. -.SH NAME -mairixrc \- configuration file for mairix(1) -.SH SYNOPSIS -$HOME/.mairixrc -.SH DESCRIPTION -.PP -The -.I mairixrc -file tells -.B mairix -where your mail folders are located. It also tells -.B mairix -where the results of searches are to be written. - -.B mairix -searches for this file at -.I $HOME/.mairixrc -unless the -.B -f -option is used. - -The directives -.BR base , -.BR mfolder , -and -.B database -must always appear in the file. There must also be some folder definitions -(using the -.BR maildir , -.BR mh , -or -.BR mbox ) -directives. - -.SS Comments -Any line starting with a '#' character is treated as a comment. - -.SS Directives -.TP -.BI base= base-directory -.br -This defines the path to the common parent directory of all your -maildir folders. - -If the path is relative, it is treated as relative to the location of the -.I mairixrc -file. - -.TP -.BI maildir= list-of-folder-specifications -This is a colon-separated list of the Maildir folders (relative to -`base') that you want indexed. Any entry that ends `...' is -recursively scanned to find any Maildir folders underneath it. - -More than one line starting with `maildir' can be included. In -this case, mairix joins the lines together with colons as though a -single list of folders had been given on a single very long line. - -Each colon-separated entry may be a wildcard. See the discussion -under mbox (below) for the wildcard syntax. For example -.Sx 1 -maildir=zzz/foo*... -.Ex -will match maildir folders like these (relative to the -.IR base-directory ) -.Sx 4 -zzz/foobar/xyz -zzz/fooquux -zzz/foo -zzz/fooabc/u/v/w -.Ex - -and -.Sx 1 -maildir=zzz/foo[abc]* -.Ex -will match maildir folders like these (relative to the folder_base) -.Sx 4 -zzz/fooa -zzz/fooaaaxyz -zzz/foobcd -zzz/fooccccccc -.Ex -If a folder name contains a colon, you can write this by using the -sequence '\\:' to escape the colon. Otherwise, the backslash -character is treated normally. (If the folder name actually -contains the sequence '\\:', you're out of luck.) - -.TP -.BI mh= list-of-folder-specifications -.br -This is a colon-separated list of the MH folders (relative to -`base') that you want indexed. Any entry that ends '...' is -recursively scanned to find any MH folders underneath it. - -More than one line starting with 'mh' can be included. In this -case, mairix joins the lines together with colons as though a -single list of folders had been given on a single very long line. - -Each colon-separated entry may be a wildcard, see the discussion -under maildir (above) and mbox (below) for the syntax and -semantics of specifying wildcards. - -.b mairix -recognizes the types of MH folders created by the following email applications: -.RS 7 -.IP "*" -xmh -.IP "*" -sylpheed -.IP "*" -claws-mail -.IP "*" -evolution -.IP "*" -NNML -.IP "*" -Mew -.RE - -.TP -.BI mbox= list-of-folder-specifications -.br -This is a colon-separated list of the mbox folders (relative to -`base') that you want indexed. - -Each colon-separated item in the list can be suffixed by '...'. -If the item matches a regular file, that file is treated as a mbox -folder and the '...' suffix is ignored. If the item matches a -directory, a recursive scan of everything inside that directory is -made, and all regular files are initially considered as mbox -folders. (Any directories found in this scan are themselves -scanned, since the scan is recursive.) - -Each colon-separated item may contain wildcard operators, but only -in its final path component. The wildcard operators currently -supported are - -.TP -* -.br -Match zero or more characters (each character matched is -arbitrary) - -.TP -? -.br -Match exactly one arbitrary character - -.TP -[abcs-z] -.br -Character class : match a single character from the set a, b, -c, s, t, u, v, w, x, y and z. - -To include a literal ']' in the class, place it immediately -after the opening '['. To include a literal '-' in the -class, place it immediately before the closing ']'. - -If these metacharacters are included in non-final path components, -they have no special meaning. - -Here are some examples - -.TP -mbox=foo/bar* -.br -matches 'foo/bar', 'foo/bar1', 'foo/barrrr' etc - -.TP -mbox=foo*/bar* -.br -matches 'foo*/bar', 'foo*/bar1', 'foo*/barrrr' etc - -.TP -mbox=foo/* -.br -matches 'foo/bar', 'foo/bar1', 'foo/barrrr', 'foo/foo', -\'foo/x' etc - -.TP -mbox=foo... -.br -matches any regular file in the tree rooted at 'foo' - -.TP -mbox=foo/*... -.br -same as before - -.TP -mbox=foo/[a-z]*... -.br -matches 'foo/a', 'foo/aardvark/xxx', 'foo/zzz/foobar', -\'foo/w/x/y/zzz', but not 'foo/A/foobar' - -Regular files that are mbox folder candidates are examined -internally. Only files containing standard mbox 'From ' separator -lines will be scanned for messages. - -If a regular file has a name ending in '.gz', and gzip support is -compiled into the -.B mairix -binary, the file will be treated as a gzipped mbox. - -If a regular file has a name ending in '.bz2', and bzip support is -compiled into the -.B mairix -binary, the file will be treated as a bzip2'd mbox. - -More than one line starting with 'mbox' can be included. In this -case, -.B mairix -joins the lines together with colons as though a -single list of folders had been given on a single very long line. - -.B mairix -performs no locking of mbox folders when it is accessing -them. If a mail delivery program is modifying the mbox at the -same time, it is likely that one or messages in the mbox will -never get indexed by -.B mairix -(until the database is removed and recreated from scratch, anyway.) The -assumption is that -.B mairix -will be used to index archive folders rather than incoming ones, so this is -unlikely to be much of a problem in reality. - -.B mairix -can support a maximum of 65536 separate mboxes, and a -maximum of 65536 messages within any one mbox. - -.TP -.BI omit= list-of-glob-patterns -This is a colon-separated list of glob patterns for folders to be omitted from -the indexing. This allows wide wildcards and recursive elements to be used -in the -.BR maildir , mh ", and" mbox -directives, with the -.B omit -option used to selectively remove unwanted folders from the folder -lists. - -Within the glob patterns, a single '*' matches any -sequence of characters other than '/'. However '**' matches any -sequence of characters including '/'. This allows glob patterns -to be constructed which have a wildcard for just one directory -component, or for any number of directory components. - -The _omit_ option can be specified as many times as required so -that the list of patterns doesn't all have to fit on one line. - -As an example, -.Sx 2 -mbox=bulk... -omit=bulk/spam* -.Ex -will index all mbox folders at any level under the 'bulk' -subdirectory of the base folder, except for those folders whose -names start 'bulk/spam', e.g. 'bulk/spam', 'bulk/spam2005' etc. - -In constrast, -.Sx 2 -mbox=bulk... -omit=bulk/spam** -.Ex -will index all mbox folders at any level under the 'bulk' -subdirectory of the base folder, except for those folders whose -names start 'bulk/spam', e.g. 'bulk/spam', 'bulk/spam2005', -\'bulk/spam/2005', 'bulk/spam/2005/jan' etc. - -.TP -.B nochecks -This takes no arguments. If a line starting with -.B nochecks is -present, it is the equivalent of specifying the -.B -Q -flag to every indexing run. - -.TP -.BI mfolder= match-folder-name -This defines the name of the folder (within the directory -specified by -.BR base ) -into which the search mode writes its output. (If the -.B mformat -used is 'raw' or 'excerpt', then this setting is not used and may be omitted.) - -The -.B mfolder -setting may be over-ridden for a particular search by using the -.B -o -option to -.BR mairix . - -.B mairix -will refuse to output search results to a folder that appears to be amongst -those that are indexed. This is to prevent accidental deletion of emails. - -If the first character of the mfolder value is '/' or '.', it is -taken as a pathname in its own right. This allows you to specify -absolute paths and paths relative to the current directory where -the mfolder should be written. Otherwise, the value of mfolder is -appended to the value of base, in the same way as for the source -folders. - -.TP -.BI mformat= format -This defines the type of folder used for the match folder where -the search results go. There are four valid settings for -.IR format , -namely 'maildir', 'mh', 'mbox', 'raw' or 'excerpt'. If the 'raw' setting is -used then -.B mairix -will just print out the path names of the files that match and no match folder -will be created. If the 'excerpt' setting is used, -.B mairix -will also print out the To:, Cc:, From:, Subject: and Date: headers of the -matching messages. 'maildir' is the default if this option is not -defined. The setting is case-insensitive. - -.TP -.BI database= path-to-database -.br -This defines the path where -.BR mairix 's -index database is kept. You can keep this file anywhere you like. - -Currently, -.B mairix -will place a single database file at the location indicated by -.IR path-to-database . -However, a future version of -.B mairix -may instead place a directory containing several files at this location. - -.I path-to-database -should be an absolute pathname (starting with '/'). If a relative pathname is -used, it will be interpreted relative to the current directory at the time -.B mairix -is run, -.RB ( not -relative to the location of the -.I mairixrc -file or anything like that.) - -.SS Expansions - -The part of each line in '.mairixrc' following the equals sign can -contain the following types of expansion: - -.TP -.B Home directory expansion -If the sequence '~/' appears at the start of the text after the -equals sign, it is expanded to the user's home directory. Example: -.Sx 1 -database=~/Mail/mairix_database -.Ex -.TP -.B Environment expansion -If a '$' is followed by a sequence of alpha-numeric characters (or -\'_'), the whole string is replaced by looking up the corresponding -environment variable. Similarly, if '$' is followed by an open -brace ('{'), everything up to the next close brace is looked up as -an environment variable and the result replaces the entire -sequence. - -Suppose in the shell we do -.Sx 1 -export FOO=bar -.Ex -and the '.mairixrc' file contains -.Sx 2 -maildir=xxx/$FOO -mbox=yyy/a${FOO}b -.Ex -this is equivalent to -.Sx 2 -maildir=xxx/bar -mbox=yyy/abarb -.Ex -If the specified environment variable is not set, the replacement -is the empty string. - -.SH NOTES -.PP -An alternative path to the configuration file may be given with the -.B \-f -option to mairix(1). - - diff --git a/src/mairix/mbox.c b/src/mairix/mbox.c @@ -1,1060 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2003,2004,2005,2006,2007 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <assert.h> -#include <dirent.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include "mairix.h" -#include "from.h" -#include "fromcheck.h" -#include "md5.h" - -struct extant_mbox {/*{{{*/ - char *full_path; - time_t mtime; - size_t size; - int db_index; - /* + stuff to store positions etc of individual messages. */ -}; -/*}}}*/ -static int compare_extant_mboxen(const void *a, const void *b)/*{{{*/ -{ - const struct extant_mbox *aa = (const struct extant_mbox *) a; - const struct extant_mbox *bb = (const struct extant_mbox *) b; - return strcmp(aa->full_path, bb->full_path); -} -/*}}}*/ -static int lookup_extant_mbox(struct extant_mbox *sorted_mboxen, int n_extant, char *key)/*{{{*/ -{ - /* Implement bisection search */ - int l, h, m, r; - l = 0, h = n_extant; - m = -1; - while (h > l) { - m = (h + l) >> 1; - /* Should only get called on 'file' type messages - TBC */ - r = strcmp(sorted_mboxen[m].full_path, key); - if (r == 0) break; - if (l == m) return -1; - if (r > 0) h = m; - else l = m; - } - return m; -} -/*}}}*/ -static void append_new_mboxen_to_db(struct database *db, struct extant_mbox *extant_mboxen, int n_extant)/*{{{*/ -{ - int N, n_reqd; - int i, j; - - for (i=N=0; i<n_extant; i++) { - if (extant_mboxen[i].db_index < 0) N++; - } - - n_reqd = db->n_mboxen + N; - if (n_reqd > db->max_mboxen) { - db->max_mboxen = n_reqd; - db->mboxen = grow_array(struct mbox, n_reqd, db->mboxen); - } - /* Init new entries. */ - for (j=0, i=db->n_mboxen; j<n_extant; j++) { - if (extant_mboxen[j].db_index < 0) { - db->mboxen[i].path = new_string(extant_mboxen[j].full_path); - db->mboxen[i].current_mtime = extant_mboxen[j].mtime; - db->mboxen[i].current_size = extant_mboxen[j].size; - db->mboxen[i].file_mtime = 0; - db->mboxen[i].file_size = 0; - db->mboxen[i].n_msgs = 0; - db->mboxen[i].n_old_msgs_valid = 0; - db->mboxen[i].max_msgs = 0; - db->mboxen[i].start = NULL; - db->mboxen[i].len = NULL; - db->mboxen[i].check_all = NULL; - i++; - } - } - - db->n_mboxen = n_reqd; -} -/*}}}*/ -void compute_checksum(const char *data, size_t len, checksum_t *csum)/*{{{*/ -{ - MD5_CTX md5; - MD5Init(&md5); - MD5Update(&md5, (unsigned char *) data, len); - MD5Final(&md5); - memcpy(csum, md5.digest, sizeof(md5.digest)); - return; -} -/*}}}*/ -static int message_is_intact(struct mbox *mb, int idx, char *va, size_t len)/*{{{*/ -{ - /* TODO : later, look at whether to optimise this in some way, e.g. by doing - an initial check on just the first 1k of a message, this will detect - failures much faster at the cost of extra storage. */ - - if (mb->start[idx] + mb->len[idx] > len) { - /* Message overruns the end of the file - can't possibly be intact. */ - return 0; - } else { - checksum_t csum; - compute_checksum(va + mb->start[idx], mb->len[idx], &csum); - if (!memcmp(mb->check_all[idx], &csum, sizeof(checksum_t))) { - return 1; - } else { - return 0; - } - } - return 0; -} -/*}}}*/ -static int find_number_intact(struct mbox *mb, char *va, size_t len)/*{{{*/ -{ - /* Pick up the common obvious case first - where new messages have been appended to the - end of the mbox */ - if (mb->n_msgs == 0) { - return 0; - } else if (message_is_intact(mb, mb->n_msgs - 1, va, len)) { - return mb->n_msgs; /* The lot */ - } else if (!message_is_intact(mb, 0, va, len)) { - return 0; /* None of them. */ - } else { - /* Looks like a deletion has occurred earlier in the file => binary chop - search to find the last message that's still valid. Assume that - everything below a valid message is still valid itself (possibly - dangerous assumption, time will tell.) */ - - int l, m, h; - l = 0; - h = mb->n_msgs; - /* Loop invariant : always, mesasage[l] is intact, message[h] isn't. */ - while (l < h) { - m = (h + l) >> 1; - if (m==l) break; - if (message_is_intact(mb, m, va, len)) { - l = m; - } else { - h = m; - } - } - /* By loop invariant, message[l] is the highest valid one. */ - return (l + 1); - } -} -/*}}}*/ - - -static int fromtab_inited = 0; -static signed char fromtab[256]; - -static void init_fromtab(void)/*{{{*/ -{ - memset(fromtab, 0xff, 256); - fromtab[(int)(unsigned char)'\n'] = ~(1<<0); - fromtab[(int)(unsigned char)'F'] = ~(1<<1); - fromtab[(int)(unsigned char)'r'] = ~(1<<2); - fromtab[(int)(unsigned char)'o'] = ~(1<<3); - fromtab[(int)(unsigned char)'m'] = ~(1<<4); - fromtab[(int)(unsigned char)' '] = ~(1<<5); -} -/*}}}*/ - -/* REAL CHECKING : need to see if the line looks like this: - * From [ <return-path> ] <weekday> <month> <day> <time> [ <timezone> ] <year> - (from the mutt sources). - * where timezone can be two words rather than one sometimes. */ - -#undef DEBUG_DFA - -static int looks_like_from_separator(off_t n, char *va, size_t len, int verbose)/*{{{*/ -{ - char p; - int current_state = 0; - int result = 0; - - n++; /* look beyond the space. */ - - while (n < len) { - p = va[n++]; - if (verbose) { - printf("current_state=%d, p=%02x (%1c) ", current_state, (int)(unsigned char)p, ((p>=32)&&(p<=126))?p:'.'); - } - current_state = fromcheck_next_state(current_state, (int)fromcheck_char2tok[(int)(unsigned char)p]); - if (verbose) { - printf("next_state=%d\n", current_state); - } - if (current_state < 0) { - /* not matched */ - break; - } - if (fromcheck_attr[current_state] == FROMCHECK_PASS) { - result = 1; /* matched good separator */ - break; - } - } - - /* If we hit the end of the file, it doesn't look like a real 'From' line. */ -#ifdef DEBUG_DFA - unlock_and_exit(0); -#endif - return result; -} -/*}}}*/ - -static off_t find_next_from(off_t n, char *va, size_t len)/*{{{*/ -{ - unsigned char c; - unsigned long hit; - unsigned long reg; - unsigned long mask; - - if (!n) { - if ((len >= 5) && !strncmp(va, "From ", 5)) { - return 0; - } - } - -scan_again: - - reg = (unsigned long) -1; - hit = ~(1<<5); - while (n < len) { - c = va[n]; - mask = (unsigned long)(signed long) fromtab[(int)c]; - reg = (reg << 1) | mask; - if (~(reg|hit)) { - if (looks_like_from_separator(n, va, len, 0)) { - return (n-4); - } else { -#if 0 - int nn; - printf("Rejecting from line at %d\n", n); - nn = n; - printf(" >> "); - while (nn < len) { - unsigned char c = va[nn++]; - putchar(c); - if (c=='\n') break; - } - looks_like_from_separator(n, va, len, 1); -#endif - goto scan_again; - } - } - n++; - } - return -1; -} -/*}}}*/ -static off_t start_of_next_line(off_t n, char *va, size_t len)/*{{{*/ -{ - unsigned char c; - /* We are always starting from 'From ' so we can advance before testing */ - do { - c = va[n]; - n++; - } - while ((n < len) && (c != '\n')); - if (n == len) { - return -1; - } else { - return n; - } -} -/*}}}*/ - - -static struct message_list *build_new_message_list(struct mbox *mb, char *va, size_t len, int *n_messages)/*{{{*/ -{ - struct message_list *result, *here, *next; - off_t start_from, start_pos, end_from; - int old_percent = -100; - int N; - -#define PERCENT_GRAN 2 - - *n_messages = 0; - - result = here = NULL; - N = mb->n_old_msgs_valid; - if (N == 0) { - start_from = 0; - } else { - /* Must point to the \n at the end of the preceding message, otherwise the - 'From ' at the start of the first message in the section to be rescanned - won't get detected and that message won't get indexed. */ - start_from = mb->start[N - 1] + mb->len[N - 1] - 1; - } - - if (!fromtab_inited) { - init_fromtab(); - fromtab_inited = 1; - } - - /* Locate next 'From ' at the start of a line */ - start_from = find_next_from(start_from, va, len); - while (start_from != -1) { - start_pos = start_of_next_line(start_from, va, len); - if (start_pos == -1) { - /* Something is awry. */ - goto done; - } - if (verbose) { - int percent; - percent = (int)(0.5 + 100.0 * (double) start_pos / (double) len); - if (percent > (old_percent+PERCENT_GRAN)) { - printf("Scanning mbox %s : %3d%% done\r", mb->path, percent); - fflush(stdout); - old_percent = percent; - } - } - - end_from = find_next_from(start_pos, va, len); - next = new(struct message_list); - next->next = NULL; - next->start = start_pos; - if (end_from == -1) { - /* message runs through to end of file. */ - next->len = len - start_pos; - } else { - next->len = end_from - start_pos; - } - if (!result) { - result = here = next; - } else { - here->next = next; - here = next; - } - ++*n_messages; - start_from = end_from; - } - -done: - if (verbose) { - printf("Scanning mbox %s : 100%% done\n", mb->path); - fflush(stdout); - } - return result; - -} -/*}}}*/ -static void rescan_mbox(struct mbox *mb, char *va, size_t len)/*{{{*/ -{ - /* We get here if it's determined that - * 1. the mbox file still exists - * 2. the mtime or size has changed, i.e. it's been modified in some way - since the last mairix run. - */ - - /* Find the last message in the box that appears to be intact. */ - mb->n_old_msgs_valid = find_number_intact(mb, va, len); - mb->new_msgs = build_new_message_list(mb, va, len, &mb->n_new_msgs); -} -/*}}}*/ -static void deaden_mbox(struct mbox *mb)/*{{{*/ -{ - mb->n_old_msgs_valid = 0; - mb->n_msgs = 0; - - free(mb->path); - mb->path = NULL; - - if (mb->max_msgs > 0) { - free(mb->start); - free(mb->len); - free(mb->check_all); - mb->max_msgs = 0; - } -} -/*}}}*/ -static void marry_up_mboxen(struct database *db, struct extant_mbox *extant_mboxen, int n_extant)/*{{{*/ -{ - int *old_to_new_idx; - int i; - - for (i=0; i<n_extant; i++) extant_mboxen[i].db_index = -1; - - old_to_new_idx = NULL; - if (db->n_mboxen > 0) { - old_to_new_idx = new_array(int, db->n_mboxen); - for (i=0; i<db->n_mboxen; i++) old_to_new_idx[i] = -1; - - for (i=0; i<db->n_mboxen; i++) { - if (db->mboxen[i].path) { - int idx; - idx = lookup_extant_mbox(extant_mboxen, n_extant, db->mboxen[i].path); - if (idx >= 0) { - struct mbox *mb = &db->mboxen[i]; - old_to_new_idx[i] = idx; - extant_mboxen[idx].db_index = i; - mb->current_mtime = extant_mboxen[idx].mtime; - mb->current_size = extant_mboxen[idx].size; - } - } - } - } - - for (i=0; i<db->n_mboxen; i++) { - if (old_to_new_idx[i] < 0) { - /* old mbox is no more. */ - deaden_mbox(&db->mboxen[i]); - } - } - - /* Append entries for newly discovered mboxen */ - append_new_mboxen_to_db(db, extant_mboxen, n_extant); - - /* From here on, everything we need is in the db */ - if (old_to_new_idx) - free(old_to_new_idx); - -} -/*}}}*/ -static void check_duplicates(struct extant_mbox *extant_mboxen, int n_extant)/*{{{*/ -{ - /* Note, list is sorted at this point */ - int i; - int any_dupl = 0; - for (i=0; i<n_extant-1; i++) { - if (!strcmp(extant_mboxen[i].full_path, extant_mboxen[i+1].full_path)) { - printf("mbox %s is listed twice in the mairixrc file\n", extant_mboxen[i].full_path); - any_dupl = 1; - } - } - if (any_dupl) { - printf("Exiting, the mairixrc file needs fixing\n"); - unlock_and_exit(1); - } -} -/*}}}*/ -static char *find_last_slash(char *in)/*{{{*/ -{ - char *p = in; - char *result = NULL; - while (*p) { - if (*p == '/') result = p; - p++; - } - return result; -} -/*}}}*/ -static int append_shallow(char *path, int base_len, struct stat *sb, struct string_list *list, /*{{{*/ - const struct traverse_methods *methods, - struct globber_array *omit_globs) -{ - int result = 0; - if ((methods->filter)(path, sb)) { - if (!is_globber_array_match(omit_globs, path + base_len)) { - struct string_list *nn = new(struct string_list); - nn->data = new_string(path); - nn->next = list; - nn->prev = list->prev; - list->prev->next = nn; - list->prev = nn; - result = 1; - } - } - return result; -} -/*}}}*/ -static int append_deep(char *path, int base_len, struct stat *sb, struct string_list *list, /*{{{*/ - const struct traverse_methods *methods, - struct globber_array *omit_globs) -{ - /* path is dir : read its contents, call append_shallow or self accordingly. */ - /* path is file : call append_shallow. */ - struct stat sb2; - char *xpath; - DIR *d; - struct dirent *de; - int appended_any = 0; - int this_file_matched; - - this_file_matched = append_shallow(path, base_len, sb, list, methods, omit_globs); - appended_any |= this_file_matched; - - if (S_ISDIR(sb->st_mode)) { - xpath = new_array(char, strlen(path) + 2 + NAME_MAX); - d = opendir(path); - if (d) { - while ((de = readdir(d))) { - enum traverse_check status; - if (!strcmp(de->d_name, ".")) continue; - if (!strcmp(de->d_name, "..")) continue; - strcpy(xpath, path); - strcat(xpath, "/"); - strcat(xpath, de->d_name); - if (!is_globber_array_match(omit_globs, xpath+base_len)) { - /* Filter out omissions at this point, e.g. to avoid wasting time on - * a recursive expansion of a tree that's going to get pruned in at - * the deepest level anyway. */ - status = (methods->scrutinize)(this_file_matched, de->d_name); -#if 0 - /* debugging */ - fprintf(stderr, "scrutinize for %s in %s returned %s\n", - de->d_name, - path, - (status == TRAV_FINISH) ? "FINISH" : - (status == TRAV_IGNORE) ? "IGNORE" : "PROCESS"); -#endif - switch (status) { - case TRAV_FINISH: - goto done_this_dir; - case TRAV_IGNORE: - goto next_path; - case TRAV_PROCESS: - if (stat(xpath, &sb2) >= 0) { - if (S_ISREG(sb2.st_mode)) { - appended_any |= append_shallow(xpath, base_len, &sb2, list, methods, omit_globs); - } else if (S_ISDIR(sb2.st_mode)) { - appended_any |= append_deep(xpath, base_len, &sb2, list, methods, omit_globs); - } - } - break; - } - } -next_path: - (void) 0; - } -done_this_dir: - closedir(d); - } - free(xpath); - } - return appended_any; -} -/*}}}*/ -static void handle_wild(char *path, int base_len, char *last_comp, struct string_list *list,/*{{{*/ - int (*append)(char *, int, struct stat *, struct string_list *, - const struct traverse_methods *, struct globber_array *), - const struct traverse_methods *methods, - struct globber_array *omit_globs) -{ - /* last_comp is the character within 'path' where the wildcard stuff starts. */ - struct globber *gg; - char *temp_path, *xpath; - DIR *d; - struct dirent *de; - int had_matches; - - gg = make_globber(last_comp); - - /* Null-terminate parent directory, i.e. null the character where the trailing / is */ - if (last_comp > path) { - int len = last_comp - path; - temp_path = new_array(char, len); - memcpy(temp_path, path, len-1); - temp_path[len-1] = '\0'; - xpath = new_array(char, len + 2 + NAME_MAX); - } else { - temp_path = new_string("."); - xpath = new_array(char, 3 + NAME_MAX); - } - - d = opendir(temp_path); - had_matches = 0; - if (d) { - while ((de = readdir(d))) { - if (!strcmp(de->d_name, ".")) continue; - if (!strcmp(de->d_name, "..")) continue; - if (is_glob_match(gg, de->d_name)) { - struct stat xsb; - strcpy(xpath, temp_path); - strcat(xpath, "/"); - strcat(xpath, de->d_name); - if (!is_globber_array_match(omit_globs, xpath+base_len)) { - /* Filter out omissions at this point, e.g. to avoid wasting time on - * a recursive expansion of a tree that's going to get pruned in full - * later anyway. */ - had_matches = 1; - if (stat(xpath, &xsb) >= 0) { - (*append)(xpath, base_len, &xsb, list, methods, omit_globs); - } - } - } - } - closedir(d); - if (!had_matches) { - fprintf(stderr, "WARNING: Wildcard \"%s\" matched nothing in %s\n", last_comp, temp_path); - } - } else { - fprintf(stderr, "WARNING: Folder path %s does not exist\n", temp_path); - } - - - free(temp_path); - free(xpath); - free(gg); -} -/*}}}*/ -static void handle_single(char *path, int base_len, struct string_list *list,/*{{{*/ - int (*append)(char *, int, struct stat *, struct string_list *, - const struct traverse_methods *, struct globber_array *), - const struct traverse_methods *methods, - struct globber_array *omit_globs) -{ - struct stat sb; - if (stat(path, &sb) >= 0) { - (*append)(path, base_len, &sb, list, methods, omit_globs); - } else { - fprintf(stderr, "WARNING: Folder path %s does not exist\n", path); - } -} -/*}}}*/ -static int filter_is_file(const char *x, const struct stat *sb)/*{{{*/ -{ - if (S_ISREG(sb->st_mode)) - return 1; - else - return 0; -} -/*}}}*/ -enum traverse_check scrutinize_mbox_entry(int parent_is_mbox, const char *de_name)/*{{{*/ -{ - /* We have to keep looking at everything in this case. */ - return TRAV_PROCESS; -} -/*}}}*/ -struct traverse_methods mbox_traverse_methods = {/*{{{*/ - .filter = filter_is_file, - .scrutinize = scrutinize_mbox_entry -}; -/*}}}*/ -static int is_wild(const char *x)/*{{{*/ -{ - const char *p; - p = x; - while (*p) { - switch (*p) { - case '[': - case '*': - case '?': - return 1; - } - p++; - } - return 0; -} -/*}}}*/ -/*{{{ handle_one_path() */ -static void handle_one_path(const char *folder_base, - const char *path, - struct string_list *list, - const struct traverse_methods *methods, - struct globber_array *omit_globs) -{ - /* Valid syntaxen ([.]=optional): - * [xxx/]foo : single path - * [xxx/]foo... : if foo is a file, as before; if a directory, every ordinary file under it - * [xxx/]wild : any single path matching the wildcard - * [xxx/]wild... : consider each match of the wildcard by the rule 2 lines above - - * <wild> contains any of these shell-like metacharacters - * * : any string of 1 or more arbitrary characters - * ? : any 1 arbitrary character - * [a-z] : character class - * [^a-z] : negated character class. - - */ - int folder_base_len = strlen(folder_base); - char *full_path; - int is_abs; - int len; - char *last_slash; - char *last_comp; - int base_len; - - is_abs = (path[0] == '/') ? 1 : 0; - if (is_abs) { - full_path = new_string(path); - base_len = 0; - } else { - full_path = new_array(char, folder_base_len + strlen(path) + 2); - strcpy(full_path, folder_base); - strcat(full_path, "/"); - strcat(full_path, path); - base_len = strlen(folder_base) + 1; - } - len = strlen(full_path); - last_slash = find_last_slash(full_path); - last_comp = last_slash ? (last_slash + 1) : full_path; - if ((len >= 4) && !strcmp(full_path + (len - 3), "...")) { - full_path[len - 3] = '\0'; - if (is_wild(last_comp)) { - handle_wild(full_path, base_len, last_comp, list, append_deep, methods, omit_globs); - } else { - handle_single(full_path, base_len, list, append_deep, methods, omit_globs); - } - } else { - if (is_wild(last_comp)) { - handle_wild(full_path, base_len, last_comp, list, append_shallow, methods, omit_globs); - } else { - handle_single(full_path, base_len, list, append_shallow, methods, omit_globs); - } - } - free(full_path); -} -/*}}}*/ -/*{{{ glob_and_expand_paths() */ -void glob_and_expand_paths(const char *folder_base, - char **paths_in, int n_in, - char ***paths_out, int *n_out, - const struct traverse_methods *methods, - struct globber_array *omit_globs) -{ - struct string_list list; - int i; - - /* Clear it. */ - list.next = list.prev = &list; - - for (i=0; i<n_in; i++) { - char *path = paths_in[i]; - handle_one_path(folder_base, path, &list, methods, omit_globs); - } - - string_list_to_array(&list, n_out, paths_out); -} -/*}}}*/ - -void build_mbox_lists(struct database *db, const char *folder_base, /*{{{*/ - const char *mboxen_paths, struct globber_array *omit_globs) -{ - char **raw_paths, **paths; - int n_raw_paths, i; - int n_paths; - struct stat sb; - - int n_extant; - struct extant_mbox *extant_mboxen; - - n_extant = 0; - - if (mboxen_paths) { - split_on_colons(mboxen_paths, &n_raw_paths, &raw_paths); - glob_and_expand_paths(folder_base, raw_paths, n_raw_paths, &paths, &n_paths, &mbox_traverse_methods, omit_globs); - extant_mboxen = new_array(struct extant_mbox, n_paths); - } else { - n_paths = 0; - paths = NULL; - extant_mboxen = NULL; - } - - /* Assume maximal size array. TODO : new strategy when globbing is included. - * */ - - /* TODO TODO ::: Build a sorted list of the paths and check that there aren't - any duplicates!! */ - - for (i=0; i<n_paths; i++) { - char *path = paths[i]; - if (lstat(path, &sb) < 0) { - /* can't stat */ - } else { - if (S_ISLNK(sb.st_mode)) { - /* Skip mbox if symlink */ - if (verbose) { - printf("%s is a link - skipping\n", path); - } - } else { - extant_mboxen[n_extant].full_path = new_string(path); - extant_mboxen[n_extant].mtime = sb.st_mtime; - extant_mboxen[n_extant].size = sb.st_size; - n_extant++; - } - } - free(paths[i]); - } - if (paths) { - free(paths); - paths=NULL; - } - - /* Reconcile list against that in the db. : sort, match etc. */ - if (n_extant) { - qsort(extant_mboxen, n_extant, sizeof(struct extant_mbox), compare_extant_mboxen); - } - - check_duplicates(extant_mboxen, n_extant); - - marry_up_mboxen(db, extant_mboxen, n_extant); - - /* Now look for new/modified mboxen, find how many of the old messages are - * still valid and scan the remainder. */ - - for (i=0; i<db->n_mboxen; i++) { - struct mbox *mb = &db->mboxen[i]; - mb->new_msgs = NULL; - if (mb->path) { - if ((mb->current_mtime == mb->file_mtime) && - (mb->current_size == mb->file_size)) { - mb->n_old_msgs_valid = mb->n_msgs; - } else { - unsigned char *va; - int len; - create_ro_mapping(mb->path, &va, &len); - if (va) { - rescan_mbox(mb, (char *) va, len); - free_ro_mapping(va, len); - } else if (!len) { - mb->n_old_msgs_valid = mb->n_msgs = 0; - } else { - /* Treat as dead mbox */ - deaden_mbox(mb); - } - } - } - } - - /* At the end of this, we want the db->mboxen table to contain up to date info about - * the mboxen, together with how much of the old info was still current. */ -} -/*}}}*/ - -static struct msg_src *setup_msg_src(char *filename, off_t start, size_t len)/*{{{*/ -{ - static struct msg_src result; - result.type = MS_MBOX; - result.filename = filename; - result.start = start; - result.len = len; - return &result; -} -/*}}}*/ -int add_mbox_messages(struct database *db)/*{{{*/ -{ - int i, j; - int any_new = 0; - int N; - unsigned char *va; - int valen; - enum data_to_rfc822_error error; - - for (i=0; i<db->n_mboxen; i++) { - struct mbox *mb = &db->mboxen[i]; - struct message_list *here, *next; - - if (mb->new_msgs) { - /* Upper bound : we may need to coalesce 2 or more messages if false - * matches on From lines have occurred inside MIME encoded body parts. */ - N = mb->n_old_msgs_valid + mb->n_new_msgs; - if (N > mb->max_msgs) { - mb->max_msgs = N; - mb->start = grow_array(off_t, N, mb->start); - mb->len = grow_array(size_t, N, mb->len); - mb->check_all = grow_array(checksum_t, N, mb->check_all); - } - - va = NULL; /* lazy mmap */ - for (j=mb->n_old_msgs_valid, here=mb->new_msgs; here; j++, here=next) { - int n; - int trials = 0; - off_t start; - size_t len; - struct rfc822 *r8; - struct msg_src *msg_src; - struct message_list *last, *xx, *xn; - - next = here->next; - - if (!va) { - create_ro_mapping(mb->path, &va, &valen); - } - if (!va) { - fprintf(stderr, "Couldn't create mapping of file %s\n", mb->path); - unlock_and_exit(1); - } - - - /* Try to parse the next 'From' -to- 'From' chunk as an rfc822 message. - * If we get an unterminated MIME encoding, coalesce the next chunk - * onto the current one and try again. Keep going until it works, or - * we run out of chunks. If we run out, back up to just using the - * first chunk and assume it is broken. - * - * This is to deal with cases such as having a text/plain attachment - * that is actually an mbox file in its own right, i.e. will have - * embedded '^From ' lines in it. - * - * 'last' is the last chunk currently in the putative message. */ - last = here; - do { - len = last->start + last->len - here->start; - msg_src = setup_msg_src(mb->path, here->start, len); - r8 = data_to_rfc822(msg_src, (char *) va + here->start, len, &error); - if (error == DTR8_MISSING_END) { - if (r8) free_rfc822(r8); - r8 = NULL; - last = last->next; /* Try with another chunk on the end */ - ++trials; - } else { - /* Treat as success */ - next = last->next; - break; - } - } while (last && trials < 100); - - if (last && trials < 100) { - start = mb->start[j] = here->start; - mb->len[j] = len; - compute_checksum((char *) va + here->start, len, &mb->check_all[j]); - } else { - /* Faulty message or last message in the file */ - start = mb->start[j] = here->start; - len = mb->len[j] = here->len; - compute_checksum((char *) va + here->start, len, &mb->check_all[j]); - msg_src = setup_msg_src(mb->path, start, len); - r8 = data_to_rfc822(msg_src, (char *) va + start, len, &error); - if (error == DTR8_MISSING_END) { - fprintf(stderr, "Can't find end boundary in multipart message %s\n", - format_msg_src(msg_src)); - } - } - - /* Release all the list entries in the range [here,next) (inclusive) */ - for (xx=here; xx!=next; xx=xn) { - xn = xx->next; - free(xx); - } - - /* Only do this once a valid rfc822 structure has been obtained. */ - maybe_grow_message_arrays(db); - n = db->n_msgs; - db->type[n] = MTY_MBOX; - db->msgs[n].src.mbox.file_index = i; - db->msgs[n].src.mbox.msg_index = j; - - if (r8) { - if (verbose) { - 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 { - printf("Message in %s at [%d,%d) is misformatted\n", mb->path, (int)start, (int)(start + len)); - } - - ++db->n_msgs; - any_new = 1; - } - mb->n_msgs = j; - if (va) { - free_ro_mapping(va, valen); - } - } - } - return any_new; -} -/*}}}*/ - -/* OTHER */ -void cull_dead_mboxen(struct database *db)/*{{{*/ -{ - int n_alive, i, j, n; - int *old_to_new; - struct mbox *newtab; - - n = db->n_mboxen; - for (i=0, n_alive=0; i<n; i++) { - if (db->mboxen[i].path) n_alive++; - } - - /* Simple case - no dead mboxen */ - if (n_alive == n) return; - - newtab = new_array(struct mbox, n_alive); - old_to_new = new_array(int, n); - for (i=0, j=0; i<n; i++) { - if (db->mboxen[i].path) { - old_to_new[i] = j; - newtab[j] = db->mboxen[i]; - printf("Copying mbox[%d] to [%d], path=%s\n", i, j, db->mboxen[i].path); - j++; - } else { - printf("Pruning old mbox[%d], dead\n", i); - old_to_new[i] = -1; - } - } - - /* Renumber file indices in messages */ - n = db->n_msgs; - for (i=0; i<n; i++) { - if (db->type[i] == MTY_MBOX) { - int old_idx = db->msgs[i].src.mbox.file_index; - assert(old_to_new[old_idx] != -1); - db->msgs[i].src.mbox.file_index = old_to_new[old_idx]; - } - } - - /* Fix up pointers */ - db->n_mboxen = db->max_mboxen = n_alive; - free(db->mboxen); - db->mboxen = newtab; - free(old_to_new); - return; -} -/*}}}*/ - -unsigned int encode_mbox_indices(unsigned int mb, unsigned int msg)/*{{{*/ -{ - unsigned int result; - result = ((mb & 0xffff) << 16) | (msg & 0xffff); - return result; -} -/*}}}*/ -void decode_mbox_indices(unsigned int index, unsigned int *mb, unsigned int *msg)/*{{{*/ -{ - *mb = (index >> 16) & 0xffff; - *msg = (index & 0xffff); -} -/*}}}*/ -int verify_mbox_size_constraints(struct database *db)/*{{{*/ -{ - int i; - int fail; - if (db->n_mboxen > 65536) { - fprintf(stderr, "Too many mboxes (max 65536, you have %d)\n", db->n_mboxen); - return 0; - } - fail = 0; - for (i=0; i<db->n_mboxen; i++) { - if (db->mboxen[i].n_msgs > 65536) { - fprintf(stderr, "Too many messages in mbox %s (max 65536, you have %d)\n", - db->mboxen[i].path, db->mboxen[i].n_msgs); - fail = 1; - } - } - if (fail) return 0; - else return 1; -} -/*}}}*/ - diff --git a/src/mairix/md5.c b/src/mairix/md5.c @@ -1,322 +0,0 @@ -/* - *********************************************************************** - ** md5.c -- the source code for MD5 routines ** - ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** - ** Created: 2/17/90 RLR ** - ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version ** - ** Revised (for MD5): RLR 4/27/91 ** - ** -- G modified to have y&~z instead of y&z ** - ** -- FF, GG, HH modified to add in last register done ** - ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** - ** -- distinct additive constant for each step ** - ** -- round 4 added, working mod 7 ** - *********************************************************************** - */ - -/* - *********************************************************************** - ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** - ** ** - ** License to copy and use this software is granted provided that ** - ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** - ** Digest Algorithm" in all material mentioning or referencing this ** - ** software or this function. ** - ** ** - ** License is also granted to make and use derivative works ** - ** provided that such works are identified as "derived from the RSA ** - ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** - ** material mentioning or referencing the derived work. ** - ** ** - ** RSA Data Security, Inc. makes no representations concerning ** - ** either the merchantability of this software or the suitability ** - ** of this software for any particular purpose. It is provided "as ** - ** is" without express or implied warranty of any kind. ** - ** ** - ** These notices must be retained in any copies of any part of this ** - ** documentation and/or software. ** - *********************************************************************** - */ - -#include "md5.h" - -/* - *********************************************************************** - ** Message-digest routines: ** - ** To form the message digest for a message M ** - ** (1) Initialize a context buffer mdContext using MD5Init ** - ** (2) Call MD5Update on mdContext and M ** - ** (3) Call MD5Final on mdContext ** - ** The message digest is now in mdContext->digest[0...15] ** - *********************************************************************** - */ - -/* forward declaration */ -static void Transform (UINT4 *, UINT4 *); - -#ifdef __STDC__ -static const -#else -static -#endif -unsigned char PADDING[64] = { - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -/* F, G, H and I are basic MD5 functions */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits */ -#if defined(FAST_MD5) && defined(__GNUC__) && defined(mc68000) -/* - * If we're on a 68000 based CPU and using a GNU C compiler with - * inline assembly code, we can speed this up a bit. - */ -inline UINT4 ROTATE_LEFT(UINT4 x, int n) -{ - asm("roll %2,%0" : "=d" (x) : "0" (x), "Ir" (n)); - return x; -} -#else -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) -#endif - - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ -/* Rotation is separate from addition to prevent recomputation */ -#define FF(a, b, c, d, x, s, ac) \ - {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) \ - {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) \ - {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) \ - {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - -/* The routine MD5Init initializes the message-digest context - mdContext. All fields are set to zero. - */ -void MD5Init (mdContext) -MD5_CTX *mdContext; -{ - mdContext->i[0] = mdContext->i[1] = (UINT4)0; - - /* Load magic initialization constants. - */ - mdContext->buf[0] = (UINT4)0x67452301; - mdContext->buf[1] = (UINT4)0xefcdab89; - mdContext->buf[2] = (UINT4)0x98badcfe; - mdContext->buf[3] = (UINT4)0x10325476; -} - -/* The routine MD5Update updates the message-digest context to - account for the presence of each of the characters inBuf[0..inLen-1] - in the message whose digest is being computed. - */ -void MD5Update (mdContext, inBuf, inLen) -MD5_CTX *mdContext; -unsigned const char *inBuf; -unsigned int inLen; -{ - UINT4 in[16]; - int mdi; - unsigned int i, ii; - - /* compute number of bytes mod 64 */ - mdi = (int)((mdContext->i[0] >> 3) & 0x3F); - - /* update number of bits */ - if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) - mdContext->i[1]++; - mdContext->i[0] += ((UINT4)inLen << 3); - mdContext->i[1] += ((UINT4)inLen >> 29); - - while (inLen--) { - /* add new character to buffer, increment mdi */ - mdContext->in[mdi++] = *inBuf++; - - /* transform if necessary */ - if (mdi == 0x40) { - for (i = 0, ii = 0; i < 16; i++, ii += 4) - in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | - (((UINT4)mdContext->in[ii+2]) << 16) | - (((UINT4)mdContext->in[ii+1]) << 8) | - ((UINT4)mdContext->in[ii]); - Transform (mdContext->buf, in); - mdi = 0; - } - } -} - -/* The routine MD5Final terminates the message-digest computation and - ends with the desired message digest in mdContext->digest[0...15]. - */ - -void MD5Final (mdContext) -MD5_CTX *mdContext; -{ - UINT4 in[16]; - int mdi; - unsigned int i, ii; - unsigned int padLen; - - /* save number of bits */ - in[14] = mdContext->i[0]; - in[15] = mdContext->i[1]; - - /* compute number of bytes mod 64 */ - mdi = (int)((mdContext->i[0] >> 3) & 0x3F); - - /* pad out to 56 mod 64 */ - padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); - MD5Update (mdContext, PADDING, padLen); - - /* append length in bits and transform */ - for (i = 0, ii = 0; i < 14; i++, ii += 4) - in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | - (((UINT4)mdContext->in[ii+2]) << 16) | - (((UINT4)mdContext->in[ii+1]) << 8) | - ((UINT4)mdContext->in[ii]); - Transform (mdContext->buf, in); - - /* store buffer in digest */ - for (i = 0, ii = 0; i < 4; i++, ii += 4) { - mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); - mdContext->digest[ii+1] = - (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); - mdContext->digest[ii+2] = - (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); - mdContext->digest[ii+3] = - (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); - } -} - -/* Basic MD5 step. Transforms buf based on in. - */ -static void Transform (buf, in) -UINT4 *buf; -UINT4 *in; -{ - UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; - - /* Round 1 */ -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 - - FF ( a, b, c, d, in[ 0], S11, 0xd76aa478); /* 1 */ - FF ( d, a, b, c, in[ 1], S12, 0xe8c7b756); /* 2 */ - FF ( c, d, a, b, in[ 2], S13, 0x242070db); /* 3 */ - FF ( b, c, d, a, in[ 3], S14, 0xc1bdceee); /* 4 */ - FF ( a, b, c, d, in[ 4], S11, 0xf57c0faf); /* 5 */ - FF ( d, a, b, c, in[ 5], S12, 0x4787c62a); /* 6 */ - FF ( c, d, a, b, in[ 6], S13, 0xa8304613); /* 7 */ - FF ( b, c, d, a, in[ 7], S14, 0xfd469501); /* 8 */ - FF ( a, b, c, d, in[ 8], S11, 0x698098d8); /* 9 */ - FF ( d, a, b, c, in[ 9], S12, 0x8b44f7af); /* 10 */ - FF ( c, d, a, b, in[10], S13, 0xffff5bb1); /* 11 */ - FF ( b, c, d, a, in[11], S14, 0x895cd7be); /* 12 */ - FF ( a, b, c, d, in[12], S11, 0x6b901122); /* 13 */ - FF ( d, a, b, c, in[13], S12, 0xfd987193); /* 14 */ - FF ( c, d, a, b, in[14], S13, 0xa679438e); /* 15 */ - FF ( b, c, d, a, in[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 - GG ( a, b, c, d, in[ 1], S21, 0xf61e2562); /* 17 */ - GG ( d, a, b, c, in[ 6], S22, 0xc040b340); /* 18 */ - GG ( c, d, a, b, in[11], S23, 0x265e5a51); /* 19 */ - GG ( b, c, d, a, in[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG ( a, b, c, d, in[ 5], S21, 0xd62f105d); /* 21 */ - GG ( d, a, b, c, in[10], S22, 0x2441453); /* 22 */ - GG ( c, d, a, b, in[15], S23, 0xd8a1e681); /* 23 */ - GG ( b, c, d, a, in[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG ( a, b, c, d, in[ 9], S21, 0x21e1cde6); /* 25 */ - GG ( d, a, b, c, in[14], S22, 0xc33707d6); /* 26 */ - GG ( c, d, a, b, in[ 3], S23, 0xf4d50d87); /* 27 */ - GG ( b, c, d, a, in[ 8], S24, 0x455a14ed); /* 28 */ - GG ( a, b, c, d, in[13], S21, 0xa9e3e905); /* 29 */ - GG ( d, a, b, c, in[ 2], S22, 0xfcefa3f8); /* 30 */ - GG ( c, d, a, b, in[ 7], S23, 0x676f02d9); /* 31 */ - GG ( b, c, d, a, in[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 - HH ( a, b, c, d, in[ 5], S31, 0xfffa3942); /* 33 */ - HH ( d, a, b, c, in[ 8], S32, 0x8771f681); /* 34 */ - HH ( c, d, a, b, in[11], S33, 0x6d9d6122); /* 35 */ - HH ( b, c, d, a, in[14], S34, 0xfde5380c); /* 36 */ - HH ( a, b, c, d, in[ 1], S31, 0xa4beea44); /* 37 */ - HH ( d, a, b, c, in[ 4], S32, 0x4bdecfa9); /* 38 */ - HH ( c, d, a, b, in[ 7], S33, 0xf6bb4b60); /* 39 */ - HH ( b, c, d, a, in[10], S34, 0xbebfbc70); /* 40 */ - HH ( a, b, c, d, in[13], S31, 0x289b7ec6); /* 41 */ - HH ( d, a, b, c, in[ 0], S32, 0xeaa127fa); /* 42 */ - HH ( c, d, a, b, in[ 3], S33, 0xd4ef3085); /* 43 */ - HH ( b, c, d, a, in[ 6], S34, 0x4881d05); /* 44 */ - HH ( a, b, c, d, in[ 9], S31, 0xd9d4d039); /* 45 */ - HH ( d, a, b, c, in[12], S32, 0xe6db99e5); /* 46 */ - HH ( c, d, a, b, in[15], S33, 0x1fa27cf8); /* 47 */ - HH ( b, c, d, a, in[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - II ( a, b, c, d, in[ 0], S41, 0xf4292244); /* 49 */ - II ( d, a, b, c, in[ 7], S42, 0x432aff97); /* 50 */ - II ( c, d, a, b, in[14], S43, 0xab9423a7); /* 51 */ - II ( b, c, d, a, in[ 5], S44, 0xfc93a039); /* 52 */ - II ( a, b, c, d, in[12], S41, 0x655b59c3); /* 53 */ - II ( d, a, b, c, in[ 3], S42, 0x8f0ccc92); /* 54 */ - II ( c, d, a, b, in[10], S43, 0xffeff47d); /* 55 */ - II ( b, c, d, a, in[ 1], S44, 0x85845dd1); /* 56 */ - II ( a, b, c, d, in[ 8], S41, 0x6fa87e4f); /* 57 */ - II ( d, a, b, c, in[15], S42, 0xfe2ce6e0); /* 58 */ - II ( c, d, a, b, in[ 6], S43, 0xa3014314); /* 59 */ - II ( b, c, d, a, in[13], S44, 0x4e0811a1); /* 60 */ - II ( a, b, c, d, in[ 4], S41, 0xf7537e82); /* 61 */ - II ( d, a, b, c, in[11], S42, 0xbd3af235); /* 62 */ - II ( c, d, a, b, in[ 2], S43, 0x2ad7d2bb); /* 63 */ - II ( b, c, d, a, in[ 9], S44, 0xeb86d391); /* 64 */ - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -/* - *********************************************************************** - ** End of md5.c ** - ******************************** (cut) ******************************** - */ diff --git a/src/mairix/md5.h b/src/mairix/md5.h @@ -1,62 +0,0 @@ -/* - *********************************************************************** - ** md5.h -- header file for implementation of MD5 ** - ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** - ** Created: 2/17/90 RLR ** - ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** - ** Revised (for MD5): RLR 4/27/91 ** - *********************************************************************** - */ - -/* - *********************************************************************** - ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** - ** ** - ** License to copy and use this software is granted provided that ** - ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** - ** Digest Algorithm" in all material mentioning or referencing this ** - ** software or this function. ** - ** ** - ** License is also granted to make and use derivative works ** - ** provided that such works are identified as "derived from the RSA ** - ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** - ** material mentioning or referencing the derived work. ** - ** ** - ** RSA Data Security, Inc. makes no representations concerning ** - ** either the merchantability of this software or the suitability ** - ** of this software for any particular purpose. It is provided "as ** - ** is" without express or implied warranty of any kind. ** - ** ** - ** These notices must be retained in any copies of any part of this ** - ** documentation and/or software. ** - *********************************************************************** - */ - -#ifdef HAS_STDINT_H -#include <stdint.h> -#elif defined(HAS_INTTYPES_H) -#include <inttypes.h> -#else -#error "No <stdint.h> or <inttypes.h>" -#endif - -/* typedef a 32-bit type */ -typedef uint32_t UINT4; - -/* Data structure for MD5 (Message-Digest) computation */ -typedef struct { - UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ - UINT4 buf[4]; /* scratch buffer */ - unsigned char in[64]; /* input buffer */ - unsigned char digest[16]; /* actual digest after MD5Final call */ -} MD5_CTX; - -void MD5Init (MD5_CTX *mdContext); -void MD5Update (MD5_CTX *, unsigned const char *, unsigned int); -void MD5Final (MD5_CTX *); - -/* - *********************************************************************** - ** End of md5.h ** - ******************************** (cut) ******************************** - */ diff --git a/src/mairix/memmac.h b/src/mairix/memmac.h @@ -1,72 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002-2004 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - - -#ifndef MEMMAC_H -#define MEMMAC_H - -/*{{{ Safe alloc helpers (GCC extensions) */ -extern void out_of_mem(char *file, int line, size_t size); - -#undef TEST_OOM - -#ifdef TEST_OOM -extern int total_bytes; -#endif - -static __inline__ void* safe_malloc(char *file, int line, size_t s)/*{{{*/ -{ - void *x = malloc(s); -#ifdef TEST_OOM - total_bytes += s; - if (total_bytes > 131072) x = NULL; -#endif - if (!x) out_of_mem(file, line, s); - return x; -} -/*}}}*/ -static __inline__ void* safe_realloc(char *file, int line, void *old_ptr, size_t s)/*{{{*/ -{ - void *x = realloc(old_ptr, s); - if (!x) out_of_mem(file, line, s); - return x; -} -/*}}}*/ -#ifndef TEST -#define Malloc(s) safe_malloc(__FILE__, __LINE__, s) -#define Realloc(xx,s) safe_realloc(__FILE__, __LINE__,xx,s) -#else -#define Malloc(s) malloc(s) -#define Realloc(xx,s) realloc(xx,s) -#endif -/*}}}*/ - -/*{{{ Memory macros*/ -#define new_string(s) strcpy((char *) Malloc(1+strlen(s)), (s)) -#define extend_string(x,s) (strcat(Realloc(x, (strlen(x)+strlen(s)+1)), s)) -#define new(T) (T *) Malloc(sizeof(T)) -#define new_array(T, n) (T *) Malloc(sizeof(T) * (n)) -#define grow_array(T, n, oldX) (T *) ((oldX) ? Realloc(oldX, (sizeof(T) * (n))) : Malloc(sizeof(T) * (n))) -#define EMPTY(x) {&(x), &(x)} -/*}}}*/ - -#endif /* MEMMAC_H */ diff --git a/src/mairix/mkversion b/src/mairix/mkversion @@ -1,15 +0,0 @@ -#!/bin/sh - -rm -f version.h -echo "#ifndef VERSION_H" > version.h -echo "#define VERSION_H 1" >> version.h - -if [ -f version.txt ]; then - ver=`cat version.txt` - echo "#define PROGRAM_VERSION \"$ver\"" >> version.h -else - echo "#define PROGRAM_VERSION \"DEVELOPMENT\"" >> version.h -fi - -echo "#endif /* VERSION_H */" >> version.h - diff --git a/src/mairix/nvp.c b/src/mairix/nvp.c @@ -1,416 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2006,2007 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#ifdef VERBOSE_TEST -#define TEST 1 -#endif - -/* 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); -} -/*}}}*/ -static void combine_namevalue(struct nvp *nvp, char *name, char *value)/*{{{*/ -{ - struct nvp_entry *n; - for (n=nvp->first; n; n=n->next) { - if (n->type == NVP_NAMEVALUE) { - if (!strcmp(n->lhs, name)) { - char *new_rhs; - new_rhs = new_array(char, strlen(n->rhs) + strlen(value) + 1); - strcpy(new_rhs, n->rhs); - strcat(new_rhs, value); - free(n->rhs); - n->rhs = new_rhs; - return; - } - } - } - /* No match : it's the first one */ - append_namevalue(nvp, name, value); -} -/*}}}*/ -static void release_nvp(struct nvp *nvp)/*{{{*/ -{ - struct nvp_entry *e, *ne; - for (e=nvp->first; e; e=ne) { - ne = e->next; - switch (e->type) { - case NVP_NAME: - free(e->lhs); - break; - case NVP_MAJORMINOR: - case NVP_NAMEVALUE: - free(e->lhs); - free(e->rhs); - break; - } - free(e); - } - free(nvp); -} -/*}}}*/ -struct nvp *make_nvp(struct msg_src *src, char *s, const char *pfx)/*{{{*/ -{ - int current_state; - unsigned int tok; - char *q; - unsigned char qq; - char name[256]; - char minor[256]; - char value[256]; - enum nvp_action last_action, current_action; - struct nvp *result; - size_t pfxlen; - char *nn, *mm, *vv; - - pfxlen = strlen(pfx); - if (strncasecmp(pfx, s, pfxlen)) - return NULL; - s += pfxlen; - - 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 { - qq = *(unsigned char *) q; - if (qq) { - tok = nvp_char2tok[qq]; - } else { - tok = nvp_EOS; - } - current_state = nvp_next_state(current_state, tok); -#ifdef VERBOSE_TEST - fprintf(stderr, "Char %02x (%c) tok=%d new_current_state=%d\n", - qq, ((qq>=32) && (qq<=126)) ? qq : '.', - tok, current_state); -#endif - - if (current_state < 0) { -#ifdef TEST - fprintf(stderr, "'%s' could not be parsed\n", s); -#else - fprintf(stderr, "Header '%s%s' in %s could not be parsed\n", - pfx, s, format_msg_src(src)); -#endif - release_nvp(result); - return NULL; - } - - switch (nvp_copier[current_state]) { - case COPY_TO_NAME: -#ifdef VERBOSE_TEST - fprintf(stderr, " COPY_TO_NAME\n"); -#endif - *nn++ = *q; - break; - case COPY_TO_MINOR: -#ifdef VERBOSE_TEST - fprintf(stderr, " COPY_TO_MINOR\n"); -#endif - *mm++ = *q; - break; - case COPY_TO_VALUE: -#ifdef VERBOSE_TEST - fprintf(stderr, " COPY_TO_VALUE\n"); -#endif - *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: - case GOT_NAMEVALUE_CONT: -#ifdef VERBOSE_TEST - fprintf(stderr, " Setting last action to %d\n", current_action); -#endif - last_action = current_action; - break; - case GOT_TERMINATOR: -#ifdef VERBOSE_TEST - fprintf(stderr, " Hit terminator; last_action=%d\n", last_action); -#endif - 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; - case GOT_NAMEVALUE_CONT: - *nn = 0; - *vv = 0; - combine_namevalue(result, name, value); - break; - default: - break; - } - nn = name; - mm = minor; - vv = value; - break; - case GOT_NOTHING: - break; - } - - q++; - } while (tok != nvp_EOS); - - return result; -} -/*}}}*/ -void free_nvp(struct nvp *nvp)/*{{{*/ -{ - struct nvp_entry *ne, *nne; - for (ne = nvp->first; ne; ne=nne) { - nne = ne->next; - switch (ne->type) { - case NVP_NAME: - free(ne->lhs); - break; - case NVP_MAJORMINOR: - case NVP_NAMEVALUE: - free(ne->lhs); - free(ne->rhs); - break; - } - free(ne); - } - free(nvp); -} -/*}}}*/ -const char *nvp_lookup(struct nvp *nvp, const char *name)/*{{{*/ -{ - struct nvp_entry *ne; - for (ne = nvp->first; ne; ne=ne->next) { - if (ne->type == NVP_NAMEVALUE) { - if (!strcmp(ne->lhs, name)) { - return ne->rhs; - } - } - } - return NULL; -} -/*}}}*/ -const char *nvp_lookupcase(struct nvp *nvp, const char *name)/*{{{*/ -{ - struct nvp_entry *ne; - for (ne = nvp->first; ne; ne=ne->next) { - if (ne->type == NVP_NAMEVALUE) { - if (!strcasecmp(ne->lhs, name)) { - return ne->rhs; - } - } - } - return NULL; -} -/*}}}*/ - -void nvp_dump(struct nvp *nvp, FILE *out)/*{{{*/ -{ - struct nvp_entry *ne; - fprintf(out, "----\n"); - for (ne = nvp->first; ne; ne=ne->next) { - switch (ne->type) { - case NVP_NAME: - fprintf(out, "NAME: %s\n", ne->lhs); - break; - case NVP_MAJORMINOR: - fprintf(out, "MAJORMINOR: %s/%s\n", ne->lhs, ne->rhs); - break; - case NVP_NAMEVALUE: - fprintf(out, "NAMEVALUE: %s=%s\n", ne->lhs, ne->rhs); - break; - } - } -} -/*}}}*/ - -/* In these cases, we only look at the first entry */ -const char *nvp_major(struct nvp *nvp)/*{{{*/ -{ - struct nvp_entry *ne; - ne = nvp->first; - if (ne) { - if (ne->type == NVP_MAJORMINOR) { - return ne->lhs; - } else { - return NULL; - } - } else { - return NULL; - } -} -/*}}}*/ -const char *nvp_minor(struct nvp *nvp)/*{{{*/ -{ - struct nvp_entry *ne; - ne = nvp->first; - if (ne) { - if (ne->type == NVP_MAJORMINOR) { - return ne->rhs; - } else { - return NULL; - } - } else { - return NULL; - } -} -/*}}}*/ -const char *nvp_first(struct nvp *nvp)/*{{{*/ -{ - struct nvp_entry *ne; - ne = nvp->first; - if (ne) { - if (ne->type == NVP_NAME) { - return ne->lhs; - } else { - return NULL; - } - } else { - return NULL; - } -} -/*}}}*/ - -#ifdef TEST - -static void do_test(char *s) -{ - struct nvp *n; - n = make_nvp(NULL, s, ""); - if (n) { - nvp_dump(n, stderr); - free_nvp(n); - } -} - - -int main (int argc, char **argv) { - struct nvp *n; -#if 0 - do_test("attachment; filename=\"foo.c\"; prot=ro"); - do_test("attachment; filename= \"foo bar.c\" ;prot=ro"); - do_test("attachment ; filename= \"foo bar.c\" ;prot= ro"); - do_test("attachment ; filename= \"foo bar.c\" ;prot= ro"); - do_test("attachment ; filename= \"foo ; bar.c\" ;prot= ro"); - do_test("attachment ; x*0=\"hi \"; x*1=\"there\""); -#endif - - do_test("application/vnd.ms-excel; name=\"thequiz.xls\""); -#if 0 - do_test("inline; filename*0=\"aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj\t kkkkllll\""); - do_test(" text/plain ; name= \"foo bar.c\" ;prot= ro/rw; read/write; read= foo bar"); -#endif - return 0; -} -#endif - - - - diff --git a/src/mairix/nvp.h b/src/mairix/nvp.h @@ -1,38 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2006,2010 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#ifndef NVP_H -#define NVP_H - -struct nvp; -struct msg_src; -extern struct nvp *make_nvp(struct msg_src *, char *, const char *); -extern void free_nvp(struct nvp *); -extern void nvp_dump(struct nvp *nvp, FILE *out); -extern const char *nvp_major(struct nvp *n); -extern const char *nvp_minor(struct nvp *n); -extern const char *nvp_first(struct nvp *n); -extern const char *nvp_lookup(struct nvp *n, const char *name); -extern const char *nvp_lookupcase(struct nvp *n, const char *name); - -#endif - diff --git a/src/mairix/nvp.nfa b/src/mairix/nvp.nfa @@ -1,197 +0,0 @@ -######################################################################### -# -# mairix - message index builder and finder for maildir folders. -# -# Copyright (C) Richard P. Curnow 2006,2007 -# -# 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., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# ======================================================================= - -Tokens EOS -Abbrev VALUE = [\041-~]~[\\";] -Abbrev QVALUE = VALUE | [\011\040;] | <escape:in->out> -Abbrev NAME1 = [0-9a-zA-Z_\-] -Abbrev MINOR = NAME1 | [\.\-+] -Abbrev OWS = <optwhite:in->out> - -%{ -#include "nvptypes.h" -%} - -Block escape { - State in - [\\] ; [\\] -> out - [\\] ; ["] -> out -} - -Block optwhite { - State in - -> out - # I have seen headers with ^M in them... - [ \t\r] -> in -} - -Block name { - # This needs to cope with embedded spaces, e.g. for mailers that write '7 - # bit' instead of '7bit' - State in - NAME1 -> name1 - - State name1 - = COPY_TO_NAME - = GOT_NAME - NAME1 -> name1 - [ \t] -> name2 - -> out - - State name2 - = COPY_TO_NAME - = GOT_NAME_TRAILING_SPACE - [ \t] -> name2 - NAME1 -> name1 - -> out - - State out -} - -Block value { - State in - VALUE -> v1 - State v1 - = COPY_TO_VALUE - -> out - VALUE -> v1 -} - -Block qvalue { - State in - ["] -> qv0 - - State qv0 - QVALUE -> qv1 - - State qv1 - = COPY_TO_VALUE - QVALUE -> qv1 - -> qv2 - - State qv2 - ["] -> out -} - -Block digits { - State in - [0-9] -> out - [0-9] -> in -} - -Block namevalue { - State in - OWS ; <name:in->out> ; OWS ; [=] -> rhs_normal - OWS ; <name:in->out> ; [*] ; <digits:in->out> ; OWS ; [=] -> rhs_continue - - State rhs_normal - OWS ; <qvalue:in->out> ; OWS -> out_normal - OWS ; <value:in->out> ; OWS -> out_normal - OWS ; ; EOS -> out_normal - - State rhs_continue - OWS ; <qvalue:in->out> ; OWS -> out_continue - OWS ; <value:in->out> ; OWS -> out_continue - - State out_normal = GOT_NAMEVALUE - -> out - State out_continue = GOT_NAMEVALUE_CONT - -> out -} - -Block major { - State in - NAME1 -> name1 - - State name1 - NAME1 -> name1 - -> out -} - -Block minor { - State in - MINOR -> minor1 - - State minor1 - = COPY_TO_MINOR - MINOR -> minor1 - -> out -} - -Block majorminor { - State in - <major:in->out> -> foo - - State foo - [/] -> bar - - State bar - <minor:in->out> -> out - - State out = GOT_MAJORMINOR -} - -Block component { - State in - <namevalue:in->out> -> out - <name:in->out> -> out - <majorminor:in->out> -> out -} - -Block main { - State in Entry in - OWS ; <component:in->out> ; OWS ; EOS -> out2 - OWS ; <component:in->out> ; OWS ; [;] ; OWS ; EOS -> out2 - OWS ; <component:in->out> ; OWS ; [;] -> in2 - - State in2 - = GOT_TERMINATOR - -> in - - State out2 - = GOT_TERMINATOR - -> out -} - -Defattr 0 -Prefix nvp - -Group action { - Attr GOT_NAMEVALUE - Attr GOT_NAMEVALUE_CONT - Attr GOT_NAME - Attr GOT_NAME_TRAILING_SPACE - Attr GOT_MAJORMINOR - Attr GOT_TERMINATOR - Defattr GOT_NOTHING - Type "enum nvp_action" -} - -Group copier { - Attr COPY_TO_NAME - Attr COPY_TO_MINOR - Attr COPY_TO_VALUE - Defattr COPY_NOWHERE - Type "enum nvp_copier" -} - -# vim:et:sts=4:sw=4:ht=8 - diff --git a/src/mairix/nvpscan.report b/src/mairix/nvpscan.report @@ -1,6352 +0,0 @@ -Processing 1 separate entry points -Entries in 1 blocks, total of 415 states -NFA state 0 = main.in [Entries: in] - [(epsilon)] -> optwhite#8.in - [(epsilon)] -> optwhite#4.in - [(epsilon)] -> optwhite#1.in - Epsilon closure : - (self) - main.#1 - main.optwhite#1.in - main.optwhite#1.out - main.component#2.in - main.component#2.namevalue#1.in - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.in - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.in - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - main.component#2.name#2.in - main.component#2.majorminor#3.in - main.component#2.majorminor#3.major#1.in - main.#4 - main.optwhite#4.in - main.optwhite#4.out - main.component#5.in - main.component#5.namevalue#1.in - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.in - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.in - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - main.component#5.name#2.in - main.component#5.majorminor#3.in - main.component#5.majorminor#3.major#1.in - main.#9 - main.optwhite#8.in - main.optwhite#8.out - main.component#9.in - main.component#9.namevalue#1.in - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.in - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.in - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - main.component#9.name#2.in - main.component#9.majorminor#3.in - main.component#9.majorminor#3.major#1.in - -NFA state 1 = main.#1 - [(epsilon)] -> component#2.in - Epsilon closure : - (self) - main.component#2.in - main.component#2.namevalue#1.in - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.in - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.in - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - main.component#2.name#2.in - main.component#2.majorminor#3.in - main.component#2.majorminor#3.major#1.in - -NFA state 2 = main.optwhite#1.in - [(epsilon)] -> optwhite#1.out - 0:[\t ] -> optwhite#1.in - 1:[\r] -> optwhite#1.in - Epsilon closure : - (self) - main.#1 - main.optwhite#1.out - main.component#2.in - main.component#2.namevalue#1.in - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.in - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.in - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - main.component#2.name#2.in - main.component#2.majorminor#3.in - main.component#2.majorminor#3.major#1.in - -NFA state 3 = main.optwhite#1.out - [(epsilon)] -> #1 - Epsilon closure : - (self) - main.#1 - main.component#2.in - main.component#2.namevalue#1.in - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.in - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.in - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - main.component#2.name#2.in - main.component#2.majorminor#3.in - main.component#2.majorminor#3.major#1.in - -NFA state 4 = main.#2 - [(epsilon)] -> optwhite#3.in - Epsilon closure : - (self) - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 5 = main.component#2.in - [(epsilon)] -> component#2.namevalue#1.in - [(epsilon)] -> component#2.name#2.in - [(epsilon)] -> component#2.majorminor#3.in - Epsilon closure : - (self) - main.component#2.namevalue#1.in - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.in - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.in - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - main.component#2.name#2.in - main.component#2.majorminor#3.in - main.component#2.majorminor#3.major#1.in - -NFA state 6 = main.component#2.namevalue#1.in - [(epsilon)] -> component#2.namevalue#1.optwhite#4.in - [(epsilon)] -> component#2.namevalue#1.optwhite#1.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.in - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.in - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - -NFA state 7 = main.component#2.namevalue#1.#1 - [(epsilon)] -> component#2.namevalue#1.name#2.in - Epsilon closure : - (self) - main.component#2.namevalue#1.name#2.in - -NFA state 8 = main.component#2.namevalue#1.optwhite#1.in - [(epsilon)] -> component#2.namevalue#1.optwhite#1.out - 0:[\t ] -> component#2.namevalue#1.optwhite#1.in - 1:[\r] -> component#2.namevalue#1.optwhite#1.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - -NFA state 9 = main.component#2.namevalue#1.optwhite#1.out - [(epsilon)] -> component#2.namevalue#1.#1 - Epsilon closure : - (self) - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.name#2.in - -NFA state 10 = main.component#2.namevalue#1.#2 - [(epsilon)] -> component#2.namevalue#1.optwhite#3.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#3 - main.component#2.namevalue#1.optwhite#3.in - main.component#2.namevalue#1.optwhite#3.out - -NFA state 11 = main.component#2.namevalue#1.name#2.in - 6:[\055] -> component#2.namevalue#1.name#2.name1 - 11:[A-Z_a-z] -> component#2.namevalue#1.name#2.name1 - 8:[0-9] -> component#2.namevalue#1.name#2.name1 - Epsilon closure : - (self) - -NFA state 12 = main.component#2.namevalue#1.name#2.name1 - [(epsilon)] -> component#2.namevalue#1.name#2.#1 - [(epsilon)] -> component#2.namevalue#1.name#2.#2 - 6:[\055] -> component#2.namevalue#1.name#2.name1 - 11:[A-Z_a-z] -> component#2.namevalue#1.name#2.name1 - 8:[0-9] -> component#2.namevalue#1.name#2.name1 - 0:[\t ] -> component#2.namevalue#1.name#2.name2 - [(epsilon)] -> component#2.namevalue#1.name#2.out - Epsilon closure : - (self) - main.component#2.namevalue#1.#2 - main.component#2.namevalue#1.name#2.#1 - main.component#2.namevalue#1.name#2.#2 - main.component#2.namevalue#1.name#2.out - main.component#2.namevalue#1.#3 - main.component#2.namevalue#1.optwhite#3.in - main.component#2.namevalue#1.optwhite#3.out - -NFA state 13 = main.component#2.namevalue#1.name#2.#1 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 14 = main.component#2.namevalue#1.name#2.#2 - Tags : GOT_NAME - Epsilon closure : - (self) - -NFA state 15 = main.component#2.namevalue#1.name#2.name2 - [(epsilon)] -> component#2.namevalue#1.name#2.#3 - [(epsilon)] -> component#2.namevalue#1.name#2.#4 - 0:[\t ] -> component#2.namevalue#1.name#2.name2 - 6:[\055] -> component#2.namevalue#1.name#2.name1 - 11:[A-Z_a-z] -> component#2.namevalue#1.name#2.name1 - 8:[0-9] -> component#2.namevalue#1.name#2.name1 - [(epsilon)] -> component#2.namevalue#1.name#2.out - Epsilon closure : - (self) - main.component#2.namevalue#1.#2 - main.component#2.namevalue#1.name#2.#3 - main.component#2.namevalue#1.name#2.#4 - main.component#2.namevalue#1.name#2.out - main.component#2.namevalue#1.#3 - main.component#2.namevalue#1.optwhite#3.in - main.component#2.namevalue#1.optwhite#3.out - -NFA state 16 = main.component#2.namevalue#1.name#2.#3 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 17 = main.component#2.namevalue#1.name#2.#4 - Tags : GOT_NAME_TRAILING_SPACE - Epsilon closure : - (self) - -NFA state 18 = main.component#2.namevalue#1.name#2.out - [(epsilon)] -> component#2.namevalue#1.#2 - Epsilon closure : - (self) - main.component#2.namevalue#1.#2 - main.component#2.namevalue#1.#3 - main.component#2.namevalue#1.optwhite#3.in - main.component#2.namevalue#1.optwhite#3.out - -NFA state 19 = main.component#2.namevalue#1.#3 - 10:[=] -> component#2.namevalue#1.rhs_normal - Epsilon closure : - (self) - -NFA state 20 = main.component#2.namevalue#1.optwhite#3.in - [(epsilon)] -> component#2.namevalue#1.optwhite#3.out - 0:[\t ] -> component#2.namevalue#1.optwhite#3.in - 1:[\r] -> component#2.namevalue#1.optwhite#3.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#3 - main.component#2.namevalue#1.optwhite#3.out - -NFA state 21 = main.component#2.namevalue#1.optwhite#3.out - [(epsilon)] -> component#2.namevalue#1.#3 - Epsilon closure : - (self) - main.component#2.namevalue#1.#3 - -NFA state 22 = main.component#2.namevalue#1.#4 - [(epsilon)] -> component#2.namevalue#1.name#5.in - Epsilon closure : - (self) - main.component#2.namevalue#1.name#5.in - -NFA state 23 = main.component#2.namevalue#1.optwhite#4.in - [(epsilon)] -> component#2.namevalue#1.optwhite#4.out - 0:[\t ] -> component#2.namevalue#1.optwhite#4.in - 1:[\r] -> component#2.namevalue#1.optwhite#4.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - -NFA state 24 = main.component#2.namevalue#1.optwhite#4.out - [(epsilon)] -> component#2.namevalue#1.#4 - Epsilon closure : - (self) - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.name#5.in - -NFA state 25 = main.component#2.namevalue#1.#5 - 4:[*] -> component#2.namevalue#1.#6 - Epsilon closure : - (self) - -NFA state 26 = main.component#2.namevalue#1.name#5.in - 6:[\055] -> component#2.namevalue#1.name#5.name1 - 11:[A-Z_a-z] -> component#2.namevalue#1.name#5.name1 - 8:[0-9] -> component#2.namevalue#1.name#5.name1 - Epsilon closure : - (self) - -NFA state 27 = main.component#2.namevalue#1.name#5.name1 - [(epsilon)] -> component#2.namevalue#1.name#5.#1 - [(epsilon)] -> component#2.namevalue#1.name#5.#2 - 6:[\055] -> component#2.namevalue#1.name#5.name1 - 11:[A-Z_a-z] -> component#2.namevalue#1.name#5.name1 - 8:[0-9] -> component#2.namevalue#1.name#5.name1 - 0:[\t ] -> component#2.namevalue#1.name#5.name2 - [(epsilon)] -> component#2.namevalue#1.name#5.out - Epsilon closure : - (self) - main.component#2.namevalue#1.#5 - main.component#2.namevalue#1.name#5.#1 - main.component#2.namevalue#1.name#5.#2 - main.component#2.namevalue#1.name#5.out - -NFA state 28 = main.component#2.namevalue#1.name#5.#1 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 29 = main.component#2.namevalue#1.name#5.#2 - Tags : GOT_NAME - Epsilon closure : - (self) - -NFA state 30 = main.component#2.namevalue#1.name#5.name2 - [(epsilon)] -> component#2.namevalue#1.name#5.#3 - [(epsilon)] -> component#2.namevalue#1.name#5.#4 - 0:[\t ] -> component#2.namevalue#1.name#5.name2 - 6:[\055] -> component#2.namevalue#1.name#5.name1 - 11:[A-Z_a-z] -> component#2.namevalue#1.name#5.name1 - 8:[0-9] -> component#2.namevalue#1.name#5.name1 - [(epsilon)] -> component#2.namevalue#1.name#5.out - Epsilon closure : - (self) - main.component#2.namevalue#1.#5 - main.component#2.namevalue#1.name#5.#3 - main.component#2.namevalue#1.name#5.#4 - main.component#2.namevalue#1.name#5.out - -NFA state 31 = main.component#2.namevalue#1.name#5.#3 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 32 = main.component#2.namevalue#1.name#5.#4 - Tags : GOT_NAME_TRAILING_SPACE - Epsilon closure : - (self) - -NFA state 33 = main.component#2.namevalue#1.name#5.out - [(epsilon)] -> component#2.namevalue#1.#5 - Epsilon closure : - (self) - main.component#2.namevalue#1.#5 - -NFA state 34 = main.component#2.namevalue#1.#6 - [(epsilon)] -> component#2.namevalue#1.digits#6.in - Epsilon closure : - (self) - main.component#2.namevalue#1.digits#6.in - -NFA state 35 = main.component#2.namevalue#1.#7 - [(epsilon)] -> component#2.namevalue#1.optwhite#7.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#8 - main.component#2.namevalue#1.optwhite#7.in - main.component#2.namevalue#1.optwhite#7.out - -NFA state 36 = main.component#2.namevalue#1.digits#6.in - 8:[0-9] -> component#2.namevalue#1.digits#6.out - 8:[0-9] -> component#2.namevalue#1.digits#6.in - Epsilon closure : - (self) - -NFA state 37 = main.component#2.namevalue#1.digits#6.out - [(epsilon)] -> component#2.namevalue#1.#7 - Epsilon closure : - (self) - main.component#2.namevalue#1.#7 - main.component#2.namevalue#1.#8 - main.component#2.namevalue#1.optwhite#7.in - main.component#2.namevalue#1.optwhite#7.out - -NFA state 38 = main.component#2.namevalue#1.#8 - 10:[=] -> component#2.namevalue#1.rhs_continue - Epsilon closure : - (self) - -NFA state 39 = main.component#2.namevalue#1.optwhite#7.in - [(epsilon)] -> component#2.namevalue#1.optwhite#7.out - 0:[\t ] -> component#2.namevalue#1.optwhite#7.in - 1:[\r] -> component#2.namevalue#1.optwhite#7.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#8 - main.component#2.namevalue#1.optwhite#7.out - -NFA state 40 = main.component#2.namevalue#1.optwhite#7.out - [(epsilon)] -> component#2.namevalue#1.#8 - Epsilon closure : - (self) - main.component#2.namevalue#1.#8 - -NFA state 41 = main.component#2.namevalue#1.rhs_normal - [(epsilon)] -> component#2.namevalue#1.optwhite#14.in - [(epsilon)] -> component#2.namevalue#1.optwhite#11.in - [(epsilon)] -> component#2.namevalue#1.optwhite#8.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#9 - main.component#2.namevalue#1.optwhite#8.in - main.component#2.namevalue#1.optwhite#8.out - main.component#2.namevalue#1.qvalue#9.in - main.component#2.namevalue#1.#11 - main.component#2.namevalue#1.optwhite#11.in - main.component#2.namevalue#1.optwhite#11.out - main.component#2.namevalue#1.value#12.in - main.component#2.namevalue#1.#13 - main.component#2.namevalue#1.optwhite#14.in - main.component#2.namevalue#1.optwhite#14.out - main.component#2.namevalue#1.#14 - -NFA state 42 = main.component#2.namevalue#1.#9 - [(epsilon)] -> component#2.namevalue#1.qvalue#9.in - Epsilon closure : - (self) - main.component#2.namevalue#1.qvalue#9.in - -NFA state 43 = main.component#2.namevalue#1.optwhite#8.in - [(epsilon)] -> component#2.namevalue#1.optwhite#8.out - 0:[\t ] -> component#2.namevalue#1.optwhite#8.in - 1:[\r] -> component#2.namevalue#1.optwhite#8.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#9 - main.component#2.namevalue#1.optwhite#8.out - main.component#2.namevalue#1.qvalue#9.in - -NFA state 44 = main.component#2.namevalue#1.optwhite#8.out - [(epsilon)] -> component#2.namevalue#1.#9 - Epsilon closure : - (self) - main.component#2.namevalue#1.#9 - main.component#2.namevalue#1.qvalue#9.in - -NFA state 45 = main.component#2.namevalue#1.#10 - [(epsilon)] -> component#2.namevalue#1.optwhite#10.in - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.optwhite#10.in - main.component#2.namevalue#1.optwhite#10.out - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 46 = main.component#2.namevalue#1.qvalue#9.in - 3:["] -> component#2.namevalue#1.qvalue#9.qv0 - Epsilon closure : - (self) - -NFA state 47 = main.component#2.namevalue#1.qvalue#9.qv0 - [(epsilon)] -> component#2.namevalue#1.qvalue#9.escape#1.in - 0:[\t ] -> component#2.namevalue#1.qvalue#9.qv1 - 9:[;] -> component#2.namevalue#1.qvalue#9.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#2.namevalue#1.qvalue#9.qv1 - 11:[A-Z_a-z] -> component#2.namevalue#1.qvalue#9.qv1 - 10:[=] -> component#2.namevalue#1.qvalue#9.qv1 - 8:[0-9] -> component#2.namevalue#1.qvalue#9.qv1 - 7:[/] -> component#2.namevalue#1.qvalue#9.qv1 - 6:[\055] -> component#2.namevalue#1.qvalue#9.qv1 - 5:[+.] -> component#2.namevalue#1.qvalue#9.qv1 - 4:[*] -> component#2.namevalue#1.qvalue#9.qv1 - Epsilon closure : - (self) - main.component#2.namevalue#1.qvalue#9.escape#1.in - -NFA state 48 = main.component#2.namevalue#1.qvalue#9.escape#1.in - 12:[\\] -> component#2.namevalue#1.qvalue#9.escape#1.#2 - 12:[\\] -> component#2.namevalue#1.qvalue#9.escape#1.#1 - Epsilon closure : - (self) - -NFA state 49 = main.component#2.namevalue#1.qvalue#9.escape#1.#1 - 12:[\\] -> component#2.namevalue#1.qvalue#9.escape#1.out - Epsilon closure : - (self) - -NFA state 50 = main.component#2.namevalue#1.qvalue#9.escape#1.#2 - 3:["] -> component#2.namevalue#1.qvalue#9.escape#1.out - Epsilon closure : - (self) - -NFA state 51 = main.component#2.namevalue#1.qvalue#9.escape#1.out - [(epsilon)] -> component#2.namevalue#1.qvalue#9.qv1 - Epsilon closure : - (self) - main.component#2.namevalue#1.qvalue#9.qv1 - main.component#2.namevalue#1.qvalue#9.#1 - main.component#2.namevalue#1.qvalue#9.escape#2.in - main.component#2.namevalue#1.qvalue#9.qv2 - -NFA state 52 = main.component#2.namevalue#1.qvalue#9.qv1 - [(epsilon)] -> component#2.namevalue#1.qvalue#9.#1 - [(epsilon)] -> component#2.namevalue#1.qvalue#9.escape#2.in - 0:[\t ] -> component#2.namevalue#1.qvalue#9.qv1 - 9:[;] -> component#2.namevalue#1.qvalue#9.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#2.namevalue#1.qvalue#9.qv1 - 11:[A-Z_a-z] -> component#2.namevalue#1.qvalue#9.qv1 - 10:[=] -> component#2.namevalue#1.qvalue#9.qv1 - 8:[0-9] -> component#2.namevalue#1.qvalue#9.qv1 - 7:[/] -> component#2.namevalue#1.qvalue#9.qv1 - 6:[\055] -> component#2.namevalue#1.qvalue#9.qv1 - 5:[+.] -> component#2.namevalue#1.qvalue#9.qv1 - 4:[*] -> component#2.namevalue#1.qvalue#9.qv1 - [(epsilon)] -> component#2.namevalue#1.qvalue#9.qv2 - Epsilon closure : - (self) - main.component#2.namevalue#1.qvalue#9.#1 - main.component#2.namevalue#1.qvalue#9.escape#2.in - main.component#2.namevalue#1.qvalue#9.qv2 - -NFA state 53 = main.component#2.namevalue#1.qvalue#9.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 54 = main.component#2.namevalue#1.qvalue#9.escape#2.in - 12:[\\] -> component#2.namevalue#1.qvalue#9.escape#2.#2 - 12:[\\] -> component#2.namevalue#1.qvalue#9.escape#2.#1 - Epsilon closure : - (self) - -NFA state 55 = main.component#2.namevalue#1.qvalue#9.escape#2.#1 - 12:[\\] -> component#2.namevalue#1.qvalue#9.escape#2.out - Epsilon closure : - (self) - -NFA state 56 = main.component#2.namevalue#1.qvalue#9.escape#2.#2 - 3:["] -> component#2.namevalue#1.qvalue#9.escape#2.out - Epsilon closure : - (self) - -NFA state 57 = main.component#2.namevalue#1.qvalue#9.escape#2.out - [(epsilon)] -> component#2.namevalue#1.qvalue#9.qv1 - Epsilon closure : - (self) - main.component#2.namevalue#1.qvalue#9.qv1 - main.component#2.namevalue#1.qvalue#9.#1 - main.component#2.namevalue#1.qvalue#9.escape#2.in - main.component#2.namevalue#1.qvalue#9.qv2 - -NFA state 58 = main.component#2.namevalue#1.qvalue#9.qv2 - 3:["] -> component#2.namevalue#1.qvalue#9.out - Epsilon closure : - (self) - -NFA state 59 = main.component#2.namevalue#1.qvalue#9.out - [(epsilon)] -> component#2.namevalue#1.#10 - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.#10 - main.component#2.namevalue#1.optwhite#10.in - main.component#2.namevalue#1.optwhite#10.out - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 60 = main.component#2.namevalue#1.optwhite#10.in - [(epsilon)] -> component#2.namevalue#1.optwhite#10.out - 0:[\t ] -> component#2.namevalue#1.optwhite#10.in - 1:[\r] -> component#2.namevalue#1.optwhite#10.in - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.optwhite#10.out - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 61 = main.component#2.namevalue#1.optwhite#10.out - [(epsilon)] -> component#2.namevalue#1.out_normal - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 62 = main.component#2.namevalue#1.#11 - [(epsilon)] -> component#2.namevalue#1.value#12.in - Epsilon closure : - (self) - main.component#2.namevalue#1.value#12.in - -NFA state 63 = main.component#2.namevalue#1.optwhite#11.in - [(epsilon)] -> component#2.namevalue#1.optwhite#11.out - 0:[\t ] -> component#2.namevalue#1.optwhite#11.in - 1:[\r] -> component#2.namevalue#1.optwhite#11.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#11 - main.component#2.namevalue#1.optwhite#11.out - main.component#2.namevalue#1.value#12.in - -NFA state 64 = main.component#2.namevalue#1.optwhite#11.out - [(epsilon)] -> component#2.namevalue#1.#11 - Epsilon closure : - (self) - main.component#2.namevalue#1.#11 - main.component#2.namevalue#1.value#12.in - -NFA state 65 = main.component#2.namevalue#1.#12 - [(epsilon)] -> component#2.namevalue#1.optwhite#13.in - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.optwhite#13.in - main.component#2.namevalue#1.optwhite#13.out - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 66 = main.component#2.namevalue#1.value#12.in - 2:[!#-),:<>-@[]^`{-~] -> component#2.namevalue#1.value#12.v1 - 11:[A-Z_a-z] -> component#2.namevalue#1.value#12.v1 - 10:[=] -> component#2.namevalue#1.value#12.v1 - 8:[0-9] -> component#2.namevalue#1.value#12.v1 - 7:[/] -> component#2.namevalue#1.value#12.v1 - 6:[\055] -> component#2.namevalue#1.value#12.v1 - 5:[+.] -> component#2.namevalue#1.value#12.v1 - 4:[*] -> component#2.namevalue#1.value#12.v1 - Epsilon closure : - (self) - -NFA state 67 = main.component#2.namevalue#1.value#12.v1 - [(epsilon)] -> component#2.namevalue#1.value#12.#1 - [(epsilon)] -> component#2.namevalue#1.value#12.out - 2:[!#-),:<>-@[]^`{-~] -> component#2.namevalue#1.value#12.v1 - 11:[A-Z_a-z] -> component#2.namevalue#1.value#12.v1 - 10:[=] -> component#2.namevalue#1.value#12.v1 - 8:[0-9] -> component#2.namevalue#1.value#12.v1 - 7:[/] -> component#2.namevalue#1.value#12.v1 - 6:[\055] -> component#2.namevalue#1.value#12.v1 - 5:[+.] -> component#2.namevalue#1.value#12.v1 - 4:[*] -> component#2.namevalue#1.value#12.v1 - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.#12 - main.component#2.namevalue#1.value#12.#1 - main.component#2.namevalue#1.value#12.out - main.component#2.namevalue#1.optwhite#13.in - main.component#2.namevalue#1.optwhite#13.out - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 68 = main.component#2.namevalue#1.value#12.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 69 = main.component#2.namevalue#1.value#12.out - [(epsilon)] -> component#2.namevalue#1.#12 - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.#12 - main.component#2.namevalue#1.optwhite#13.in - main.component#2.namevalue#1.optwhite#13.out - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 70 = main.component#2.namevalue#1.optwhite#13.in - [(epsilon)] -> component#2.namevalue#1.optwhite#13.out - 0:[\t ] -> component#2.namevalue#1.optwhite#13.in - 1:[\r] -> component#2.namevalue#1.optwhite#13.in - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.optwhite#13.out - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 71 = main.component#2.namevalue#1.optwhite#13.out - [(epsilon)] -> component#2.namevalue#1.out_normal - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 72 = main.component#2.namevalue#1.#13 - [(epsilon)] -> component#2.namevalue#1.#14 - Epsilon closure : - (self) - main.component#2.namevalue#1.#14 - -NFA state 73 = main.component#2.namevalue#1.optwhite#14.in - [(epsilon)] -> component#2.namevalue#1.optwhite#14.out - 0:[\t ] -> component#2.namevalue#1.optwhite#14.in - 1:[\r] -> component#2.namevalue#1.optwhite#14.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#13 - main.component#2.namevalue#1.optwhite#14.out - main.component#2.namevalue#1.#14 - -NFA state 74 = main.component#2.namevalue#1.optwhite#14.out - [(epsilon)] -> component#2.namevalue#1.#13 - Epsilon closure : - (self) - main.component#2.namevalue#1.#13 - main.component#2.namevalue#1.#14 - -NFA state 75 = main.component#2.namevalue#1.#14 - EOS -> component#2.namevalue#1.out_normal - Epsilon closure : - (self) - -NFA state 76 = main.component#2.namevalue#1.rhs_continue - [(epsilon)] -> component#2.namevalue#1.optwhite#18.in - [(epsilon)] -> component#2.namevalue#1.optwhite#15.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#15 - main.component#2.namevalue#1.optwhite#15.in - main.component#2.namevalue#1.optwhite#15.out - main.component#2.namevalue#1.qvalue#16.in - main.component#2.namevalue#1.#17 - main.component#2.namevalue#1.optwhite#18.in - main.component#2.namevalue#1.optwhite#18.out - main.component#2.namevalue#1.value#19.in - -NFA state 77 = main.component#2.namevalue#1.#15 - [(epsilon)] -> component#2.namevalue#1.qvalue#16.in - Epsilon closure : - (self) - main.component#2.namevalue#1.qvalue#16.in - -NFA state 78 = main.component#2.namevalue#1.optwhite#15.in - [(epsilon)] -> component#2.namevalue#1.optwhite#15.out - 0:[\t ] -> component#2.namevalue#1.optwhite#15.in - 1:[\r] -> component#2.namevalue#1.optwhite#15.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#15 - main.component#2.namevalue#1.optwhite#15.out - main.component#2.namevalue#1.qvalue#16.in - -NFA state 79 = main.component#2.namevalue#1.optwhite#15.out - [(epsilon)] -> component#2.namevalue#1.#15 - Epsilon closure : - (self) - main.component#2.namevalue#1.#15 - main.component#2.namevalue#1.qvalue#16.in - -NFA state 80 = main.component#2.namevalue#1.#16 - [(epsilon)] -> component#2.namevalue#1.optwhite#17.in - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.optwhite#17.in - main.component#2.namevalue#1.optwhite#17.out - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 81 = main.component#2.namevalue#1.qvalue#16.in - 3:["] -> component#2.namevalue#1.qvalue#16.qv0 - Epsilon closure : - (self) - -NFA state 82 = main.component#2.namevalue#1.qvalue#16.qv0 - [(epsilon)] -> component#2.namevalue#1.qvalue#16.escape#1.in - 0:[\t ] -> component#2.namevalue#1.qvalue#16.qv1 - 9:[;] -> component#2.namevalue#1.qvalue#16.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#2.namevalue#1.qvalue#16.qv1 - 11:[A-Z_a-z] -> component#2.namevalue#1.qvalue#16.qv1 - 10:[=] -> component#2.namevalue#1.qvalue#16.qv1 - 8:[0-9] -> component#2.namevalue#1.qvalue#16.qv1 - 7:[/] -> component#2.namevalue#1.qvalue#16.qv1 - 6:[\055] -> component#2.namevalue#1.qvalue#16.qv1 - 5:[+.] -> component#2.namevalue#1.qvalue#16.qv1 - 4:[*] -> component#2.namevalue#1.qvalue#16.qv1 - Epsilon closure : - (self) - main.component#2.namevalue#1.qvalue#16.escape#1.in - -NFA state 83 = main.component#2.namevalue#1.qvalue#16.escape#1.in - 12:[\\] -> component#2.namevalue#1.qvalue#16.escape#1.#2 - 12:[\\] -> component#2.namevalue#1.qvalue#16.escape#1.#1 - Epsilon closure : - (self) - -NFA state 84 = main.component#2.namevalue#1.qvalue#16.escape#1.#1 - 12:[\\] -> component#2.namevalue#1.qvalue#16.escape#1.out - Epsilon closure : - (self) - -NFA state 85 = main.component#2.namevalue#1.qvalue#16.escape#1.#2 - 3:["] -> component#2.namevalue#1.qvalue#16.escape#1.out - Epsilon closure : - (self) - -NFA state 86 = main.component#2.namevalue#1.qvalue#16.escape#1.out - [(epsilon)] -> component#2.namevalue#1.qvalue#16.qv1 - Epsilon closure : - (self) - main.component#2.namevalue#1.qvalue#16.qv1 - main.component#2.namevalue#1.qvalue#16.#1 - main.component#2.namevalue#1.qvalue#16.escape#2.in - main.component#2.namevalue#1.qvalue#16.qv2 - -NFA state 87 = main.component#2.namevalue#1.qvalue#16.qv1 - [(epsilon)] -> component#2.namevalue#1.qvalue#16.#1 - [(epsilon)] -> component#2.namevalue#1.qvalue#16.escape#2.in - 0:[\t ] -> component#2.namevalue#1.qvalue#16.qv1 - 9:[;] -> component#2.namevalue#1.qvalue#16.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#2.namevalue#1.qvalue#16.qv1 - 11:[A-Z_a-z] -> component#2.namevalue#1.qvalue#16.qv1 - 10:[=] -> component#2.namevalue#1.qvalue#16.qv1 - 8:[0-9] -> component#2.namevalue#1.qvalue#16.qv1 - 7:[/] -> component#2.namevalue#1.qvalue#16.qv1 - 6:[\055] -> component#2.namevalue#1.qvalue#16.qv1 - 5:[+.] -> component#2.namevalue#1.qvalue#16.qv1 - 4:[*] -> component#2.namevalue#1.qvalue#16.qv1 - [(epsilon)] -> component#2.namevalue#1.qvalue#16.qv2 - Epsilon closure : - (self) - main.component#2.namevalue#1.qvalue#16.#1 - main.component#2.namevalue#1.qvalue#16.escape#2.in - main.component#2.namevalue#1.qvalue#16.qv2 - -NFA state 88 = main.component#2.namevalue#1.qvalue#16.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 89 = main.component#2.namevalue#1.qvalue#16.escape#2.in - 12:[\\] -> component#2.namevalue#1.qvalue#16.escape#2.#2 - 12:[\\] -> component#2.namevalue#1.qvalue#16.escape#2.#1 - Epsilon closure : - (self) - -NFA state 90 = main.component#2.namevalue#1.qvalue#16.escape#2.#1 - 12:[\\] -> component#2.namevalue#1.qvalue#16.escape#2.out - Epsilon closure : - (self) - -NFA state 91 = main.component#2.namevalue#1.qvalue#16.escape#2.#2 - 3:["] -> component#2.namevalue#1.qvalue#16.escape#2.out - Epsilon closure : - (self) - -NFA state 92 = main.component#2.namevalue#1.qvalue#16.escape#2.out - [(epsilon)] -> component#2.namevalue#1.qvalue#16.qv1 - Epsilon closure : - (self) - main.component#2.namevalue#1.qvalue#16.qv1 - main.component#2.namevalue#1.qvalue#16.#1 - main.component#2.namevalue#1.qvalue#16.escape#2.in - main.component#2.namevalue#1.qvalue#16.qv2 - -NFA state 93 = main.component#2.namevalue#1.qvalue#16.qv2 - 3:["] -> component#2.namevalue#1.qvalue#16.out - Epsilon closure : - (self) - -NFA state 94 = main.component#2.namevalue#1.qvalue#16.out - [(epsilon)] -> component#2.namevalue#1.#16 - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.#16 - main.component#2.namevalue#1.optwhite#17.in - main.component#2.namevalue#1.optwhite#17.out - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 95 = main.component#2.namevalue#1.optwhite#17.in - [(epsilon)] -> component#2.namevalue#1.optwhite#17.out - 0:[\t ] -> component#2.namevalue#1.optwhite#17.in - 1:[\r] -> component#2.namevalue#1.optwhite#17.in - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.optwhite#17.out - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 96 = main.component#2.namevalue#1.optwhite#17.out - [(epsilon)] -> component#2.namevalue#1.out_continue - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 97 = main.component#2.namevalue#1.#17 - [(epsilon)] -> component#2.namevalue#1.value#19.in - Epsilon closure : - (self) - main.component#2.namevalue#1.value#19.in - -NFA state 98 = main.component#2.namevalue#1.optwhite#18.in - [(epsilon)] -> component#2.namevalue#1.optwhite#18.out - 0:[\t ] -> component#2.namevalue#1.optwhite#18.in - 1:[\r] -> component#2.namevalue#1.optwhite#18.in - Epsilon closure : - (self) - main.component#2.namevalue#1.#17 - main.component#2.namevalue#1.optwhite#18.out - main.component#2.namevalue#1.value#19.in - -NFA state 99 = main.component#2.namevalue#1.optwhite#18.out - [(epsilon)] -> component#2.namevalue#1.#17 - Epsilon closure : - (self) - main.component#2.namevalue#1.#17 - main.component#2.namevalue#1.value#19.in - -NFA state 100 = main.component#2.namevalue#1.#18 - [(epsilon)] -> component#2.namevalue#1.optwhite#20.in - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.optwhite#20.in - main.component#2.namevalue#1.optwhite#20.out - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 101 = main.component#2.namevalue#1.value#19.in - 2:[!#-),:<>-@[]^`{-~] -> component#2.namevalue#1.value#19.v1 - 11:[A-Z_a-z] -> component#2.namevalue#1.value#19.v1 - 10:[=] -> component#2.namevalue#1.value#19.v1 - 8:[0-9] -> component#2.namevalue#1.value#19.v1 - 7:[/] -> component#2.namevalue#1.value#19.v1 - 6:[\055] -> component#2.namevalue#1.value#19.v1 - 5:[+.] -> component#2.namevalue#1.value#19.v1 - 4:[*] -> component#2.namevalue#1.value#19.v1 - Epsilon closure : - (self) - -NFA state 102 = main.component#2.namevalue#1.value#19.v1 - [(epsilon)] -> component#2.namevalue#1.value#19.#1 - [(epsilon)] -> component#2.namevalue#1.value#19.out - 2:[!#-),:<>-@[]^`{-~] -> component#2.namevalue#1.value#19.v1 - 11:[A-Z_a-z] -> component#2.namevalue#1.value#19.v1 - 10:[=] -> component#2.namevalue#1.value#19.v1 - 8:[0-9] -> component#2.namevalue#1.value#19.v1 - 7:[/] -> component#2.namevalue#1.value#19.v1 - 6:[\055] -> component#2.namevalue#1.value#19.v1 - 5:[+.] -> component#2.namevalue#1.value#19.v1 - 4:[*] -> component#2.namevalue#1.value#19.v1 - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.#18 - main.component#2.namevalue#1.value#19.#1 - main.component#2.namevalue#1.value#19.out - main.component#2.namevalue#1.optwhite#20.in - main.component#2.namevalue#1.optwhite#20.out - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 103 = main.component#2.namevalue#1.value#19.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 104 = main.component#2.namevalue#1.value#19.out - [(epsilon)] -> component#2.namevalue#1.#18 - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.#18 - main.component#2.namevalue#1.optwhite#20.in - main.component#2.namevalue#1.optwhite#20.out - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 105 = main.component#2.namevalue#1.optwhite#20.in - [(epsilon)] -> component#2.namevalue#1.optwhite#20.out - 0:[\t ] -> component#2.namevalue#1.optwhite#20.in - 1:[\r] -> component#2.namevalue#1.optwhite#20.in - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.optwhite#20.out - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 106 = main.component#2.namevalue#1.optwhite#20.out - [(epsilon)] -> component#2.namevalue#1.out_continue - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 107 = main.component#2.namevalue#1.out_normal - [(epsilon)] -> component#2.namevalue#1.out - [(epsilon)] -> component#2.namevalue#1.#19 - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 108 = main.component#2.namevalue#1.#19 - Tags : GOT_NAMEVALUE - Epsilon closure : - (self) - -NFA state 109 = main.component#2.namevalue#1.out_continue - [(epsilon)] -> component#2.namevalue#1.out - [(epsilon)] -> component#2.namevalue#1.#20 - Epsilon closure : - (self) - main.#2 - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 110 = main.component#2.namevalue#1.#20 - Tags : GOT_NAMEVALUE_CONT - Epsilon closure : - (self) - -NFA state 111 = main.component#2.namevalue#1.out - [(epsilon)] -> component#2.out - Epsilon closure : - (self) - main.#2 - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 112 = main.component#2.name#2.in - 6:[\055] -> component#2.name#2.name1 - 11:[A-Z_a-z] -> component#2.name#2.name1 - 8:[0-9] -> component#2.name#2.name1 - Epsilon closure : - (self) - -NFA state 113 = main.component#2.name#2.name1 - [(epsilon)] -> component#2.name#2.out - 0:[\t ] -> component#2.name#2.name2 - 6:[\055] -> component#2.name#2.name1 - 11:[A-Z_a-z] -> component#2.name#2.name1 - 8:[0-9] -> component#2.name#2.name1 - [(epsilon)] -> component#2.name#2.#2 - [(epsilon)] -> component#2.name#2.#1 - Epsilon closure : - (self) - main.#2 - main.component#2.name#2.#1 - main.component#2.name#2.#2 - main.component#2.name#2.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 114 = main.component#2.name#2.#1 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 115 = main.component#2.name#2.#2 - Tags : GOT_NAME - Epsilon closure : - (self) - -NFA state 116 = main.component#2.name#2.name2 - [(epsilon)] -> component#2.name#2.out - 6:[\055] -> component#2.name#2.name1 - 11:[A-Z_a-z] -> component#2.name#2.name1 - 8:[0-9] -> component#2.name#2.name1 - 0:[\t ] -> component#2.name#2.name2 - [(epsilon)] -> component#2.name#2.#4 - [(epsilon)] -> component#2.name#2.#3 - Epsilon closure : - (self) - main.#2 - main.component#2.name#2.#3 - main.component#2.name#2.#4 - main.component#2.name#2.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 117 = main.component#2.name#2.#3 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 118 = main.component#2.name#2.#4 - Tags : GOT_NAME_TRAILING_SPACE - Epsilon closure : - (self) - -NFA state 119 = main.component#2.name#2.out - [(epsilon)] -> component#2.out - Epsilon closure : - (self) - main.#2 - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 120 = main.component#2.majorminor#3.in - [(epsilon)] -> component#2.majorminor#3.major#1.in - Epsilon closure : - (self) - main.component#2.majorminor#3.major#1.in - -NFA state 121 = main.component#2.majorminor#3.major#1.in - 6:[\055] -> component#2.majorminor#3.major#1.name1 - 11:[A-Z_a-z] -> component#2.majorminor#3.major#1.name1 - 8:[0-9] -> component#2.majorminor#3.major#1.name1 - Epsilon closure : - (self) - -NFA state 122 = main.component#2.majorminor#3.major#1.name1 - 6:[\055] -> component#2.majorminor#3.major#1.name1 - 11:[A-Z_a-z] -> component#2.majorminor#3.major#1.name1 - 8:[0-9] -> component#2.majorminor#3.major#1.name1 - [(epsilon)] -> component#2.majorminor#3.major#1.out - Epsilon closure : - (self) - main.component#2.majorminor#3.major#1.out - main.component#2.majorminor#3.foo - -NFA state 123 = main.component#2.majorminor#3.major#1.out - [(epsilon)] -> component#2.majorminor#3.foo - Epsilon closure : - (self) - main.component#2.majorminor#3.foo - -NFA state 124 = main.component#2.majorminor#3.foo - 7:[/] -> component#2.majorminor#3.bar - Epsilon closure : - (self) - -NFA state 125 = main.component#2.majorminor#3.bar - [(epsilon)] -> component#2.majorminor#3.minor#2.in - Epsilon closure : - (self) - main.component#2.majorminor#3.minor#2.in - -NFA state 126 = main.component#2.majorminor#3.minor#2.in - 5:[+.] -> component#2.majorminor#3.minor#2.minor1 - 12:[\\] -> component#2.majorminor#3.minor#2.minor1 - 6:[\055] -> component#2.majorminor#3.minor#2.minor1 - 6:[\055] -> component#2.majorminor#3.minor#2.minor1 - 11:[A-Z_a-z] -> component#2.majorminor#3.minor#2.minor1 - 8:[0-9] -> component#2.majorminor#3.minor#2.minor1 - Epsilon closure : - (self) - -NFA state 127 = main.component#2.majorminor#3.minor#2.minor1 - [(epsilon)] -> component#2.majorminor#3.minor#2.#1 - 5:[+.] -> component#2.majorminor#3.minor#2.minor1 - 12:[\\] -> component#2.majorminor#3.minor#2.minor1 - 6:[\055] -> component#2.majorminor#3.minor#2.minor1 - 6:[\055] -> component#2.majorminor#3.minor#2.minor1 - 11:[A-Z_a-z] -> component#2.majorminor#3.minor#2.minor1 - 8:[0-9] -> component#2.majorminor#3.minor#2.minor1 - [(epsilon)] -> component#2.majorminor#3.minor#2.out - Epsilon closure : - (self) - main.#2 - main.component#2.majorminor#3.minor#2.#1 - main.component#2.majorminor#3.minor#2.out - main.component#2.majorminor#3.out - main.component#2.majorminor#3.#1 - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 128 = main.component#2.majorminor#3.minor#2.#1 - Tags : COPY_TO_MINOR - Epsilon closure : - (self) - -NFA state 129 = main.component#2.majorminor#3.minor#2.out - [(epsilon)] -> component#2.majorminor#3.out - Epsilon closure : - (self) - main.#2 - main.component#2.majorminor#3.out - main.component#2.majorminor#3.#1 - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 130 = main.component#2.majorminor#3.out - [(epsilon)] -> component#2.majorminor#3.#1 - [(epsilon)] -> component#2.out - Epsilon closure : - (self) - main.#2 - main.component#2.majorminor#3.#1 - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 131 = main.component#2.majorminor#3.#1 - Tags : GOT_MAJORMINOR - Epsilon closure : - (self) - -NFA state 132 = main.component#2.out - [(epsilon)] -> #2 - Epsilon closure : - (self) - main.#2 - main.#3 - main.optwhite#3.in - main.optwhite#3.out - -NFA state 133 = main.#3 - EOS -> out2 - Epsilon closure : - (self) - -NFA state 134 = main.optwhite#3.in - [(epsilon)] -> optwhite#3.out - 0:[\t ] -> optwhite#3.in - 1:[\r] -> optwhite#3.in - Epsilon closure : - (self) - main.#3 - main.optwhite#3.out - -NFA state 135 = main.optwhite#3.out - [(epsilon)] -> #3 - Epsilon closure : - (self) - main.#3 - -NFA state 136 = main.#4 - [(epsilon)] -> component#5.in - Epsilon closure : - (self) - main.component#5.in - main.component#5.namevalue#1.in - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.in - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.in - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - main.component#5.name#2.in - main.component#5.majorminor#3.in - main.component#5.majorminor#3.major#1.in - -NFA state 137 = main.optwhite#4.in - [(epsilon)] -> optwhite#4.out - 0:[\t ] -> optwhite#4.in - 1:[\r] -> optwhite#4.in - Epsilon closure : - (self) - main.#4 - main.optwhite#4.out - main.component#5.in - main.component#5.namevalue#1.in - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.in - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.in - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - main.component#5.name#2.in - main.component#5.majorminor#3.in - main.component#5.majorminor#3.major#1.in - -NFA state 138 = main.optwhite#4.out - [(epsilon)] -> #4 - Epsilon closure : - (self) - main.#4 - main.component#5.in - main.component#5.namevalue#1.in - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.in - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.in - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - main.component#5.name#2.in - main.component#5.majorminor#3.in - main.component#5.majorminor#3.major#1.in - -NFA state 139 = main.#5 - [(epsilon)] -> optwhite#6.in - Epsilon closure : - (self) - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 140 = main.component#5.in - [(epsilon)] -> component#5.namevalue#1.in - [(epsilon)] -> component#5.name#2.in - [(epsilon)] -> component#5.majorminor#3.in - Epsilon closure : - (self) - main.component#5.namevalue#1.in - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.in - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.in - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - main.component#5.name#2.in - main.component#5.majorminor#3.in - main.component#5.majorminor#3.major#1.in - -NFA state 141 = main.component#5.namevalue#1.in - [(epsilon)] -> component#5.namevalue#1.optwhite#4.in - [(epsilon)] -> component#5.namevalue#1.optwhite#1.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.in - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.in - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - -NFA state 142 = main.component#5.namevalue#1.#1 - [(epsilon)] -> component#5.namevalue#1.name#2.in - Epsilon closure : - (self) - main.component#5.namevalue#1.name#2.in - -NFA state 143 = main.component#5.namevalue#1.optwhite#1.in - [(epsilon)] -> component#5.namevalue#1.optwhite#1.out - 0:[\t ] -> component#5.namevalue#1.optwhite#1.in - 1:[\r] -> component#5.namevalue#1.optwhite#1.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - -NFA state 144 = main.component#5.namevalue#1.optwhite#1.out - [(epsilon)] -> component#5.namevalue#1.#1 - Epsilon closure : - (self) - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.name#2.in - -NFA state 145 = main.component#5.namevalue#1.#2 - [(epsilon)] -> component#5.namevalue#1.optwhite#3.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#3 - main.component#5.namevalue#1.optwhite#3.in - main.component#5.namevalue#1.optwhite#3.out - -NFA state 146 = main.component#5.namevalue#1.name#2.in - 6:[\055] -> component#5.namevalue#1.name#2.name1 - 11:[A-Z_a-z] -> component#5.namevalue#1.name#2.name1 - 8:[0-9] -> component#5.namevalue#1.name#2.name1 - Epsilon closure : - (self) - -NFA state 147 = main.component#5.namevalue#1.name#2.name1 - [(epsilon)] -> component#5.namevalue#1.name#2.#1 - [(epsilon)] -> component#5.namevalue#1.name#2.#2 - 6:[\055] -> component#5.namevalue#1.name#2.name1 - 11:[A-Z_a-z] -> component#5.namevalue#1.name#2.name1 - 8:[0-9] -> component#5.namevalue#1.name#2.name1 - 0:[\t ] -> component#5.namevalue#1.name#2.name2 - [(epsilon)] -> component#5.namevalue#1.name#2.out - Epsilon closure : - (self) - main.component#5.namevalue#1.#2 - main.component#5.namevalue#1.name#2.#1 - main.component#5.namevalue#1.name#2.#2 - main.component#5.namevalue#1.name#2.out - main.component#5.namevalue#1.#3 - main.component#5.namevalue#1.optwhite#3.in - main.component#5.namevalue#1.optwhite#3.out - -NFA state 148 = main.component#5.namevalue#1.name#2.#1 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 149 = main.component#5.namevalue#1.name#2.#2 - Tags : GOT_NAME - Epsilon closure : - (self) - -NFA state 150 = main.component#5.namevalue#1.name#2.name2 - [(epsilon)] -> component#5.namevalue#1.name#2.#3 - [(epsilon)] -> component#5.namevalue#1.name#2.#4 - 0:[\t ] -> component#5.namevalue#1.name#2.name2 - 6:[\055] -> component#5.namevalue#1.name#2.name1 - 11:[A-Z_a-z] -> component#5.namevalue#1.name#2.name1 - 8:[0-9] -> component#5.namevalue#1.name#2.name1 - [(epsilon)] -> component#5.namevalue#1.name#2.out - Epsilon closure : - (self) - main.component#5.namevalue#1.#2 - main.component#5.namevalue#1.name#2.#3 - main.component#5.namevalue#1.name#2.#4 - main.component#5.namevalue#1.name#2.out - main.component#5.namevalue#1.#3 - main.component#5.namevalue#1.optwhite#3.in - main.component#5.namevalue#1.optwhite#3.out - -NFA state 151 = main.component#5.namevalue#1.name#2.#3 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 152 = main.component#5.namevalue#1.name#2.#4 - Tags : GOT_NAME_TRAILING_SPACE - Epsilon closure : - (self) - -NFA state 153 = main.component#5.namevalue#1.name#2.out - [(epsilon)] -> component#5.namevalue#1.#2 - Epsilon closure : - (self) - main.component#5.namevalue#1.#2 - main.component#5.namevalue#1.#3 - main.component#5.namevalue#1.optwhite#3.in - main.component#5.namevalue#1.optwhite#3.out - -NFA state 154 = main.component#5.namevalue#1.#3 - 10:[=] -> component#5.namevalue#1.rhs_normal - Epsilon closure : - (self) - -NFA state 155 = main.component#5.namevalue#1.optwhite#3.in - [(epsilon)] -> component#5.namevalue#1.optwhite#3.out - 0:[\t ] -> component#5.namevalue#1.optwhite#3.in - 1:[\r] -> component#5.namevalue#1.optwhite#3.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#3 - main.component#5.namevalue#1.optwhite#3.out - -NFA state 156 = main.component#5.namevalue#1.optwhite#3.out - [(epsilon)] -> component#5.namevalue#1.#3 - Epsilon closure : - (self) - main.component#5.namevalue#1.#3 - -NFA state 157 = main.component#5.namevalue#1.#4 - [(epsilon)] -> component#5.namevalue#1.name#5.in - Epsilon closure : - (self) - main.component#5.namevalue#1.name#5.in - -NFA state 158 = main.component#5.namevalue#1.optwhite#4.in - [(epsilon)] -> component#5.namevalue#1.optwhite#4.out - 0:[\t ] -> component#5.namevalue#1.optwhite#4.in - 1:[\r] -> component#5.namevalue#1.optwhite#4.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - -NFA state 159 = main.component#5.namevalue#1.optwhite#4.out - [(epsilon)] -> component#5.namevalue#1.#4 - Epsilon closure : - (self) - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.name#5.in - -NFA state 160 = main.component#5.namevalue#1.#5 - 4:[*] -> component#5.namevalue#1.#6 - Epsilon closure : - (self) - -NFA state 161 = main.component#5.namevalue#1.name#5.in - 6:[\055] -> component#5.namevalue#1.name#5.name1 - 11:[A-Z_a-z] -> component#5.namevalue#1.name#5.name1 - 8:[0-9] -> component#5.namevalue#1.name#5.name1 - Epsilon closure : - (self) - -NFA state 162 = main.component#5.namevalue#1.name#5.name1 - [(epsilon)] -> component#5.namevalue#1.name#5.#1 - [(epsilon)] -> component#5.namevalue#1.name#5.#2 - 6:[\055] -> component#5.namevalue#1.name#5.name1 - 11:[A-Z_a-z] -> component#5.namevalue#1.name#5.name1 - 8:[0-9] -> component#5.namevalue#1.name#5.name1 - 0:[\t ] -> component#5.namevalue#1.name#5.name2 - [(epsilon)] -> component#5.namevalue#1.name#5.out - Epsilon closure : - (self) - main.component#5.namevalue#1.#5 - main.component#5.namevalue#1.name#5.#1 - main.component#5.namevalue#1.name#5.#2 - main.component#5.namevalue#1.name#5.out - -NFA state 163 = main.component#5.namevalue#1.name#5.#1 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 164 = main.component#5.namevalue#1.name#5.#2 - Tags : GOT_NAME - Epsilon closure : - (self) - -NFA state 165 = main.component#5.namevalue#1.name#5.name2 - [(epsilon)] -> component#5.namevalue#1.name#5.#3 - [(epsilon)] -> component#5.namevalue#1.name#5.#4 - 0:[\t ] -> component#5.namevalue#1.name#5.name2 - 6:[\055] -> component#5.namevalue#1.name#5.name1 - 11:[A-Z_a-z] -> component#5.namevalue#1.name#5.name1 - 8:[0-9] -> component#5.namevalue#1.name#5.name1 - [(epsilon)] -> component#5.namevalue#1.name#5.out - Epsilon closure : - (self) - main.component#5.namevalue#1.#5 - main.component#5.namevalue#1.name#5.#3 - main.component#5.namevalue#1.name#5.#4 - main.component#5.namevalue#1.name#5.out - -NFA state 166 = main.component#5.namevalue#1.name#5.#3 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 167 = main.component#5.namevalue#1.name#5.#4 - Tags : GOT_NAME_TRAILING_SPACE - Epsilon closure : - (self) - -NFA state 168 = main.component#5.namevalue#1.name#5.out - [(epsilon)] -> component#5.namevalue#1.#5 - Epsilon closure : - (self) - main.component#5.namevalue#1.#5 - -NFA state 169 = main.component#5.namevalue#1.#6 - [(epsilon)] -> component#5.namevalue#1.digits#6.in - Epsilon closure : - (self) - main.component#5.namevalue#1.digits#6.in - -NFA state 170 = main.component#5.namevalue#1.#7 - [(epsilon)] -> component#5.namevalue#1.optwhite#7.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#8 - main.component#5.namevalue#1.optwhite#7.in - main.component#5.namevalue#1.optwhite#7.out - -NFA state 171 = main.component#5.namevalue#1.digits#6.in - 8:[0-9] -> component#5.namevalue#1.digits#6.out - 8:[0-9] -> component#5.namevalue#1.digits#6.in - Epsilon closure : - (self) - -NFA state 172 = main.component#5.namevalue#1.digits#6.out - [(epsilon)] -> component#5.namevalue#1.#7 - Epsilon closure : - (self) - main.component#5.namevalue#1.#7 - main.component#5.namevalue#1.#8 - main.component#5.namevalue#1.optwhite#7.in - main.component#5.namevalue#1.optwhite#7.out - -NFA state 173 = main.component#5.namevalue#1.#8 - 10:[=] -> component#5.namevalue#1.rhs_continue - Epsilon closure : - (self) - -NFA state 174 = main.component#5.namevalue#1.optwhite#7.in - [(epsilon)] -> component#5.namevalue#1.optwhite#7.out - 0:[\t ] -> component#5.namevalue#1.optwhite#7.in - 1:[\r] -> component#5.namevalue#1.optwhite#7.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#8 - main.component#5.namevalue#1.optwhite#7.out - -NFA state 175 = main.component#5.namevalue#1.optwhite#7.out - [(epsilon)] -> component#5.namevalue#1.#8 - Epsilon closure : - (self) - main.component#5.namevalue#1.#8 - -NFA state 176 = main.component#5.namevalue#1.rhs_normal - [(epsilon)] -> component#5.namevalue#1.optwhite#14.in - [(epsilon)] -> component#5.namevalue#1.optwhite#11.in - [(epsilon)] -> component#5.namevalue#1.optwhite#8.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#9 - main.component#5.namevalue#1.optwhite#8.in - main.component#5.namevalue#1.optwhite#8.out - main.component#5.namevalue#1.qvalue#9.in - main.component#5.namevalue#1.#11 - main.component#5.namevalue#1.optwhite#11.in - main.component#5.namevalue#1.optwhite#11.out - main.component#5.namevalue#1.value#12.in - main.component#5.namevalue#1.#13 - main.component#5.namevalue#1.optwhite#14.in - main.component#5.namevalue#1.optwhite#14.out - main.component#5.namevalue#1.#14 - -NFA state 177 = main.component#5.namevalue#1.#9 - [(epsilon)] -> component#5.namevalue#1.qvalue#9.in - Epsilon closure : - (self) - main.component#5.namevalue#1.qvalue#9.in - -NFA state 178 = main.component#5.namevalue#1.optwhite#8.in - [(epsilon)] -> component#5.namevalue#1.optwhite#8.out - 0:[\t ] -> component#5.namevalue#1.optwhite#8.in - 1:[\r] -> component#5.namevalue#1.optwhite#8.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#9 - main.component#5.namevalue#1.optwhite#8.out - main.component#5.namevalue#1.qvalue#9.in - -NFA state 179 = main.component#5.namevalue#1.optwhite#8.out - [(epsilon)] -> component#5.namevalue#1.#9 - Epsilon closure : - (self) - main.component#5.namevalue#1.#9 - main.component#5.namevalue#1.qvalue#9.in - -NFA state 180 = main.component#5.namevalue#1.#10 - [(epsilon)] -> component#5.namevalue#1.optwhite#10.in - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.optwhite#10.in - main.component#5.namevalue#1.optwhite#10.out - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 181 = main.component#5.namevalue#1.qvalue#9.in - 3:["] -> component#5.namevalue#1.qvalue#9.qv0 - Epsilon closure : - (self) - -NFA state 182 = main.component#5.namevalue#1.qvalue#9.qv0 - [(epsilon)] -> component#5.namevalue#1.qvalue#9.escape#1.in - 0:[\t ] -> component#5.namevalue#1.qvalue#9.qv1 - 9:[;] -> component#5.namevalue#1.qvalue#9.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#5.namevalue#1.qvalue#9.qv1 - 11:[A-Z_a-z] -> component#5.namevalue#1.qvalue#9.qv1 - 10:[=] -> component#5.namevalue#1.qvalue#9.qv1 - 8:[0-9] -> component#5.namevalue#1.qvalue#9.qv1 - 7:[/] -> component#5.namevalue#1.qvalue#9.qv1 - 6:[\055] -> component#5.namevalue#1.qvalue#9.qv1 - 5:[+.] -> component#5.namevalue#1.qvalue#9.qv1 - 4:[*] -> component#5.namevalue#1.qvalue#9.qv1 - Epsilon closure : - (self) - main.component#5.namevalue#1.qvalue#9.escape#1.in - -NFA state 183 = main.component#5.namevalue#1.qvalue#9.escape#1.in - 12:[\\] -> component#5.namevalue#1.qvalue#9.escape#1.#2 - 12:[\\] -> component#5.namevalue#1.qvalue#9.escape#1.#1 - Epsilon closure : - (self) - -NFA state 184 = main.component#5.namevalue#1.qvalue#9.escape#1.#1 - 12:[\\] -> component#5.namevalue#1.qvalue#9.escape#1.out - Epsilon closure : - (self) - -NFA state 185 = main.component#5.namevalue#1.qvalue#9.escape#1.#2 - 3:["] -> component#5.namevalue#1.qvalue#9.escape#1.out - Epsilon closure : - (self) - -NFA state 186 = main.component#5.namevalue#1.qvalue#9.escape#1.out - [(epsilon)] -> component#5.namevalue#1.qvalue#9.qv1 - Epsilon closure : - (self) - main.component#5.namevalue#1.qvalue#9.qv1 - main.component#5.namevalue#1.qvalue#9.#1 - main.component#5.namevalue#1.qvalue#9.escape#2.in - main.component#5.namevalue#1.qvalue#9.qv2 - -NFA state 187 = main.component#5.namevalue#1.qvalue#9.qv1 - [(epsilon)] -> component#5.namevalue#1.qvalue#9.#1 - [(epsilon)] -> component#5.namevalue#1.qvalue#9.escape#2.in - 0:[\t ] -> component#5.namevalue#1.qvalue#9.qv1 - 9:[;] -> component#5.namevalue#1.qvalue#9.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#5.namevalue#1.qvalue#9.qv1 - 11:[A-Z_a-z] -> component#5.namevalue#1.qvalue#9.qv1 - 10:[=] -> component#5.namevalue#1.qvalue#9.qv1 - 8:[0-9] -> component#5.namevalue#1.qvalue#9.qv1 - 7:[/] -> component#5.namevalue#1.qvalue#9.qv1 - 6:[\055] -> component#5.namevalue#1.qvalue#9.qv1 - 5:[+.] -> component#5.namevalue#1.qvalue#9.qv1 - 4:[*] -> component#5.namevalue#1.qvalue#9.qv1 - [(epsilon)] -> component#5.namevalue#1.qvalue#9.qv2 - Epsilon closure : - (self) - main.component#5.namevalue#1.qvalue#9.#1 - main.component#5.namevalue#1.qvalue#9.escape#2.in - main.component#5.namevalue#1.qvalue#9.qv2 - -NFA state 188 = main.component#5.namevalue#1.qvalue#9.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 189 = main.component#5.namevalue#1.qvalue#9.escape#2.in - 12:[\\] -> component#5.namevalue#1.qvalue#9.escape#2.#2 - 12:[\\] -> component#5.namevalue#1.qvalue#9.escape#2.#1 - Epsilon closure : - (self) - -NFA state 190 = main.component#5.namevalue#1.qvalue#9.escape#2.#1 - 12:[\\] -> component#5.namevalue#1.qvalue#9.escape#2.out - Epsilon closure : - (self) - -NFA state 191 = main.component#5.namevalue#1.qvalue#9.escape#2.#2 - 3:["] -> component#5.namevalue#1.qvalue#9.escape#2.out - Epsilon closure : - (self) - -NFA state 192 = main.component#5.namevalue#1.qvalue#9.escape#2.out - [(epsilon)] -> component#5.namevalue#1.qvalue#9.qv1 - Epsilon closure : - (self) - main.component#5.namevalue#1.qvalue#9.qv1 - main.component#5.namevalue#1.qvalue#9.#1 - main.component#5.namevalue#1.qvalue#9.escape#2.in - main.component#5.namevalue#1.qvalue#9.qv2 - -NFA state 193 = main.component#5.namevalue#1.qvalue#9.qv2 - 3:["] -> component#5.namevalue#1.qvalue#9.out - Epsilon closure : - (self) - -NFA state 194 = main.component#5.namevalue#1.qvalue#9.out - [(epsilon)] -> component#5.namevalue#1.#10 - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.#10 - main.component#5.namevalue#1.optwhite#10.in - main.component#5.namevalue#1.optwhite#10.out - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 195 = main.component#5.namevalue#1.optwhite#10.in - [(epsilon)] -> component#5.namevalue#1.optwhite#10.out - 0:[\t ] -> component#5.namevalue#1.optwhite#10.in - 1:[\r] -> component#5.namevalue#1.optwhite#10.in - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.optwhite#10.out - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 196 = main.component#5.namevalue#1.optwhite#10.out - [(epsilon)] -> component#5.namevalue#1.out_normal - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 197 = main.component#5.namevalue#1.#11 - [(epsilon)] -> component#5.namevalue#1.value#12.in - Epsilon closure : - (self) - main.component#5.namevalue#1.value#12.in - -NFA state 198 = main.component#5.namevalue#1.optwhite#11.in - [(epsilon)] -> component#5.namevalue#1.optwhite#11.out - 0:[\t ] -> component#5.namevalue#1.optwhite#11.in - 1:[\r] -> component#5.namevalue#1.optwhite#11.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#11 - main.component#5.namevalue#1.optwhite#11.out - main.component#5.namevalue#1.value#12.in - -NFA state 199 = main.component#5.namevalue#1.optwhite#11.out - [(epsilon)] -> component#5.namevalue#1.#11 - Epsilon closure : - (self) - main.component#5.namevalue#1.#11 - main.component#5.namevalue#1.value#12.in - -NFA state 200 = main.component#5.namevalue#1.#12 - [(epsilon)] -> component#5.namevalue#1.optwhite#13.in - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.optwhite#13.in - main.component#5.namevalue#1.optwhite#13.out - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 201 = main.component#5.namevalue#1.value#12.in - 2:[!#-),:<>-@[]^`{-~] -> component#5.namevalue#1.value#12.v1 - 11:[A-Z_a-z] -> component#5.namevalue#1.value#12.v1 - 10:[=] -> component#5.namevalue#1.value#12.v1 - 8:[0-9] -> component#5.namevalue#1.value#12.v1 - 7:[/] -> component#5.namevalue#1.value#12.v1 - 6:[\055] -> component#5.namevalue#1.value#12.v1 - 5:[+.] -> component#5.namevalue#1.value#12.v1 - 4:[*] -> component#5.namevalue#1.value#12.v1 - Epsilon closure : - (self) - -NFA state 202 = main.component#5.namevalue#1.value#12.v1 - [(epsilon)] -> component#5.namevalue#1.value#12.#1 - [(epsilon)] -> component#5.namevalue#1.value#12.out - 2:[!#-),:<>-@[]^`{-~] -> component#5.namevalue#1.value#12.v1 - 11:[A-Z_a-z] -> component#5.namevalue#1.value#12.v1 - 10:[=] -> component#5.namevalue#1.value#12.v1 - 8:[0-9] -> component#5.namevalue#1.value#12.v1 - 7:[/] -> component#5.namevalue#1.value#12.v1 - 6:[\055] -> component#5.namevalue#1.value#12.v1 - 5:[+.] -> component#5.namevalue#1.value#12.v1 - 4:[*] -> component#5.namevalue#1.value#12.v1 - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.#12 - main.component#5.namevalue#1.value#12.#1 - main.component#5.namevalue#1.value#12.out - main.component#5.namevalue#1.optwhite#13.in - main.component#5.namevalue#1.optwhite#13.out - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 203 = main.component#5.namevalue#1.value#12.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 204 = main.component#5.namevalue#1.value#12.out - [(epsilon)] -> component#5.namevalue#1.#12 - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.#12 - main.component#5.namevalue#1.optwhite#13.in - main.component#5.namevalue#1.optwhite#13.out - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 205 = main.component#5.namevalue#1.optwhite#13.in - [(epsilon)] -> component#5.namevalue#1.optwhite#13.out - 0:[\t ] -> component#5.namevalue#1.optwhite#13.in - 1:[\r] -> component#5.namevalue#1.optwhite#13.in - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.optwhite#13.out - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 206 = main.component#5.namevalue#1.optwhite#13.out - [(epsilon)] -> component#5.namevalue#1.out_normal - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 207 = main.component#5.namevalue#1.#13 - [(epsilon)] -> component#5.namevalue#1.#14 - Epsilon closure : - (self) - main.component#5.namevalue#1.#14 - -NFA state 208 = main.component#5.namevalue#1.optwhite#14.in - [(epsilon)] -> component#5.namevalue#1.optwhite#14.out - 0:[\t ] -> component#5.namevalue#1.optwhite#14.in - 1:[\r] -> component#5.namevalue#1.optwhite#14.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#13 - main.component#5.namevalue#1.optwhite#14.out - main.component#5.namevalue#1.#14 - -NFA state 209 = main.component#5.namevalue#1.optwhite#14.out - [(epsilon)] -> component#5.namevalue#1.#13 - Epsilon closure : - (self) - main.component#5.namevalue#1.#13 - main.component#5.namevalue#1.#14 - -NFA state 210 = main.component#5.namevalue#1.#14 - EOS -> component#5.namevalue#1.out_normal - Epsilon closure : - (self) - -NFA state 211 = main.component#5.namevalue#1.rhs_continue - [(epsilon)] -> component#5.namevalue#1.optwhite#18.in - [(epsilon)] -> component#5.namevalue#1.optwhite#15.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#15 - main.component#5.namevalue#1.optwhite#15.in - main.component#5.namevalue#1.optwhite#15.out - main.component#5.namevalue#1.qvalue#16.in - main.component#5.namevalue#1.#17 - main.component#5.namevalue#1.optwhite#18.in - main.component#5.namevalue#1.optwhite#18.out - main.component#5.namevalue#1.value#19.in - -NFA state 212 = main.component#5.namevalue#1.#15 - [(epsilon)] -> component#5.namevalue#1.qvalue#16.in - Epsilon closure : - (self) - main.component#5.namevalue#1.qvalue#16.in - -NFA state 213 = main.component#5.namevalue#1.optwhite#15.in - [(epsilon)] -> component#5.namevalue#1.optwhite#15.out - 0:[\t ] -> component#5.namevalue#1.optwhite#15.in - 1:[\r] -> component#5.namevalue#1.optwhite#15.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#15 - main.component#5.namevalue#1.optwhite#15.out - main.component#5.namevalue#1.qvalue#16.in - -NFA state 214 = main.component#5.namevalue#1.optwhite#15.out - [(epsilon)] -> component#5.namevalue#1.#15 - Epsilon closure : - (self) - main.component#5.namevalue#1.#15 - main.component#5.namevalue#1.qvalue#16.in - -NFA state 215 = main.component#5.namevalue#1.#16 - [(epsilon)] -> component#5.namevalue#1.optwhite#17.in - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.optwhite#17.in - main.component#5.namevalue#1.optwhite#17.out - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 216 = main.component#5.namevalue#1.qvalue#16.in - 3:["] -> component#5.namevalue#1.qvalue#16.qv0 - Epsilon closure : - (self) - -NFA state 217 = main.component#5.namevalue#1.qvalue#16.qv0 - [(epsilon)] -> component#5.namevalue#1.qvalue#16.escape#1.in - 0:[\t ] -> component#5.namevalue#1.qvalue#16.qv1 - 9:[;] -> component#5.namevalue#1.qvalue#16.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#5.namevalue#1.qvalue#16.qv1 - 11:[A-Z_a-z] -> component#5.namevalue#1.qvalue#16.qv1 - 10:[=] -> component#5.namevalue#1.qvalue#16.qv1 - 8:[0-9] -> component#5.namevalue#1.qvalue#16.qv1 - 7:[/] -> component#5.namevalue#1.qvalue#16.qv1 - 6:[\055] -> component#5.namevalue#1.qvalue#16.qv1 - 5:[+.] -> component#5.namevalue#1.qvalue#16.qv1 - 4:[*] -> component#5.namevalue#1.qvalue#16.qv1 - Epsilon closure : - (self) - main.component#5.namevalue#1.qvalue#16.escape#1.in - -NFA state 218 = main.component#5.namevalue#1.qvalue#16.escape#1.in - 12:[\\] -> component#5.namevalue#1.qvalue#16.escape#1.#2 - 12:[\\] -> component#5.namevalue#1.qvalue#16.escape#1.#1 - Epsilon closure : - (self) - -NFA state 219 = main.component#5.namevalue#1.qvalue#16.escape#1.#1 - 12:[\\] -> component#5.namevalue#1.qvalue#16.escape#1.out - Epsilon closure : - (self) - -NFA state 220 = main.component#5.namevalue#1.qvalue#16.escape#1.#2 - 3:["] -> component#5.namevalue#1.qvalue#16.escape#1.out - Epsilon closure : - (self) - -NFA state 221 = main.component#5.namevalue#1.qvalue#16.escape#1.out - [(epsilon)] -> component#5.namevalue#1.qvalue#16.qv1 - Epsilon closure : - (self) - main.component#5.namevalue#1.qvalue#16.qv1 - main.component#5.namevalue#1.qvalue#16.#1 - main.component#5.namevalue#1.qvalue#16.escape#2.in - main.component#5.namevalue#1.qvalue#16.qv2 - -NFA state 222 = main.component#5.namevalue#1.qvalue#16.qv1 - [(epsilon)] -> component#5.namevalue#1.qvalue#16.#1 - [(epsilon)] -> component#5.namevalue#1.qvalue#16.escape#2.in - 0:[\t ] -> component#5.namevalue#1.qvalue#16.qv1 - 9:[;] -> component#5.namevalue#1.qvalue#16.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#5.namevalue#1.qvalue#16.qv1 - 11:[A-Z_a-z] -> component#5.namevalue#1.qvalue#16.qv1 - 10:[=] -> component#5.namevalue#1.qvalue#16.qv1 - 8:[0-9] -> component#5.namevalue#1.qvalue#16.qv1 - 7:[/] -> component#5.namevalue#1.qvalue#16.qv1 - 6:[\055] -> component#5.namevalue#1.qvalue#16.qv1 - 5:[+.] -> component#5.namevalue#1.qvalue#16.qv1 - 4:[*] -> component#5.namevalue#1.qvalue#16.qv1 - [(epsilon)] -> component#5.namevalue#1.qvalue#16.qv2 - Epsilon closure : - (self) - main.component#5.namevalue#1.qvalue#16.#1 - main.component#5.namevalue#1.qvalue#16.escape#2.in - main.component#5.namevalue#1.qvalue#16.qv2 - -NFA state 223 = main.component#5.namevalue#1.qvalue#16.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 224 = main.component#5.namevalue#1.qvalue#16.escape#2.in - 12:[\\] -> component#5.namevalue#1.qvalue#16.escape#2.#2 - 12:[\\] -> component#5.namevalue#1.qvalue#16.escape#2.#1 - Epsilon closure : - (self) - -NFA state 225 = main.component#5.namevalue#1.qvalue#16.escape#2.#1 - 12:[\\] -> component#5.namevalue#1.qvalue#16.escape#2.out - Epsilon closure : - (self) - -NFA state 226 = main.component#5.namevalue#1.qvalue#16.escape#2.#2 - 3:["] -> component#5.namevalue#1.qvalue#16.escape#2.out - Epsilon closure : - (self) - -NFA state 227 = main.component#5.namevalue#1.qvalue#16.escape#2.out - [(epsilon)] -> component#5.namevalue#1.qvalue#16.qv1 - Epsilon closure : - (self) - main.component#5.namevalue#1.qvalue#16.qv1 - main.component#5.namevalue#1.qvalue#16.#1 - main.component#5.namevalue#1.qvalue#16.escape#2.in - main.component#5.namevalue#1.qvalue#16.qv2 - -NFA state 228 = main.component#5.namevalue#1.qvalue#16.qv2 - 3:["] -> component#5.namevalue#1.qvalue#16.out - Epsilon closure : - (self) - -NFA state 229 = main.component#5.namevalue#1.qvalue#16.out - [(epsilon)] -> component#5.namevalue#1.#16 - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.#16 - main.component#5.namevalue#1.optwhite#17.in - main.component#5.namevalue#1.optwhite#17.out - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 230 = main.component#5.namevalue#1.optwhite#17.in - [(epsilon)] -> component#5.namevalue#1.optwhite#17.out - 0:[\t ] -> component#5.namevalue#1.optwhite#17.in - 1:[\r] -> component#5.namevalue#1.optwhite#17.in - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.optwhite#17.out - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 231 = main.component#5.namevalue#1.optwhite#17.out - [(epsilon)] -> component#5.namevalue#1.out_continue - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 232 = main.component#5.namevalue#1.#17 - [(epsilon)] -> component#5.namevalue#1.value#19.in - Epsilon closure : - (self) - main.component#5.namevalue#1.value#19.in - -NFA state 233 = main.component#5.namevalue#1.optwhite#18.in - [(epsilon)] -> component#5.namevalue#1.optwhite#18.out - 0:[\t ] -> component#5.namevalue#1.optwhite#18.in - 1:[\r] -> component#5.namevalue#1.optwhite#18.in - Epsilon closure : - (self) - main.component#5.namevalue#1.#17 - main.component#5.namevalue#1.optwhite#18.out - main.component#5.namevalue#1.value#19.in - -NFA state 234 = main.component#5.namevalue#1.optwhite#18.out - [(epsilon)] -> component#5.namevalue#1.#17 - Epsilon closure : - (self) - main.component#5.namevalue#1.#17 - main.component#5.namevalue#1.value#19.in - -NFA state 235 = main.component#5.namevalue#1.#18 - [(epsilon)] -> component#5.namevalue#1.optwhite#20.in - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.optwhite#20.in - main.component#5.namevalue#1.optwhite#20.out - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 236 = main.component#5.namevalue#1.value#19.in - 2:[!#-),:<>-@[]^`{-~] -> component#5.namevalue#1.value#19.v1 - 11:[A-Z_a-z] -> component#5.namevalue#1.value#19.v1 - 10:[=] -> component#5.namevalue#1.value#19.v1 - 8:[0-9] -> component#5.namevalue#1.value#19.v1 - 7:[/] -> component#5.namevalue#1.value#19.v1 - 6:[\055] -> component#5.namevalue#1.value#19.v1 - 5:[+.] -> component#5.namevalue#1.value#19.v1 - 4:[*] -> component#5.namevalue#1.value#19.v1 - Epsilon closure : - (self) - -NFA state 237 = main.component#5.namevalue#1.value#19.v1 - [(epsilon)] -> component#5.namevalue#1.value#19.#1 - [(epsilon)] -> component#5.namevalue#1.value#19.out - 2:[!#-),:<>-@[]^`{-~] -> component#5.namevalue#1.value#19.v1 - 11:[A-Z_a-z] -> component#5.namevalue#1.value#19.v1 - 10:[=] -> component#5.namevalue#1.value#19.v1 - 8:[0-9] -> component#5.namevalue#1.value#19.v1 - 7:[/] -> component#5.namevalue#1.value#19.v1 - 6:[\055] -> component#5.namevalue#1.value#19.v1 - 5:[+.] -> component#5.namevalue#1.value#19.v1 - 4:[*] -> component#5.namevalue#1.value#19.v1 - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.#18 - main.component#5.namevalue#1.value#19.#1 - main.component#5.namevalue#1.value#19.out - main.component#5.namevalue#1.optwhite#20.in - main.component#5.namevalue#1.optwhite#20.out - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 238 = main.component#5.namevalue#1.value#19.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 239 = main.component#5.namevalue#1.value#19.out - [(epsilon)] -> component#5.namevalue#1.#18 - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.#18 - main.component#5.namevalue#1.optwhite#20.in - main.component#5.namevalue#1.optwhite#20.out - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 240 = main.component#5.namevalue#1.optwhite#20.in - [(epsilon)] -> component#5.namevalue#1.optwhite#20.out - 0:[\t ] -> component#5.namevalue#1.optwhite#20.in - 1:[\r] -> component#5.namevalue#1.optwhite#20.in - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.optwhite#20.out - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 241 = main.component#5.namevalue#1.optwhite#20.out - [(epsilon)] -> component#5.namevalue#1.out_continue - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 242 = main.component#5.namevalue#1.out_normal - [(epsilon)] -> component#5.namevalue#1.out - [(epsilon)] -> component#5.namevalue#1.#19 - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 243 = main.component#5.namevalue#1.#19 - Tags : GOT_NAMEVALUE - Epsilon closure : - (self) - -NFA state 244 = main.component#5.namevalue#1.out_continue - [(epsilon)] -> component#5.namevalue#1.out - [(epsilon)] -> component#5.namevalue#1.#20 - Epsilon closure : - (self) - main.#5 - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 245 = main.component#5.namevalue#1.#20 - Tags : GOT_NAMEVALUE_CONT - Epsilon closure : - (self) - -NFA state 246 = main.component#5.namevalue#1.out - [(epsilon)] -> component#5.out - Epsilon closure : - (self) - main.#5 - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 247 = main.component#5.name#2.in - 6:[\055] -> component#5.name#2.name1 - 11:[A-Z_a-z] -> component#5.name#2.name1 - 8:[0-9] -> component#5.name#2.name1 - Epsilon closure : - (self) - -NFA state 248 = main.component#5.name#2.name1 - [(epsilon)] -> component#5.name#2.out - 0:[\t ] -> component#5.name#2.name2 - 6:[\055] -> component#5.name#2.name1 - 11:[A-Z_a-z] -> component#5.name#2.name1 - 8:[0-9] -> component#5.name#2.name1 - [(epsilon)] -> component#5.name#2.#2 - [(epsilon)] -> component#5.name#2.#1 - Epsilon closure : - (self) - main.#5 - main.component#5.name#2.#1 - main.component#5.name#2.#2 - main.component#5.name#2.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 249 = main.component#5.name#2.#1 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 250 = main.component#5.name#2.#2 - Tags : GOT_NAME - Epsilon closure : - (self) - -NFA state 251 = main.component#5.name#2.name2 - [(epsilon)] -> component#5.name#2.out - 6:[\055] -> component#5.name#2.name1 - 11:[A-Z_a-z] -> component#5.name#2.name1 - 8:[0-9] -> component#5.name#2.name1 - 0:[\t ] -> component#5.name#2.name2 - [(epsilon)] -> component#5.name#2.#4 - [(epsilon)] -> component#5.name#2.#3 - Epsilon closure : - (self) - main.#5 - main.component#5.name#2.#3 - main.component#5.name#2.#4 - main.component#5.name#2.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 252 = main.component#5.name#2.#3 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 253 = main.component#5.name#2.#4 - Tags : GOT_NAME_TRAILING_SPACE - Epsilon closure : - (self) - -NFA state 254 = main.component#5.name#2.out - [(epsilon)] -> component#5.out - Epsilon closure : - (self) - main.#5 - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 255 = main.component#5.majorminor#3.in - [(epsilon)] -> component#5.majorminor#3.major#1.in - Epsilon closure : - (self) - main.component#5.majorminor#3.major#1.in - -NFA state 256 = main.component#5.majorminor#3.major#1.in - 6:[\055] -> component#5.majorminor#3.major#1.name1 - 11:[A-Z_a-z] -> component#5.majorminor#3.major#1.name1 - 8:[0-9] -> component#5.majorminor#3.major#1.name1 - Epsilon closure : - (self) - -NFA state 257 = main.component#5.majorminor#3.major#1.name1 - 6:[\055] -> component#5.majorminor#3.major#1.name1 - 11:[A-Z_a-z] -> component#5.majorminor#3.major#1.name1 - 8:[0-9] -> component#5.majorminor#3.major#1.name1 - [(epsilon)] -> component#5.majorminor#3.major#1.out - Epsilon closure : - (self) - main.component#5.majorminor#3.major#1.out - main.component#5.majorminor#3.foo - -NFA state 258 = main.component#5.majorminor#3.major#1.out - [(epsilon)] -> component#5.majorminor#3.foo - Epsilon closure : - (self) - main.component#5.majorminor#3.foo - -NFA state 259 = main.component#5.majorminor#3.foo - 7:[/] -> component#5.majorminor#3.bar - Epsilon closure : - (self) - -NFA state 260 = main.component#5.majorminor#3.bar - [(epsilon)] -> component#5.majorminor#3.minor#2.in - Epsilon closure : - (self) - main.component#5.majorminor#3.minor#2.in - -NFA state 261 = main.component#5.majorminor#3.minor#2.in - 5:[+.] -> component#5.majorminor#3.minor#2.minor1 - 12:[\\] -> component#5.majorminor#3.minor#2.minor1 - 6:[\055] -> component#5.majorminor#3.minor#2.minor1 - 6:[\055] -> component#5.majorminor#3.minor#2.minor1 - 11:[A-Z_a-z] -> component#5.majorminor#3.minor#2.minor1 - 8:[0-9] -> component#5.majorminor#3.minor#2.minor1 - Epsilon closure : - (self) - -NFA state 262 = main.component#5.majorminor#3.minor#2.minor1 - [(epsilon)] -> component#5.majorminor#3.minor#2.#1 - 5:[+.] -> component#5.majorminor#3.minor#2.minor1 - 12:[\\] -> component#5.majorminor#3.minor#2.minor1 - 6:[\055] -> component#5.majorminor#3.minor#2.minor1 - 6:[\055] -> component#5.majorminor#3.minor#2.minor1 - 11:[A-Z_a-z] -> component#5.majorminor#3.minor#2.minor1 - 8:[0-9] -> component#5.majorminor#3.minor#2.minor1 - [(epsilon)] -> component#5.majorminor#3.minor#2.out - Epsilon closure : - (self) - main.#5 - main.component#5.majorminor#3.minor#2.#1 - main.component#5.majorminor#3.minor#2.out - main.component#5.majorminor#3.out - main.component#5.majorminor#3.#1 - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 263 = main.component#5.majorminor#3.minor#2.#1 - Tags : COPY_TO_MINOR - Epsilon closure : - (self) - -NFA state 264 = main.component#5.majorminor#3.minor#2.out - [(epsilon)] -> component#5.majorminor#3.out - Epsilon closure : - (self) - main.#5 - main.component#5.majorminor#3.out - main.component#5.majorminor#3.#1 - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 265 = main.component#5.majorminor#3.out - [(epsilon)] -> component#5.majorminor#3.#1 - [(epsilon)] -> component#5.out - Epsilon closure : - (self) - main.#5 - main.component#5.majorminor#3.#1 - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 266 = main.component#5.majorminor#3.#1 - Tags : GOT_MAJORMINOR - Epsilon closure : - (self) - -NFA state 267 = main.component#5.out - [(epsilon)] -> #5 - Epsilon closure : - (self) - main.#5 - main.#6 - main.optwhite#6.in - main.optwhite#6.out - -NFA state 268 = main.#6 - 9:[;] -> #7 - Epsilon closure : - (self) - -NFA state 269 = main.optwhite#6.in - [(epsilon)] -> optwhite#6.out - 0:[\t ] -> optwhite#6.in - 1:[\r] -> optwhite#6.in - Epsilon closure : - (self) - main.#6 - main.optwhite#6.out - -NFA state 270 = main.optwhite#6.out - [(epsilon)] -> #6 - Epsilon closure : - (self) - main.#6 - -NFA state 271 = main.#7 - [(epsilon)] -> optwhite#7.in - Epsilon closure : - (self) - main.#8 - main.optwhite#7.in - main.optwhite#7.out - -NFA state 272 = main.#8 - EOS -> out2 - Epsilon closure : - (self) - -NFA state 273 = main.optwhite#7.in - [(epsilon)] -> optwhite#7.out - 0:[\t ] -> optwhite#7.in - 1:[\r] -> optwhite#7.in - Epsilon closure : - (self) - main.#8 - main.optwhite#7.out - -NFA state 274 = main.optwhite#7.out - [(epsilon)] -> #8 - Epsilon closure : - (self) - main.#8 - -NFA state 275 = main.#9 - [(epsilon)] -> component#9.in - Epsilon closure : - (self) - main.component#9.in - main.component#9.namevalue#1.in - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.in - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.in - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - main.component#9.name#2.in - main.component#9.majorminor#3.in - main.component#9.majorminor#3.major#1.in - -NFA state 276 = main.optwhite#8.in - [(epsilon)] -> optwhite#8.out - 0:[\t ] -> optwhite#8.in - 1:[\r] -> optwhite#8.in - Epsilon closure : - (self) - main.#9 - main.optwhite#8.out - main.component#9.in - main.component#9.namevalue#1.in - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.in - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.in - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - main.component#9.name#2.in - main.component#9.majorminor#3.in - main.component#9.majorminor#3.major#1.in - -NFA state 277 = main.optwhite#8.out - [(epsilon)] -> #9 - Epsilon closure : - (self) - main.#9 - main.component#9.in - main.component#9.namevalue#1.in - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.in - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.in - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - main.component#9.name#2.in - main.component#9.majorminor#3.in - main.component#9.majorminor#3.major#1.in - -NFA state 278 = main.#10 - [(epsilon)] -> optwhite#10.in - Epsilon closure : - (self) - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 279 = main.component#9.in - [(epsilon)] -> component#9.namevalue#1.in - [(epsilon)] -> component#9.name#2.in - [(epsilon)] -> component#9.majorminor#3.in - Epsilon closure : - (self) - main.component#9.namevalue#1.in - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.in - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.in - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - main.component#9.name#2.in - main.component#9.majorminor#3.in - main.component#9.majorminor#3.major#1.in - -NFA state 280 = main.component#9.namevalue#1.in - [(epsilon)] -> component#9.namevalue#1.optwhite#4.in - [(epsilon)] -> component#9.namevalue#1.optwhite#1.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.in - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.in - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - -NFA state 281 = main.component#9.namevalue#1.#1 - [(epsilon)] -> component#9.namevalue#1.name#2.in - Epsilon closure : - (self) - main.component#9.namevalue#1.name#2.in - -NFA state 282 = main.component#9.namevalue#1.optwhite#1.in - [(epsilon)] -> component#9.namevalue#1.optwhite#1.out - 0:[\t ] -> component#9.namevalue#1.optwhite#1.in - 1:[\r] -> component#9.namevalue#1.optwhite#1.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - -NFA state 283 = main.component#9.namevalue#1.optwhite#1.out - [(epsilon)] -> component#9.namevalue#1.#1 - Epsilon closure : - (self) - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.name#2.in - -NFA state 284 = main.component#9.namevalue#1.#2 - [(epsilon)] -> component#9.namevalue#1.optwhite#3.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#3 - main.component#9.namevalue#1.optwhite#3.in - main.component#9.namevalue#1.optwhite#3.out - -NFA state 285 = main.component#9.namevalue#1.name#2.in - 6:[\055] -> component#9.namevalue#1.name#2.name1 - 11:[A-Z_a-z] -> component#9.namevalue#1.name#2.name1 - 8:[0-9] -> component#9.namevalue#1.name#2.name1 - Epsilon closure : - (self) - -NFA state 286 = main.component#9.namevalue#1.name#2.name1 - [(epsilon)] -> component#9.namevalue#1.name#2.#1 - [(epsilon)] -> component#9.namevalue#1.name#2.#2 - 6:[\055] -> component#9.namevalue#1.name#2.name1 - 11:[A-Z_a-z] -> component#9.namevalue#1.name#2.name1 - 8:[0-9] -> component#9.namevalue#1.name#2.name1 - 0:[\t ] -> component#9.namevalue#1.name#2.name2 - [(epsilon)] -> component#9.namevalue#1.name#2.out - Epsilon closure : - (self) - main.component#9.namevalue#1.#2 - main.component#9.namevalue#1.name#2.#1 - main.component#9.namevalue#1.name#2.#2 - main.component#9.namevalue#1.name#2.out - main.component#9.namevalue#1.#3 - main.component#9.namevalue#1.optwhite#3.in - main.component#9.namevalue#1.optwhite#3.out - -NFA state 287 = main.component#9.namevalue#1.name#2.#1 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 288 = main.component#9.namevalue#1.name#2.#2 - Tags : GOT_NAME - Epsilon closure : - (self) - -NFA state 289 = main.component#9.namevalue#1.name#2.name2 - [(epsilon)] -> component#9.namevalue#1.name#2.#3 - [(epsilon)] -> component#9.namevalue#1.name#2.#4 - 0:[\t ] -> component#9.namevalue#1.name#2.name2 - 6:[\055] -> component#9.namevalue#1.name#2.name1 - 11:[A-Z_a-z] -> component#9.namevalue#1.name#2.name1 - 8:[0-9] -> component#9.namevalue#1.name#2.name1 - [(epsilon)] -> component#9.namevalue#1.name#2.out - Epsilon closure : - (self) - main.component#9.namevalue#1.#2 - main.component#9.namevalue#1.name#2.#3 - main.component#9.namevalue#1.name#2.#4 - main.component#9.namevalue#1.name#2.out - main.component#9.namevalue#1.#3 - main.component#9.namevalue#1.optwhite#3.in - main.component#9.namevalue#1.optwhite#3.out - -NFA state 290 = main.component#9.namevalue#1.name#2.#3 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 291 = main.component#9.namevalue#1.name#2.#4 - Tags : GOT_NAME_TRAILING_SPACE - Epsilon closure : - (self) - -NFA state 292 = main.component#9.namevalue#1.name#2.out - [(epsilon)] -> component#9.namevalue#1.#2 - Epsilon closure : - (self) - main.component#9.namevalue#1.#2 - main.component#9.namevalue#1.#3 - main.component#9.namevalue#1.optwhite#3.in - main.component#9.namevalue#1.optwhite#3.out - -NFA state 293 = main.component#9.namevalue#1.#3 - 10:[=] -> component#9.namevalue#1.rhs_normal - Epsilon closure : - (self) - -NFA state 294 = main.component#9.namevalue#1.optwhite#3.in - [(epsilon)] -> component#9.namevalue#1.optwhite#3.out - 0:[\t ] -> component#9.namevalue#1.optwhite#3.in - 1:[\r] -> component#9.namevalue#1.optwhite#3.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#3 - main.component#9.namevalue#1.optwhite#3.out - -NFA state 295 = main.component#9.namevalue#1.optwhite#3.out - [(epsilon)] -> component#9.namevalue#1.#3 - Epsilon closure : - (self) - main.component#9.namevalue#1.#3 - -NFA state 296 = main.component#9.namevalue#1.#4 - [(epsilon)] -> component#9.namevalue#1.name#5.in - Epsilon closure : - (self) - main.component#9.namevalue#1.name#5.in - -NFA state 297 = main.component#9.namevalue#1.optwhite#4.in - [(epsilon)] -> component#9.namevalue#1.optwhite#4.out - 0:[\t ] -> component#9.namevalue#1.optwhite#4.in - 1:[\r] -> component#9.namevalue#1.optwhite#4.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - -NFA state 298 = main.component#9.namevalue#1.optwhite#4.out - [(epsilon)] -> component#9.namevalue#1.#4 - Epsilon closure : - (self) - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.name#5.in - -NFA state 299 = main.component#9.namevalue#1.#5 - 4:[*] -> component#9.namevalue#1.#6 - Epsilon closure : - (self) - -NFA state 300 = main.component#9.namevalue#1.name#5.in - 6:[\055] -> component#9.namevalue#1.name#5.name1 - 11:[A-Z_a-z] -> component#9.namevalue#1.name#5.name1 - 8:[0-9] -> component#9.namevalue#1.name#5.name1 - Epsilon closure : - (self) - -NFA state 301 = main.component#9.namevalue#1.name#5.name1 - [(epsilon)] -> component#9.namevalue#1.name#5.#1 - [(epsilon)] -> component#9.namevalue#1.name#5.#2 - 6:[\055] -> component#9.namevalue#1.name#5.name1 - 11:[A-Z_a-z] -> component#9.namevalue#1.name#5.name1 - 8:[0-9] -> component#9.namevalue#1.name#5.name1 - 0:[\t ] -> component#9.namevalue#1.name#5.name2 - [(epsilon)] -> component#9.namevalue#1.name#5.out - Epsilon closure : - (self) - main.component#9.namevalue#1.#5 - main.component#9.namevalue#1.name#5.#1 - main.component#9.namevalue#1.name#5.#2 - main.component#9.namevalue#1.name#5.out - -NFA state 302 = main.component#9.namevalue#1.name#5.#1 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 303 = main.component#9.namevalue#1.name#5.#2 - Tags : GOT_NAME - Epsilon closure : - (self) - -NFA state 304 = main.component#9.namevalue#1.name#5.name2 - [(epsilon)] -> component#9.namevalue#1.name#5.#3 - [(epsilon)] -> component#9.namevalue#1.name#5.#4 - 0:[\t ] -> component#9.namevalue#1.name#5.name2 - 6:[\055] -> component#9.namevalue#1.name#5.name1 - 11:[A-Z_a-z] -> component#9.namevalue#1.name#5.name1 - 8:[0-9] -> component#9.namevalue#1.name#5.name1 - [(epsilon)] -> component#9.namevalue#1.name#5.out - Epsilon closure : - (self) - main.component#9.namevalue#1.#5 - main.component#9.namevalue#1.name#5.#3 - main.component#9.namevalue#1.name#5.#4 - main.component#9.namevalue#1.name#5.out - -NFA state 305 = main.component#9.namevalue#1.name#5.#3 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 306 = main.component#9.namevalue#1.name#5.#4 - Tags : GOT_NAME_TRAILING_SPACE - Epsilon closure : - (self) - -NFA state 307 = main.component#9.namevalue#1.name#5.out - [(epsilon)] -> component#9.namevalue#1.#5 - Epsilon closure : - (self) - main.component#9.namevalue#1.#5 - -NFA state 308 = main.component#9.namevalue#1.#6 - [(epsilon)] -> component#9.namevalue#1.digits#6.in - Epsilon closure : - (self) - main.component#9.namevalue#1.digits#6.in - -NFA state 309 = main.component#9.namevalue#1.#7 - [(epsilon)] -> component#9.namevalue#1.optwhite#7.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#8 - main.component#9.namevalue#1.optwhite#7.in - main.component#9.namevalue#1.optwhite#7.out - -NFA state 310 = main.component#9.namevalue#1.digits#6.in - 8:[0-9] -> component#9.namevalue#1.digits#6.out - 8:[0-9] -> component#9.namevalue#1.digits#6.in - Epsilon closure : - (self) - -NFA state 311 = main.component#9.namevalue#1.digits#6.out - [(epsilon)] -> component#9.namevalue#1.#7 - Epsilon closure : - (self) - main.component#9.namevalue#1.#7 - main.component#9.namevalue#1.#8 - main.component#9.namevalue#1.optwhite#7.in - main.component#9.namevalue#1.optwhite#7.out - -NFA state 312 = main.component#9.namevalue#1.#8 - 10:[=] -> component#9.namevalue#1.rhs_continue - Epsilon closure : - (self) - -NFA state 313 = main.component#9.namevalue#1.optwhite#7.in - [(epsilon)] -> component#9.namevalue#1.optwhite#7.out - 0:[\t ] -> component#9.namevalue#1.optwhite#7.in - 1:[\r] -> component#9.namevalue#1.optwhite#7.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#8 - main.component#9.namevalue#1.optwhite#7.out - -NFA state 314 = main.component#9.namevalue#1.optwhite#7.out - [(epsilon)] -> component#9.namevalue#1.#8 - Epsilon closure : - (self) - main.component#9.namevalue#1.#8 - -NFA state 315 = main.component#9.namevalue#1.rhs_normal - [(epsilon)] -> component#9.namevalue#1.optwhite#14.in - [(epsilon)] -> component#9.namevalue#1.optwhite#11.in - [(epsilon)] -> component#9.namevalue#1.optwhite#8.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#9 - main.component#9.namevalue#1.optwhite#8.in - main.component#9.namevalue#1.optwhite#8.out - main.component#9.namevalue#1.qvalue#9.in - main.component#9.namevalue#1.#11 - main.component#9.namevalue#1.optwhite#11.in - main.component#9.namevalue#1.optwhite#11.out - main.component#9.namevalue#1.value#12.in - main.component#9.namevalue#1.#13 - main.component#9.namevalue#1.optwhite#14.in - main.component#9.namevalue#1.optwhite#14.out - main.component#9.namevalue#1.#14 - -NFA state 316 = main.component#9.namevalue#1.#9 - [(epsilon)] -> component#9.namevalue#1.qvalue#9.in - Epsilon closure : - (self) - main.component#9.namevalue#1.qvalue#9.in - -NFA state 317 = main.component#9.namevalue#1.optwhite#8.in - [(epsilon)] -> component#9.namevalue#1.optwhite#8.out - 0:[\t ] -> component#9.namevalue#1.optwhite#8.in - 1:[\r] -> component#9.namevalue#1.optwhite#8.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#9 - main.component#9.namevalue#1.optwhite#8.out - main.component#9.namevalue#1.qvalue#9.in - -NFA state 318 = main.component#9.namevalue#1.optwhite#8.out - [(epsilon)] -> component#9.namevalue#1.#9 - Epsilon closure : - (self) - main.component#9.namevalue#1.#9 - main.component#9.namevalue#1.qvalue#9.in - -NFA state 319 = main.component#9.namevalue#1.#10 - [(epsilon)] -> component#9.namevalue#1.optwhite#10.in - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.optwhite#10.in - main.component#9.namevalue#1.optwhite#10.out - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 320 = main.component#9.namevalue#1.qvalue#9.in - 3:["] -> component#9.namevalue#1.qvalue#9.qv0 - Epsilon closure : - (self) - -NFA state 321 = main.component#9.namevalue#1.qvalue#9.qv0 - [(epsilon)] -> component#9.namevalue#1.qvalue#9.escape#1.in - 0:[\t ] -> component#9.namevalue#1.qvalue#9.qv1 - 9:[;] -> component#9.namevalue#1.qvalue#9.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#9.namevalue#1.qvalue#9.qv1 - 11:[A-Z_a-z] -> component#9.namevalue#1.qvalue#9.qv1 - 10:[=] -> component#9.namevalue#1.qvalue#9.qv1 - 8:[0-9] -> component#9.namevalue#1.qvalue#9.qv1 - 7:[/] -> component#9.namevalue#1.qvalue#9.qv1 - 6:[\055] -> component#9.namevalue#1.qvalue#9.qv1 - 5:[+.] -> component#9.namevalue#1.qvalue#9.qv1 - 4:[*] -> component#9.namevalue#1.qvalue#9.qv1 - Epsilon closure : - (self) - main.component#9.namevalue#1.qvalue#9.escape#1.in - -NFA state 322 = main.component#9.namevalue#1.qvalue#9.escape#1.in - 12:[\\] -> component#9.namevalue#1.qvalue#9.escape#1.#2 - 12:[\\] -> component#9.namevalue#1.qvalue#9.escape#1.#1 - Epsilon closure : - (self) - -NFA state 323 = main.component#9.namevalue#1.qvalue#9.escape#1.#1 - 12:[\\] -> component#9.namevalue#1.qvalue#9.escape#1.out - Epsilon closure : - (self) - -NFA state 324 = main.component#9.namevalue#1.qvalue#9.escape#1.#2 - 3:["] -> component#9.namevalue#1.qvalue#9.escape#1.out - Epsilon closure : - (self) - -NFA state 325 = main.component#9.namevalue#1.qvalue#9.escape#1.out - [(epsilon)] -> component#9.namevalue#1.qvalue#9.qv1 - Epsilon closure : - (self) - main.component#9.namevalue#1.qvalue#9.qv1 - main.component#9.namevalue#1.qvalue#9.#1 - main.component#9.namevalue#1.qvalue#9.escape#2.in - main.component#9.namevalue#1.qvalue#9.qv2 - -NFA state 326 = main.component#9.namevalue#1.qvalue#9.qv1 - [(epsilon)] -> component#9.namevalue#1.qvalue#9.#1 - [(epsilon)] -> component#9.namevalue#1.qvalue#9.escape#2.in - 0:[\t ] -> component#9.namevalue#1.qvalue#9.qv1 - 9:[;] -> component#9.namevalue#1.qvalue#9.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#9.namevalue#1.qvalue#9.qv1 - 11:[A-Z_a-z] -> component#9.namevalue#1.qvalue#9.qv1 - 10:[=] -> component#9.namevalue#1.qvalue#9.qv1 - 8:[0-9] -> component#9.namevalue#1.qvalue#9.qv1 - 7:[/] -> component#9.namevalue#1.qvalue#9.qv1 - 6:[\055] -> component#9.namevalue#1.qvalue#9.qv1 - 5:[+.] -> component#9.namevalue#1.qvalue#9.qv1 - 4:[*] -> component#9.namevalue#1.qvalue#9.qv1 - [(epsilon)] -> component#9.namevalue#1.qvalue#9.qv2 - Epsilon closure : - (self) - main.component#9.namevalue#1.qvalue#9.#1 - main.component#9.namevalue#1.qvalue#9.escape#2.in - main.component#9.namevalue#1.qvalue#9.qv2 - -NFA state 327 = main.component#9.namevalue#1.qvalue#9.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 328 = main.component#9.namevalue#1.qvalue#9.escape#2.in - 12:[\\] -> component#9.namevalue#1.qvalue#9.escape#2.#2 - 12:[\\] -> component#9.namevalue#1.qvalue#9.escape#2.#1 - Epsilon closure : - (self) - -NFA state 329 = main.component#9.namevalue#1.qvalue#9.escape#2.#1 - 12:[\\] -> component#9.namevalue#1.qvalue#9.escape#2.out - Epsilon closure : - (self) - -NFA state 330 = main.component#9.namevalue#1.qvalue#9.escape#2.#2 - 3:["] -> component#9.namevalue#1.qvalue#9.escape#2.out - Epsilon closure : - (self) - -NFA state 331 = main.component#9.namevalue#1.qvalue#9.escape#2.out - [(epsilon)] -> component#9.namevalue#1.qvalue#9.qv1 - Epsilon closure : - (self) - main.component#9.namevalue#1.qvalue#9.qv1 - main.component#9.namevalue#1.qvalue#9.#1 - main.component#9.namevalue#1.qvalue#9.escape#2.in - main.component#9.namevalue#1.qvalue#9.qv2 - -NFA state 332 = main.component#9.namevalue#1.qvalue#9.qv2 - 3:["] -> component#9.namevalue#1.qvalue#9.out - Epsilon closure : - (self) - -NFA state 333 = main.component#9.namevalue#1.qvalue#9.out - [(epsilon)] -> component#9.namevalue#1.#10 - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.#10 - main.component#9.namevalue#1.optwhite#10.in - main.component#9.namevalue#1.optwhite#10.out - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 334 = main.component#9.namevalue#1.optwhite#10.in - [(epsilon)] -> component#9.namevalue#1.optwhite#10.out - 0:[\t ] -> component#9.namevalue#1.optwhite#10.in - 1:[\r] -> component#9.namevalue#1.optwhite#10.in - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.optwhite#10.out - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 335 = main.component#9.namevalue#1.optwhite#10.out - [(epsilon)] -> component#9.namevalue#1.out_normal - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 336 = main.component#9.namevalue#1.#11 - [(epsilon)] -> component#9.namevalue#1.value#12.in - Epsilon closure : - (self) - main.component#9.namevalue#1.value#12.in - -NFA state 337 = main.component#9.namevalue#1.optwhite#11.in - [(epsilon)] -> component#9.namevalue#1.optwhite#11.out - 0:[\t ] -> component#9.namevalue#1.optwhite#11.in - 1:[\r] -> component#9.namevalue#1.optwhite#11.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#11 - main.component#9.namevalue#1.optwhite#11.out - main.component#9.namevalue#1.value#12.in - -NFA state 338 = main.component#9.namevalue#1.optwhite#11.out - [(epsilon)] -> component#9.namevalue#1.#11 - Epsilon closure : - (self) - main.component#9.namevalue#1.#11 - main.component#9.namevalue#1.value#12.in - -NFA state 339 = main.component#9.namevalue#1.#12 - [(epsilon)] -> component#9.namevalue#1.optwhite#13.in - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.optwhite#13.in - main.component#9.namevalue#1.optwhite#13.out - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 340 = main.component#9.namevalue#1.value#12.in - 2:[!#-),:<>-@[]^`{-~] -> component#9.namevalue#1.value#12.v1 - 11:[A-Z_a-z] -> component#9.namevalue#1.value#12.v1 - 10:[=] -> component#9.namevalue#1.value#12.v1 - 8:[0-9] -> component#9.namevalue#1.value#12.v1 - 7:[/] -> component#9.namevalue#1.value#12.v1 - 6:[\055] -> component#9.namevalue#1.value#12.v1 - 5:[+.] -> component#9.namevalue#1.value#12.v1 - 4:[*] -> component#9.namevalue#1.value#12.v1 - Epsilon closure : - (self) - -NFA state 341 = main.component#9.namevalue#1.value#12.v1 - [(epsilon)] -> component#9.namevalue#1.value#12.#1 - [(epsilon)] -> component#9.namevalue#1.value#12.out - 2:[!#-),:<>-@[]^`{-~] -> component#9.namevalue#1.value#12.v1 - 11:[A-Z_a-z] -> component#9.namevalue#1.value#12.v1 - 10:[=] -> component#9.namevalue#1.value#12.v1 - 8:[0-9] -> component#9.namevalue#1.value#12.v1 - 7:[/] -> component#9.namevalue#1.value#12.v1 - 6:[\055] -> component#9.namevalue#1.value#12.v1 - 5:[+.] -> component#9.namevalue#1.value#12.v1 - 4:[*] -> component#9.namevalue#1.value#12.v1 - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.#12 - main.component#9.namevalue#1.value#12.#1 - main.component#9.namevalue#1.value#12.out - main.component#9.namevalue#1.optwhite#13.in - main.component#9.namevalue#1.optwhite#13.out - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 342 = main.component#9.namevalue#1.value#12.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 343 = main.component#9.namevalue#1.value#12.out - [(epsilon)] -> component#9.namevalue#1.#12 - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.#12 - main.component#9.namevalue#1.optwhite#13.in - main.component#9.namevalue#1.optwhite#13.out - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 344 = main.component#9.namevalue#1.optwhite#13.in - [(epsilon)] -> component#9.namevalue#1.optwhite#13.out - 0:[\t ] -> component#9.namevalue#1.optwhite#13.in - 1:[\r] -> component#9.namevalue#1.optwhite#13.in - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.optwhite#13.out - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 345 = main.component#9.namevalue#1.optwhite#13.out - [(epsilon)] -> component#9.namevalue#1.out_normal - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 346 = main.component#9.namevalue#1.#13 - [(epsilon)] -> component#9.namevalue#1.#14 - Epsilon closure : - (self) - main.component#9.namevalue#1.#14 - -NFA state 347 = main.component#9.namevalue#1.optwhite#14.in - [(epsilon)] -> component#9.namevalue#1.optwhite#14.out - 0:[\t ] -> component#9.namevalue#1.optwhite#14.in - 1:[\r] -> component#9.namevalue#1.optwhite#14.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#13 - main.component#9.namevalue#1.optwhite#14.out - main.component#9.namevalue#1.#14 - -NFA state 348 = main.component#9.namevalue#1.optwhite#14.out - [(epsilon)] -> component#9.namevalue#1.#13 - Epsilon closure : - (self) - main.component#9.namevalue#1.#13 - main.component#9.namevalue#1.#14 - -NFA state 349 = main.component#9.namevalue#1.#14 - EOS -> component#9.namevalue#1.out_normal - Epsilon closure : - (self) - -NFA state 350 = main.component#9.namevalue#1.rhs_continue - [(epsilon)] -> component#9.namevalue#1.optwhite#18.in - [(epsilon)] -> component#9.namevalue#1.optwhite#15.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#15 - main.component#9.namevalue#1.optwhite#15.in - main.component#9.namevalue#1.optwhite#15.out - main.component#9.namevalue#1.qvalue#16.in - main.component#9.namevalue#1.#17 - main.component#9.namevalue#1.optwhite#18.in - main.component#9.namevalue#1.optwhite#18.out - main.component#9.namevalue#1.value#19.in - -NFA state 351 = main.component#9.namevalue#1.#15 - [(epsilon)] -> component#9.namevalue#1.qvalue#16.in - Epsilon closure : - (self) - main.component#9.namevalue#1.qvalue#16.in - -NFA state 352 = main.component#9.namevalue#1.optwhite#15.in - [(epsilon)] -> component#9.namevalue#1.optwhite#15.out - 0:[\t ] -> component#9.namevalue#1.optwhite#15.in - 1:[\r] -> component#9.namevalue#1.optwhite#15.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#15 - main.component#9.namevalue#1.optwhite#15.out - main.component#9.namevalue#1.qvalue#16.in - -NFA state 353 = main.component#9.namevalue#1.optwhite#15.out - [(epsilon)] -> component#9.namevalue#1.#15 - Epsilon closure : - (self) - main.component#9.namevalue#1.#15 - main.component#9.namevalue#1.qvalue#16.in - -NFA state 354 = main.component#9.namevalue#1.#16 - [(epsilon)] -> component#9.namevalue#1.optwhite#17.in - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.optwhite#17.in - main.component#9.namevalue#1.optwhite#17.out - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 355 = main.component#9.namevalue#1.qvalue#16.in - 3:["] -> component#9.namevalue#1.qvalue#16.qv0 - Epsilon closure : - (self) - -NFA state 356 = main.component#9.namevalue#1.qvalue#16.qv0 - [(epsilon)] -> component#9.namevalue#1.qvalue#16.escape#1.in - 0:[\t ] -> component#9.namevalue#1.qvalue#16.qv1 - 9:[;] -> component#9.namevalue#1.qvalue#16.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#9.namevalue#1.qvalue#16.qv1 - 11:[A-Z_a-z] -> component#9.namevalue#1.qvalue#16.qv1 - 10:[=] -> component#9.namevalue#1.qvalue#16.qv1 - 8:[0-9] -> component#9.namevalue#1.qvalue#16.qv1 - 7:[/] -> component#9.namevalue#1.qvalue#16.qv1 - 6:[\055] -> component#9.namevalue#1.qvalue#16.qv1 - 5:[+.] -> component#9.namevalue#1.qvalue#16.qv1 - 4:[*] -> component#9.namevalue#1.qvalue#16.qv1 - Epsilon closure : - (self) - main.component#9.namevalue#1.qvalue#16.escape#1.in - -NFA state 357 = main.component#9.namevalue#1.qvalue#16.escape#1.in - 12:[\\] -> component#9.namevalue#1.qvalue#16.escape#1.#2 - 12:[\\] -> component#9.namevalue#1.qvalue#16.escape#1.#1 - Epsilon closure : - (self) - -NFA state 358 = main.component#9.namevalue#1.qvalue#16.escape#1.#1 - 12:[\\] -> component#9.namevalue#1.qvalue#16.escape#1.out - Epsilon closure : - (self) - -NFA state 359 = main.component#9.namevalue#1.qvalue#16.escape#1.#2 - 3:["] -> component#9.namevalue#1.qvalue#16.escape#1.out - Epsilon closure : - (self) - -NFA state 360 = main.component#9.namevalue#1.qvalue#16.escape#1.out - [(epsilon)] -> component#9.namevalue#1.qvalue#16.qv1 - Epsilon closure : - (self) - main.component#9.namevalue#1.qvalue#16.qv1 - main.component#9.namevalue#1.qvalue#16.#1 - main.component#9.namevalue#1.qvalue#16.escape#2.in - main.component#9.namevalue#1.qvalue#16.qv2 - -NFA state 361 = main.component#9.namevalue#1.qvalue#16.qv1 - [(epsilon)] -> component#9.namevalue#1.qvalue#16.#1 - [(epsilon)] -> component#9.namevalue#1.qvalue#16.escape#2.in - 0:[\t ] -> component#9.namevalue#1.qvalue#16.qv1 - 9:[;] -> component#9.namevalue#1.qvalue#16.qv1 - 2:[!#-),:<>-@[]^`{-~] -> component#9.namevalue#1.qvalue#16.qv1 - 11:[A-Z_a-z] -> component#9.namevalue#1.qvalue#16.qv1 - 10:[=] -> component#9.namevalue#1.qvalue#16.qv1 - 8:[0-9] -> component#9.namevalue#1.qvalue#16.qv1 - 7:[/] -> component#9.namevalue#1.qvalue#16.qv1 - 6:[\055] -> component#9.namevalue#1.qvalue#16.qv1 - 5:[+.] -> component#9.namevalue#1.qvalue#16.qv1 - 4:[*] -> component#9.namevalue#1.qvalue#16.qv1 - [(epsilon)] -> component#9.namevalue#1.qvalue#16.qv2 - Epsilon closure : - (self) - main.component#9.namevalue#1.qvalue#16.#1 - main.component#9.namevalue#1.qvalue#16.escape#2.in - main.component#9.namevalue#1.qvalue#16.qv2 - -NFA state 362 = main.component#9.namevalue#1.qvalue#16.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 363 = main.component#9.namevalue#1.qvalue#16.escape#2.in - 12:[\\] -> component#9.namevalue#1.qvalue#16.escape#2.#2 - 12:[\\] -> component#9.namevalue#1.qvalue#16.escape#2.#1 - Epsilon closure : - (self) - -NFA state 364 = main.component#9.namevalue#1.qvalue#16.escape#2.#1 - 12:[\\] -> component#9.namevalue#1.qvalue#16.escape#2.out - Epsilon closure : - (self) - -NFA state 365 = main.component#9.namevalue#1.qvalue#16.escape#2.#2 - 3:["] -> component#9.namevalue#1.qvalue#16.escape#2.out - Epsilon closure : - (self) - -NFA state 366 = main.component#9.namevalue#1.qvalue#16.escape#2.out - [(epsilon)] -> component#9.namevalue#1.qvalue#16.qv1 - Epsilon closure : - (self) - main.component#9.namevalue#1.qvalue#16.qv1 - main.component#9.namevalue#1.qvalue#16.#1 - main.component#9.namevalue#1.qvalue#16.escape#2.in - main.component#9.namevalue#1.qvalue#16.qv2 - -NFA state 367 = main.component#9.namevalue#1.qvalue#16.qv2 - 3:["] -> component#9.namevalue#1.qvalue#16.out - Epsilon closure : - (self) - -NFA state 368 = main.component#9.namevalue#1.qvalue#16.out - [(epsilon)] -> component#9.namevalue#1.#16 - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.#16 - main.component#9.namevalue#1.optwhite#17.in - main.component#9.namevalue#1.optwhite#17.out - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 369 = main.component#9.namevalue#1.optwhite#17.in - [(epsilon)] -> component#9.namevalue#1.optwhite#17.out - 0:[\t ] -> component#9.namevalue#1.optwhite#17.in - 1:[\r] -> component#9.namevalue#1.optwhite#17.in - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.optwhite#17.out - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 370 = main.component#9.namevalue#1.optwhite#17.out - [(epsilon)] -> component#9.namevalue#1.out_continue - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 371 = main.component#9.namevalue#1.#17 - [(epsilon)] -> component#9.namevalue#1.value#19.in - Epsilon closure : - (self) - main.component#9.namevalue#1.value#19.in - -NFA state 372 = main.component#9.namevalue#1.optwhite#18.in - [(epsilon)] -> component#9.namevalue#1.optwhite#18.out - 0:[\t ] -> component#9.namevalue#1.optwhite#18.in - 1:[\r] -> component#9.namevalue#1.optwhite#18.in - Epsilon closure : - (self) - main.component#9.namevalue#1.#17 - main.component#9.namevalue#1.optwhite#18.out - main.component#9.namevalue#1.value#19.in - -NFA state 373 = main.component#9.namevalue#1.optwhite#18.out - [(epsilon)] -> component#9.namevalue#1.#17 - Epsilon closure : - (self) - main.component#9.namevalue#1.#17 - main.component#9.namevalue#1.value#19.in - -NFA state 374 = main.component#9.namevalue#1.#18 - [(epsilon)] -> component#9.namevalue#1.optwhite#20.in - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.optwhite#20.in - main.component#9.namevalue#1.optwhite#20.out - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 375 = main.component#9.namevalue#1.value#19.in - 2:[!#-),:<>-@[]^`{-~] -> component#9.namevalue#1.value#19.v1 - 11:[A-Z_a-z] -> component#9.namevalue#1.value#19.v1 - 10:[=] -> component#9.namevalue#1.value#19.v1 - 8:[0-9] -> component#9.namevalue#1.value#19.v1 - 7:[/] -> component#9.namevalue#1.value#19.v1 - 6:[\055] -> component#9.namevalue#1.value#19.v1 - 5:[+.] -> component#9.namevalue#1.value#19.v1 - 4:[*] -> component#9.namevalue#1.value#19.v1 - Epsilon closure : - (self) - -NFA state 376 = main.component#9.namevalue#1.value#19.v1 - [(epsilon)] -> component#9.namevalue#1.value#19.#1 - [(epsilon)] -> component#9.namevalue#1.value#19.out - 2:[!#-),:<>-@[]^`{-~] -> component#9.namevalue#1.value#19.v1 - 11:[A-Z_a-z] -> component#9.namevalue#1.value#19.v1 - 10:[=] -> component#9.namevalue#1.value#19.v1 - 8:[0-9] -> component#9.namevalue#1.value#19.v1 - 7:[/] -> component#9.namevalue#1.value#19.v1 - 6:[\055] -> component#9.namevalue#1.value#19.v1 - 5:[+.] -> component#9.namevalue#1.value#19.v1 - 4:[*] -> component#9.namevalue#1.value#19.v1 - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.#18 - main.component#9.namevalue#1.value#19.#1 - main.component#9.namevalue#1.value#19.out - main.component#9.namevalue#1.optwhite#20.in - main.component#9.namevalue#1.optwhite#20.out - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 377 = main.component#9.namevalue#1.value#19.#1 - Tags : COPY_TO_VALUE - Epsilon closure : - (self) - -NFA state 378 = main.component#9.namevalue#1.value#19.out - [(epsilon)] -> component#9.namevalue#1.#18 - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.#18 - main.component#9.namevalue#1.optwhite#20.in - main.component#9.namevalue#1.optwhite#20.out - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 379 = main.component#9.namevalue#1.optwhite#20.in - [(epsilon)] -> component#9.namevalue#1.optwhite#20.out - 0:[\t ] -> component#9.namevalue#1.optwhite#20.in - 1:[\r] -> component#9.namevalue#1.optwhite#20.in - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.optwhite#20.out - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 380 = main.component#9.namevalue#1.optwhite#20.out - [(epsilon)] -> component#9.namevalue#1.out_continue - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 381 = main.component#9.namevalue#1.out_normal - [(epsilon)] -> component#9.namevalue#1.out - [(epsilon)] -> component#9.namevalue#1.#19 - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 382 = main.component#9.namevalue#1.#19 - Tags : GOT_NAMEVALUE - Epsilon closure : - (self) - -NFA state 383 = main.component#9.namevalue#1.out_continue - [(epsilon)] -> component#9.namevalue#1.out - [(epsilon)] -> component#9.namevalue#1.#20 - Epsilon closure : - (self) - main.#10 - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 384 = main.component#9.namevalue#1.#20 - Tags : GOT_NAMEVALUE_CONT - Epsilon closure : - (self) - -NFA state 385 = main.component#9.namevalue#1.out - [(epsilon)] -> component#9.out - Epsilon closure : - (self) - main.#10 - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 386 = main.component#9.name#2.in - 6:[\055] -> component#9.name#2.name1 - 11:[A-Z_a-z] -> component#9.name#2.name1 - 8:[0-9] -> component#9.name#2.name1 - Epsilon closure : - (self) - -NFA state 387 = main.component#9.name#2.name1 - [(epsilon)] -> component#9.name#2.out - 0:[\t ] -> component#9.name#2.name2 - 6:[\055] -> component#9.name#2.name1 - 11:[A-Z_a-z] -> component#9.name#2.name1 - 8:[0-9] -> component#9.name#2.name1 - [(epsilon)] -> component#9.name#2.#2 - [(epsilon)] -> component#9.name#2.#1 - Epsilon closure : - (self) - main.#10 - main.component#9.name#2.#1 - main.component#9.name#2.#2 - main.component#9.name#2.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 388 = main.component#9.name#2.#1 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 389 = main.component#9.name#2.#2 - Tags : GOT_NAME - Epsilon closure : - (self) - -NFA state 390 = main.component#9.name#2.name2 - [(epsilon)] -> component#9.name#2.out - 6:[\055] -> component#9.name#2.name1 - 11:[A-Z_a-z] -> component#9.name#2.name1 - 8:[0-9] -> component#9.name#2.name1 - 0:[\t ] -> component#9.name#2.name2 - [(epsilon)] -> component#9.name#2.#4 - [(epsilon)] -> component#9.name#2.#3 - Epsilon closure : - (self) - main.#10 - main.component#9.name#2.#3 - main.component#9.name#2.#4 - main.component#9.name#2.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 391 = main.component#9.name#2.#3 - Tags : COPY_TO_NAME - Epsilon closure : - (self) - -NFA state 392 = main.component#9.name#2.#4 - Tags : GOT_NAME_TRAILING_SPACE - Epsilon closure : - (self) - -NFA state 393 = main.component#9.name#2.out - [(epsilon)] -> component#9.out - Epsilon closure : - (self) - main.#10 - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 394 = main.component#9.majorminor#3.in - [(epsilon)] -> component#9.majorminor#3.major#1.in - Epsilon closure : - (self) - main.component#9.majorminor#3.major#1.in - -NFA state 395 = main.component#9.majorminor#3.major#1.in - 6:[\055] -> component#9.majorminor#3.major#1.name1 - 11:[A-Z_a-z] -> component#9.majorminor#3.major#1.name1 - 8:[0-9] -> component#9.majorminor#3.major#1.name1 - Epsilon closure : - (self) - -NFA state 396 = main.component#9.majorminor#3.major#1.name1 - 6:[\055] -> component#9.majorminor#3.major#1.name1 - 11:[A-Z_a-z] -> component#9.majorminor#3.major#1.name1 - 8:[0-9] -> component#9.majorminor#3.major#1.name1 - [(epsilon)] -> component#9.majorminor#3.major#1.out - Epsilon closure : - (self) - main.component#9.majorminor#3.major#1.out - main.component#9.majorminor#3.foo - -NFA state 397 = main.component#9.majorminor#3.major#1.out - [(epsilon)] -> component#9.majorminor#3.foo - Epsilon closure : - (self) - main.component#9.majorminor#3.foo - -NFA state 398 = main.component#9.majorminor#3.foo - 7:[/] -> component#9.majorminor#3.bar - Epsilon closure : - (self) - -NFA state 399 = main.component#9.majorminor#3.bar - [(epsilon)] -> component#9.majorminor#3.minor#2.in - Epsilon closure : - (self) - main.component#9.majorminor#3.minor#2.in - -NFA state 400 = main.component#9.majorminor#3.minor#2.in - 5:[+.] -> component#9.majorminor#3.minor#2.minor1 - 12:[\\] -> component#9.majorminor#3.minor#2.minor1 - 6:[\055] -> component#9.majorminor#3.minor#2.minor1 - 6:[\055] -> component#9.majorminor#3.minor#2.minor1 - 11:[A-Z_a-z] -> component#9.majorminor#3.minor#2.minor1 - 8:[0-9] -> component#9.majorminor#3.minor#2.minor1 - Epsilon closure : - (self) - -NFA state 401 = main.component#9.majorminor#3.minor#2.minor1 - [(epsilon)] -> component#9.majorminor#3.minor#2.#1 - 5:[+.] -> component#9.majorminor#3.minor#2.minor1 - 12:[\\] -> component#9.majorminor#3.minor#2.minor1 - 6:[\055] -> component#9.majorminor#3.minor#2.minor1 - 6:[\055] -> component#9.majorminor#3.minor#2.minor1 - 11:[A-Z_a-z] -> component#9.majorminor#3.minor#2.minor1 - 8:[0-9] -> component#9.majorminor#3.minor#2.minor1 - [(epsilon)] -> component#9.majorminor#3.minor#2.out - Epsilon closure : - (self) - main.#10 - main.component#9.majorminor#3.minor#2.#1 - main.component#9.majorminor#3.minor#2.out - main.component#9.majorminor#3.out - main.component#9.majorminor#3.#1 - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 402 = main.component#9.majorminor#3.minor#2.#1 - Tags : COPY_TO_MINOR - Epsilon closure : - (self) - -NFA state 403 = main.component#9.majorminor#3.minor#2.out - [(epsilon)] -> component#9.majorminor#3.out - Epsilon closure : - (self) - main.#10 - main.component#9.majorminor#3.out - main.component#9.majorminor#3.#1 - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 404 = main.component#9.majorminor#3.out - [(epsilon)] -> component#9.majorminor#3.#1 - [(epsilon)] -> component#9.out - Epsilon closure : - (self) - main.#10 - main.component#9.majorminor#3.#1 - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 405 = main.component#9.majorminor#3.#1 - Tags : GOT_MAJORMINOR - Epsilon closure : - (self) - -NFA state 406 = main.component#9.out - [(epsilon)] -> #10 - Epsilon closure : - (self) - main.#10 - main.#11 - main.optwhite#10.in - main.optwhite#10.out - -NFA state 407 = main.#11 - 9:[;] -> in2 - Epsilon closure : - (self) - -NFA state 408 = main.optwhite#10.in - [(epsilon)] -> optwhite#10.out - 0:[\t ] -> optwhite#10.in - 1:[\r] -> optwhite#10.in - Epsilon closure : - (self) - main.#11 - main.optwhite#10.out - -NFA state 409 = main.optwhite#10.out - [(epsilon)] -> #11 - Epsilon closure : - (self) - main.#11 - -NFA state 410 = main.in2 - [(epsilon)] -> in - [(epsilon)] -> #12 - Epsilon closure : - (self) - main.in - main.#1 - main.optwhite#1.in - main.optwhite#1.out - main.component#2.in - main.component#2.namevalue#1.in - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.in - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.in - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - main.component#2.name#2.in - main.component#2.majorminor#3.in - main.component#2.majorminor#3.major#1.in - main.#4 - main.optwhite#4.in - main.optwhite#4.out - main.component#5.in - main.component#5.namevalue#1.in - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.in - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.in - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - main.component#5.name#2.in - main.component#5.majorminor#3.in - main.component#5.majorminor#3.major#1.in - main.#9 - main.optwhite#8.in - main.optwhite#8.out - main.component#9.in - main.component#9.namevalue#1.in - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.in - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.in - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - main.component#9.name#2.in - main.component#9.majorminor#3.in - main.component#9.majorminor#3.major#1.in - main.#12 - -NFA state 411 = main.#12 - Tags : GOT_TERMINATOR - Epsilon closure : - (self) - -NFA state 412 = main.out2 - [(epsilon)] -> out - [(epsilon)] -> #13 - Epsilon closure : - (self) - main.#13 - main.out - -NFA state 413 = main.#13 - Tags : GOT_TERMINATOR - Epsilon closure : - (self) - -NFA state 414 = main.out - Epsilon closure : - (self) - --------------------------------- -DFA structure before compression --------------------------------- -DFA state 0 - NFA states : - main.in - main.#1 - main.optwhite#1.in - main.optwhite#1.out - main.component#2.in - main.component#2.namevalue#1.in - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.in - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.in - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - main.component#2.name#2.in - main.component#2.majorminor#3.in - main.component#2.majorminor#3.major#1.in - main.#4 - main.optwhite#4.in - main.optwhite#4.out - main.component#5.in - main.component#5.namevalue#1.in - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.in - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.in - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - main.component#5.name#2.in - main.component#5.majorminor#3.in - main.component#5.majorminor#3.major#1.in - main.#9 - main.optwhite#8.in - main.optwhite#8.out - main.component#9.in - main.component#9.namevalue#1.in - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.in - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.in - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - main.component#9.name#2.in - main.component#9.majorminor#3.in - main.component#9.majorminor#3.major#1.in - - Forward route : - (START)->(HERE) - Transitions : - 0:[\t ] -> 1 - 1:[\r] -> 1 - 6:[\055] -> 2 - 8:[0-9] -> 2 - 11:[A-Z_a-z] -> 2 - -DFA state 1 - NFA states : - main.#1 - main.optwhite#1.in - main.optwhite#1.out - main.component#2.in - main.component#2.namevalue#1.in - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.in - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.in - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - main.component#2.name#2.in - main.component#2.majorminor#3.in - main.component#2.majorminor#3.major#1.in - main.#4 - main.optwhite#4.in - main.optwhite#4.out - main.component#5.in - main.component#5.namevalue#1.in - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.in - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.in - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - main.component#5.name#2.in - main.component#5.majorminor#3.in - main.component#5.majorminor#3.major#1.in - main.#9 - main.optwhite#8.in - main.optwhite#8.out - main.component#9.in - main.component#9.namevalue#1.in - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.in - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.in - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - main.component#9.name#2.in - main.component#9.majorminor#3.in - main.component#9.majorminor#3.major#1.in - - Forward route : (from state 0) - (START)->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 1 - 1:[\r] -> 1 - 6:[\055] -> 2 - 8:[0-9] -> 2 - 11:[A-Z_a-z] -> 2 - -DFA state 2 - NFA states : - main.#2 - main.component#2.namevalue#1.#2 - main.component#2.namevalue#1.name#2.name1 - main.component#2.namevalue#1.name#2.#1 - main.component#2.namevalue#1.name#2.#2 - main.component#2.namevalue#1.name#2.out - main.component#2.namevalue#1.#3 - main.component#2.namevalue#1.optwhite#3.in - main.component#2.namevalue#1.optwhite#3.out - main.component#2.namevalue#1.#5 - main.component#2.namevalue#1.name#5.name1 - main.component#2.namevalue#1.name#5.#1 - main.component#2.namevalue#1.name#5.#2 - main.component#2.namevalue#1.name#5.out - main.component#2.name#2.name1 - main.component#2.name#2.#1 - main.component#2.name#2.#2 - main.component#2.name#2.out - main.component#2.majorminor#3.major#1.name1 - main.component#2.majorminor#3.major#1.out - main.component#2.majorminor#3.foo - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.#2 - main.component#5.namevalue#1.name#2.name1 - main.component#5.namevalue#1.name#2.#1 - main.component#5.namevalue#1.name#2.#2 - main.component#5.namevalue#1.name#2.out - main.component#5.namevalue#1.#3 - main.component#5.namevalue#1.optwhite#3.in - main.component#5.namevalue#1.optwhite#3.out - main.component#5.namevalue#1.#5 - main.component#5.namevalue#1.name#5.name1 - main.component#5.namevalue#1.name#5.#1 - main.component#5.namevalue#1.name#5.#2 - main.component#5.namevalue#1.name#5.out - main.component#5.name#2.name1 - main.component#5.name#2.#1 - main.component#5.name#2.#2 - main.component#5.name#2.out - main.component#5.majorminor#3.major#1.name1 - main.component#5.majorminor#3.major#1.out - main.component#5.majorminor#3.foo - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.#2 - main.component#9.namevalue#1.name#2.name1 - main.component#9.namevalue#1.name#2.#1 - main.component#9.namevalue#1.name#2.#2 - main.component#9.namevalue#1.name#2.out - main.component#9.namevalue#1.#3 - main.component#9.namevalue#1.optwhite#3.in - main.component#9.namevalue#1.optwhite#3.out - main.component#9.namevalue#1.#5 - main.component#9.namevalue#1.name#5.name1 - main.component#9.namevalue#1.name#5.#1 - main.component#9.namevalue#1.name#5.#2 - main.component#9.namevalue#1.name#5.out - main.component#9.name#2.name1 - main.component#9.name#2.#1 - main.component#9.name#2.#2 - main.component#9.name#2.out - main.component#9.majorminor#3.major#1.name1 - main.component#9.majorminor#3.major#1.out - main.component#9.majorminor#3.foo - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 0) - (START)->6:[\055]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 4 - 1:[\r] -> 5 - 4:[*] -> 6 - 6:[\055] -> 2 - 7:[/] -> 7 - 8:[0-9] -> 2 - 9:[;] -> 8 - 10:[=] -> 9 - 11:[A-Z_a-z] -> 2 - NFA exit tags applying : - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - Attributes for <copier> : COPY_TO_NAME - Attributes for <action> : GOT_NAME - -DFA state 3 - NFA states : - main.out2 - main.#13 - main.out - - Forward route : (from state 2) - (START)->6:[\055]->EOS->(HERE) - Transitions : - NFA exit tags applying : - GOT_TERMINATOR - Attributes for <action> : GOT_TERMINATOR - -DFA state 4 - NFA states : - main.#2 - main.component#2.namevalue#1.#2 - main.component#2.namevalue#1.name#2.name2 - main.component#2.namevalue#1.name#2.#3 - main.component#2.namevalue#1.name#2.#4 - main.component#2.namevalue#1.name#2.out - main.component#2.namevalue#1.#3 - main.component#2.namevalue#1.optwhite#3.in - main.component#2.namevalue#1.optwhite#3.out - main.component#2.namevalue#1.#5 - main.component#2.namevalue#1.name#5.name2 - main.component#2.namevalue#1.name#5.#3 - main.component#2.namevalue#1.name#5.#4 - main.component#2.namevalue#1.name#5.out - main.component#2.name#2.name2 - main.component#2.name#2.#3 - main.component#2.name#2.#4 - main.component#2.name#2.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.#2 - main.component#5.namevalue#1.name#2.name2 - main.component#5.namevalue#1.name#2.#3 - main.component#5.namevalue#1.name#2.#4 - main.component#5.namevalue#1.name#2.out - main.component#5.namevalue#1.#3 - main.component#5.namevalue#1.optwhite#3.in - main.component#5.namevalue#1.optwhite#3.out - main.component#5.namevalue#1.#5 - main.component#5.namevalue#1.name#5.name2 - main.component#5.namevalue#1.name#5.#3 - main.component#5.namevalue#1.name#5.#4 - main.component#5.namevalue#1.name#5.out - main.component#5.name#2.name2 - main.component#5.name#2.#3 - main.component#5.name#2.#4 - main.component#5.name#2.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.#2 - main.component#9.namevalue#1.name#2.name2 - main.component#9.namevalue#1.name#2.#3 - main.component#9.namevalue#1.name#2.#4 - main.component#9.namevalue#1.name#2.out - main.component#9.namevalue#1.#3 - main.component#9.namevalue#1.optwhite#3.in - main.component#9.namevalue#1.optwhite#3.out - main.component#9.namevalue#1.#5 - main.component#9.namevalue#1.name#5.name2 - main.component#9.namevalue#1.name#5.#3 - main.component#9.namevalue#1.name#5.#4 - main.component#9.namevalue#1.name#5.out - main.component#9.name#2.name2 - main.component#9.name#2.#3 - main.component#9.name#2.#4 - main.component#9.name#2.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 2) - (START)->6:[\055]->0:[\t ]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 4 - 1:[\r] -> 5 - 4:[*] -> 6 - 6:[\055] -> 10 - 8:[0-9] -> 10 - 9:[;] -> 8 - 10:[=] -> 9 - 11:[A-Z_a-z] -> 10 - NFA exit tags applying : - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - Attributes for <copier> : COPY_TO_NAME - Attributes for <action> : GOT_NAME_TRAILING_SPACE - -DFA state 5 - NFA states : - main.component#2.namevalue#1.#3 - main.component#2.namevalue#1.optwhite#3.in - main.component#2.namevalue#1.optwhite#3.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.component#5.namevalue#1.#3 - main.component#5.namevalue#1.optwhite#3.in - main.component#5.namevalue#1.optwhite#3.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.component#9.namevalue#1.#3 - main.component#9.namevalue#1.optwhite#3.in - main.component#9.namevalue#1.optwhite#3.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 2) - (START)->6:[\055]->1:[\r]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 5 - 1:[\r] -> 5 - 9:[;] -> 8 - 10:[=] -> 9 - -DFA state 6 - NFA states : - main.component#2.namevalue#1.#6 - main.component#2.namevalue#1.digits#6.in - main.component#5.namevalue#1.#6 - main.component#5.namevalue#1.digits#6.in - main.component#9.namevalue#1.#6 - main.component#9.namevalue#1.digits#6.in - - Forward route : (from state 2) - (START)->6:[\055]->4:[*]->(HERE) - Transitions : - 8:[0-9] -> 11 - -DFA state 7 - NFA states : - main.component#2.majorminor#3.bar - main.component#2.majorminor#3.minor#2.in - main.component#5.majorminor#3.bar - main.component#5.majorminor#3.minor#2.in - main.component#9.majorminor#3.bar - main.component#9.majorminor#3.minor#2.in - - Forward route : (from state 2) - (START)->6:[\055]->7:[/]->(HERE) - Transitions : - 5:[+.] -> 12 - 6:[\055] -> 12 - 8:[0-9] -> 12 - 11:[A-Z_a-z] -> 12 - 12:[\\] -> 12 - -DFA state 8 - NFA states : - main.in - main.#1 - main.optwhite#1.in - main.optwhite#1.out - main.component#2.in - main.component#2.namevalue#1.in - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.in - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.in - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - main.component#2.name#2.in - main.component#2.majorminor#3.in - main.component#2.majorminor#3.major#1.in - main.#4 - main.optwhite#4.in - main.optwhite#4.out - main.component#5.in - main.component#5.namevalue#1.in - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.in - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.in - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - main.component#5.name#2.in - main.component#5.majorminor#3.in - main.component#5.majorminor#3.major#1.in - main.#7 - main.#8 - main.optwhite#7.in - main.optwhite#7.out - main.#9 - main.optwhite#8.in - main.optwhite#8.out - main.component#9.in - main.component#9.namevalue#1.in - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.in - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.in - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - main.component#9.name#2.in - main.component#9.majorminor#3.in - main.component#9.majorminor#3.major#1.in - main.in2 - main.#12 - - Forward route : (from state 2) - (START)->6:[\055]->9:[;]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 13 - 1:[\r] -> 13 - 6:[\055] -> 2 - 8:[0-9] -> 2 - 11:[A-Z_a-z] -> 2 - NFA exit tags applying : - GOT_TERMINATOR - Attributes for <action> : GOT_TERMINATOR - -DFA state 9 - NFA states : - main.component#2.namevalue#1.rhs_normal - main.component#2.namevalue#1.#9 - main.component#2.namevalue#1.optwhite#8.in - main.component#2.namevalue#1.optwhite#8.out - main.component#2.namevalue#1.qvalue#9.in - main.component#2.namevalue#1.#11 - main.component#2.namevalue#1.optwhite#11.in - main.component#2.namevalue#1.optwhite#11.out - main.component#2.namevalue#1.value#12.in - main.component#2.namevalue#1.#13 - main.component#2.namevalue#1.optwhite#14.in - main.component#2.namevalue#1.optwhite#14.out - main.component#2.namevalue#1.#14 - main.component#5.namevalue#1.rhs_normal - main.component#5.namevalue#1.#9 - main.component#5.namevalue#1.optwhite#8.in - main.component#5.namevalue#1.optwhite#8.out - main.component#5.namevalue#1.qvalue#9.in - main.component#5.namevalue#1.#11 - main.component#5.namevalue#1.optwhite#11.in - main.component#5.namevalue#1.optwhite#11.out - main.component#5.namevalue#1.value#12.in - main.component#5.namevalue#1.#13 - main.component#5.namevalue#1.optwhite#14.in - main.component#5.namevalue#1.optwhite#14.out - main.component#5.namevalue#1.#14 - main.component#9.namevalue#1.rhs_normal - main.component#9.namevalue#1.#9 - main.component#9.namevalue#1.optwhite#8.in - main.component#9.namevalue#1.optwhite#8.out - main.component#9.namevalue#1.qvalue#9.in - main.component#9.namevalue#1.#11 - main.component#9.namevalue#1.optwhite#11.in - main.component#9.namevalue#1.optwhite#11.out - main.component#9.namevalue#1.value#12.in - main.component#9.namevalue#1.#13 - main.component#9.namevalue#1.optwhite#14.in - main.component#9.namevalue#1.optwhite#14.out - main.component#9.namevalue#1.#14 - - Forward route : (from state 2) - (START)->6:[\055]->10:[=]->(HERE) - Transitions : - EOS -> 14 - 0:[\t ] -> 15 - 1:[\r] -> 15 - 2:[!#-),:<>-@[]^`{-~] -> 16 - 3:["] -> 17 - 4:[*] -> 16 - 5:[+.] -> 16 - 6:[\055] -> 16 - 7:[/] -> 16 - 8:[0-9] -> 16 - 10:[=] -> 16 - 11:[A-Z_a-z] -> 16 - -DFA state 10 - NFA states : - main.#2 - main.component#2.namevalue#1.#2 - main.component#2.namevalue#1.name#2.name1 - main.component#2.namevalue#1.name#2.#1 - main.component#2.namevalue#1.name#2.#2 - main.component#2.namevalue#1.name#2.out - main.component#2.namevalue#1.#3 - main.component#2.namevalue#1.optwhite#3.in - main.component#2.namevalue#1.optwhite#3.out - main.component#2.namevalue#1.#5 - main.component#2.namevalue#1.name#5.name1 - main.component#2.namevalue#1.name#5.#1 - main.component#2.namevalue#1.name#5.#2 - main.component#2.namevalue#1.name#5.out - main.component#2.name#2.name1 - main.component#2.name#2.#1 - main.component#2.name#2.#2 - main.component#2.name#2.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.#2 - main.component#5.namevalue#1.name#2.name1 - main.component#5.namevalue#1.name#2.#1 - main.component#5.namevalue#1.name#2.#2 - main.component#5.namevalue#1.name#2.out - main.component#5.namevalue#1.#3 - main.component#5.namevalue#1.optwhite#3.in - main.component#5.namevalue#1.optwhite#3.out - main.component#5.namevalue#1.#5 - main.component#5.namevalue#1.name#5.name1 - main.component#5.namevalue#1.name#5.#1 - main.component#5.namevalue#1.name#5.#2 - main.component#5.namevalue#1.name#5.out - main.component#5.name#2.name1 - main.component#5.name#2.#1 - main.component#5.name#2.#2 - main.component#5.name#2.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.#2 - main.component#9.namevalue#1.name#2.name1 - main.component#9.namevalue#1.name#2.#1 - main.component#9.namevalue#1.name#2.#2 - main.component#9.namevalue#1.name#2.out - main.component#9.namevalue#1.#3 - main.component#9.namevalue#1.optwhite#3.in - main.component#9.namevalue#1.optwhite#3.out - main.component#9.namevalue#1.#5 - main.component#9.namevalue#1.name#5.name1 - main.component#9.namevalue#1.name#5.#1 - main.component#9.namevalue#1.name#5.#2 - main.component#9.namevalue#1.name#5.out - main.component#9.name#2.name1 - main.component#9.name#2.#1 - main.component#9.name#2.#2 - main.component#9.name#2.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 4) - (START)->6:[\055]->0:[\t ]->6:[\055]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 4 - 1:[\r] -> 5 - 4:[*] -> 6 - 6:[\055] -> 10 - 8:[0-9] -> 10 - 9:[;] -> 8 - 10:[=] -> 9 - 11:[A-Z_a-z] -> 10 - NFA exit tags applying : - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - Attributes for <copier> : COPY_TO_NAME - Attributes for <action> : GOT_NAME - -DFA state 11 - NFA states : - main.component#2.namevalue#1.#7 - main.component#2.namevalue#1.digits#6.in - main.component#2.namevalue#1.digits#6.out - main.component#2.namevalue#1.#8 - main.component#2.namevalue#1.optwhite#7.in - main.component#2.namevalue#1.optwhite#7.out - main.component#5.namevalue#1.#7 - main.component#5.namevalue#1.digits#6.in - main.component#5.namevalue#1.digits#6.out - main.component#5.namevalue#1.#8 - main.component#5.namevalue#1.optwhite#7.in - main.component#5.namevalue#1.optwhite#7.out - main.component#9.namevalue#1.#7 - main.component#9.namevalue#1.digits#6.in - main.component#9.namevalue#1.digits#6.out - main.component#9.namevalue#1.#8 - main.component#9.namevalue#1.optwhite#7.in - main.component#9.namevalue#1.optwhite#7.out - - Forward route : (from state 6) - (START)->6:[\055]->4:[*]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 18 - 1:[\r] -> 18 - 8:[0-9] -> 11 - 10:[=] -> 19 - -DFA state 12 - NFA states : - main.#2 - main.component#2.majorminor#3.minor#2.minor1 - main.component#2.majorminor#3.minor#2.#1 - main.component#2.majorminor#3.minor#2.out - main.component#2.majorminor#3.out - main.component#2.majorminor#3.#1 - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.majorminor#3.minor#2.minor1 - main.component#5.majorminor#3.minor#2.#1 - main.component#5.majorminor#3.minor#2.out - main.component#5.majorminor#3.out - main.component#5.majorminor#3.#1 - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.majorminor#3.minor#2.minor1 - main.component#9.majorminor#3.minor#2.#1 - main.component#9.majorminor#3.minor#2.out - main.component#9.majorminor#3.out - main.component#9.majorminor#3.#1 - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 7) - (START)->6:[\055]->7:[/]->5:[+.]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 20 - 1:[\r] -> 20 - 5:[+.] -> 12 - 6:[\055] -> 12 - 8:[0-9] -> 12 - 9:[;] -> 8 - 11:[A-Z_a-z] -> 12 - 12:[\\] -> 12 - NFA exit tags applying : - GOT_MAJORMINOR - COPY_TO_MINOR - GOT_MAJORMINOR - COPY_TO_MINOR - GOT_MAJORMINOR - COPY_TO_MINOR - Attributes for <copier> : COPY_TO_MINOR - Attributes for <action> : GOT_MAJORMINOR - -DFA state 13 - NFA states : - main.#1 - main.optwhite#1.in - main.optwhite#1.out - main.component#2.in - main.component#2.namevalue#1.in - main.component#2.namevalue#1.#1 - main.component#2.namevalue#1.optwhite#1.in - main.component#2.namevalue#1.optwhite#1.out - main.component#2.namevalue#1.name#2.in - main.component#2.namevalue#1.#4 - main.component#2.namevalue#1.optwhite#4.in - main.component#2.namevalue#1.optwhite#4.out - main.component#2.namevalue#1.name#5.in - main.component#2.name#2.in - main.component#2.majorminor#3.in - main.component#2.majorminor#3.major#1.in - main.#4 - main.optwhite#4.in - main.optwhite#4.out - main.component#5.in - main.component#5.namevalue#1.in - main.component#5.namevalue#1.#1 - main.component#5.namevalue#1.optwhite#1.in - main.component#5.namevalue#1.optwhite#1.out - main.component#5.namevalue#1.name#2.in - main.component#5.namevalue#1.#4 - main.component#5.namevalue#1.optwhite#4.in - main.component#5.namevalue#1.optwhite#4.out - main.component#5.namevalue#1.name#5.in - main.component#5.name#2.in - main.component#5.majorminor#3.in - main.component#5.majorminor#3.major#1.in - main.#8 - main.optwhite#7.in - main.optwhite#7.out - main.#9 - main.optwhite#8.in - main.optwhite#8.out - main.component#9.in - main.component#9.namevalue#1.in - main.component#9.namevalue#1.#1 - main.component#9.namevalue#1.optwhite#1.in - main.component#9.namevalue#1.optwhite#1.out - main.component#9.namevalue#1.name#2.in - main.component#9.namevalue#1.#4 - main.component#9.namevalue#1.optwhite#4.in - main.component#9.namevalue#1.optwhite#4.out - main.component#9.namevalue#1.name#5.in - main.component#9.name#2.in - main.component#9.majorminor#3.in - main.component#9.majorminor#3.major#1.in - - Forward route : (from state 8) - (START)->6:[\055]->9:[;]->0:[\t ]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 13 - 1:[\r] -> 13 - 6:[\055] -> 2 - 8:[0-9] -> 2 - 11:[A-Z_a-z] -> 2 - -DFA state 14 - NFA states : - main.#2 - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 9) - (START)->6:[\055]->10:[=]->EOS->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 20 - 1:[\r] -> 20 - 9:[;] -> 8 - NFA exit tags applying : - GOT_NAMEVALUE - GOT_NAMEVALUE - GOT_NAMEVALUE - Attributes for <action> : GOT_NAMEVALUE - -DFA state 15 - NFA states : - main.component#2.namevalue#1.#9 - main.component#2.namevalue#1.optwhite#8.in - main.component#2.namevalue#1.optwhite#8.out - main.component#2.namevalue#1.qvalue#9.in - main.component#2.namevalue#1.#11 - main.component#2.namevalue#1.optwhite#11.in - main.component#2.namevalue#1.optwhite#11.out - main.component#2.namevalue#1.value#12.in - main.component#2.namevalue#1.#13 - main.component#2.namevalue#1.optwhite#14.in - main.component#2.namevalue#1.optwhite#14.out - main.component#2.namevalue#1.#14 - main.component#5.namevalue#1.#9 - main.component#5.namevalue#1.optwhite#8.in - main.component#5.namevalue#1.optwhite#8.out - main.component#5.namevalue#1.qvalue#9.in - main.component#5.namevalue#1.#11 - main.component#5.namevalue#1.optwhite#11.in - main.component#5.namevalue#1.optwhite#11.out - main.component#5.namevalue#1.value#12.in - main.component#5.namevalue#1.#13 - main.component#5.namevalue#1.optwhite#14.in - main.component#5.namevalue#1.optwhite#14.out - main.component#5.namevalue#1.#14 - main.component#9.namevalue#1.#9 - main.component#9.namevalue#1.optwhite#8.in - main.component#9.namevalue#1.optwhite#8.out - main.component#9.namevalue#1.qvalue#9.in - main.component#9.namevalue#1.#11 - main.component#9.namevalue#1.optwhite#11.in - main.component#9.namevalue#1.optwhite#11.out - main.component#9.namevalue#1.value#12.in - main.component#9.namevalue#1.#13 - main.component#9.namevalue#1.optwhite#14.in - main.component#9.namevalue#1.optwhite#14.out - main.component#9.namevalue#1.#14 - - Forward route : (from state 9) - (START)->6:[\055]->10:[=]->0:[\t ]->(HERE) - Transitions : - EOS -> 14 - 0:[\t ] -> 15 - 1:[\r] -> 15 - 2:[!#-),:<>-@[]^`{-~] -> 16 - 3:["] -> 17 - 4:[*] -> 16 - 5:[+.] -> 16 - 6:[\055] -> 16 - 7:[/] -> 16 - 8:[0-9] -> 16 - 10:[=] -> 16 - 11:[A-Z_a-z] -> 16 - -DFA state 16 - NFA states : - main.#2 - main.component#2.namevalue#1.#12 - main.component#2.namevalue#1.value#12.v1 - main.component#2.namevalue#1.value#12.#1 - main.component#2.namevalue#1.value#12.out - main.component#2.namevalue#1.optwhite#13.in - main.component#2.namevalue#1.optwhite#13.out - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.#12 - main.component#5.namevalue#1.value#12.v1 - main.component#5.namevalue#1.value#12.#1 - main.component#5.namevalue#1.value#12.out - main.component#5.namevalue#1.optwhite#13.in - main.component#5.namevalue#1.optwhite#13.out - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.#12 - main.component#9.namevalue#1.value#12.v1 - main.component#9.namevalue#1.value#12.#1 - main.component#9.namevalue#1.value#12.out - main.component#9.namevalue#1.optwhite#13.in - main.component#9.namevalue#1.optwhite#13.out - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 9) - (START)->6:[\055]->10:[=]->2:[!#-),:<>-@[]^`{-~]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 21 - 1:[\r] -> 21 - 2:[!#-),:<>-@[]^`{-~] -> 16 - 4:[*] -> 16 - 5:[+.] -> 16 - 6:[\055] -> 16 - 7:[/] -> 16 - 8:[0-9] -> 16 - 9:[;] -> 8 - 10:[=] -> 16 - 11:[A-Z_a-z] -> 16 - NFA exit tags applying : - GOT_NAMEVALUE - COPY_TO_VALUE - GOT_NAMEVALUE - COPY_TO_VALUE - GOT_NAMEVALUE - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - Attributes for <action> : GOT_NAMEVALUE - -DFA state 17 - NFA states : - main.component#2.namevalue#1.qvalue#9.qv0 - main.component#2.namevalue#1.qvalue#9.escape#1.in - main.component#5.namevalue#1.qvalue#9.qv0 - main.component#5.namevalue#1.qvalue#9.escape#1.in - main.component#9.namevalue#1.qvalue#9.qv0 - main.component#9.namevalue#1.qvalue#9.escape#1.in - - Forward route : (from state 9) - (START)->6:[\055]->10:[=]->3:["]->(HERE) - Transitions : - 0:[\t ] -> 22 - 2:[!#-),:<>-@[]^`{-~] -> 22 - 4:[*] -> 22 - 5:[+.] -> 22 - 6:[\055] -> 22 - 7:[/] -> 22 - 8:[0-9] -> 22 - 9:[;] -> 22 - 10:[=] -> 22 - 11:[A-Z_a-z] -> 22 - 12:[\\] -> 23 - -DFA state 18 - NFA states : - main.component#2.namevalue#1.#8 - main.component#2.namevalue#1.optwhite#7.in - main.component#2.namevalue#1.optwhite#7.out - main.component#5.namevalue#1.#8 - main.component#5.namevalue#1.optwhite#7.in - main.component#5.namevalue#1.optwhite#7.out - main.component#9.namevalue#1.#8 - main.component#9.namevalue#1.optwhite#7.in - main.component#9.namevalue#1.optwhite#7.out - - Forward route : (from state 11) - (START)->6:[\055]->4:[*]->8:[0-9]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 18 - 1:[\r] -> 18 - 10:[=] -> 19 - -DFA state 19 - NFA states : - main.component#2.namevalue#1.rhs_continue - main.component#2.namevalue#1.#15 - main.component#2.namevalue#1.optwhite#15.in - main.component#2.namevalue#1.optwhite#15.out - main.component#2.namevalue#1.qvalue#16.in - main.component#2.namevalue#1.#17 - main.component#2.namevalue#1.optwhite#18.in - main.component#2.namevalue#1.optwhite#18.out - main.component#2.namevalue#1.value#19.in - main.component#5.namevalue#1.rhs_continue - main.component#5.namevalue#1.#15 - main.component#5.namevalue#1.optwhite#15.in - main.component#5.namevalue#1.optwhite#15.out - main.component#5.namevalue#1.qvalue#16.in - main.component#5.namevalue#1.#17 - main.component#5.namevalue#1.optwhite#18.in - main.component#5.namevalue#1.optwhite#18.out - main.component#5.namevalue#1.value#19.in - main.component#9.namevalue#1.rhs_continue - main.component#9.namevalue#1.#15 - main.component#9.namevalue#1.optwhite#15.in - main.component#9.namevalue#1.optwhite#15.out - main.component#9.namevalue#1.qvalue#16.in - main.component#9.namevalue#1.#17 - main.component#9.namevalue#1.optwhite#18.in - main.component#9.namevalue#1.optwhite#18.out - main.component#9.namevalue#1.value#19.in - - Forward route : (from state 11) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->(HERE) - Transitions : - 0:[\t ] -> 24 - 1:[\r] -> 24 - 2:[!#-),:<>-@[]^`{-~] -> 25 - 3:["] -> 26 - 4:[*] -> 25 - 5:[+.] -> 25 - 6:[\055] -> 25 - 7:[/] -> 25 - 8:[0-9] -> 25 - 10:[=] -> 25 - 11:[A-Z_a-z] -> 25 - -DFA state 20 - NFA states : - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 12) - (START)->6:[\055]->7:[/]->5:[+.]->0:[\t ]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 20 - 1:[\r] -> 20 - 9:[;] -> 8 - -DFA state 21 - NFA states : - main.#2 - main.component#2.namevalue#1.optwhite#13.in - main.component#2.namevalue#1.optwhite#13.out - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.optwhite#13.in - main.component#5.namevalue#1.optwhite#13.out - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.optwhite#13.in - main.component#9.namevalue#1.optwhite#13.out - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 16) - (START)->6:[\055]->10:[=]->2:[!#-),:<>-@[]^`{-~]->0:[\t ]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 21 - 1:[\r] -> 21 - 9:[;] -> 8 - NFA exit tags applying : - GOT_NAMEVALUE - GOT_NAMEVALUE - GOT_NAMEVALUE - Attributes for <action> : GOT_NAMEVALUE - -DFA state 22 - NFA states : - main.component#2.namevalue#1.qvalue#9.qv1 - main.component#2.namevalue#1.qvalue#9.#1 - main.component#2.namevalue#1.qvalue#9.escape#2.in - main.component#2.namevalue#1.qvalue#9.qv2 - main.component#5.namevalue#1.qvalue#9.qv1 - main.component#5.namevalue#1.qvalue#9.#1 - main.component#5.namevalue#1.qvalue#9.escape#2.in - main.component#5.namevalue#1.qvalue#9.qv2 - main.component#9.namevalue#1.qvalue#9.qv1 - main.component#9.namevalue#1.qvalue#9.#1 - main.component#9.namevalue#1.qvalue#9.escape#2.in - main.component#9.namevalue#1.qvalue#9.qv2 - - Forward route : (from state 17) - (START)->6:[\055]->10:[=]->3:["]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 22 - 2:[!#-),:<>-@[]^`{-~] -> 22 - 3:["] -> 27 - 4:[*] -> 22 - 5:[+.] -> 22 - 6:[\055] -> 22 - 7:[/] -> 22 - 8:[0-9] -> 22 - 9:[;] -> 22 - 10:[=] -> 22 - 11:[A-Z_a-z] -> 22 - 12:[\\] -> 28 - NFA exit tags applying : - COPY_TO_VALUE - COPY_TO_VALUE - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - -DFA state 23 - NFA states : - main.component#2.namevalue#1.qvalue#9.escape#1.#1 - main.component#2.namevalue#1.qvalue#9.escape#1.#2 - main.component#5.namevalue#1.qvalue#9.escape#1.#1 - main.component#5.namevalue#1.qvalue#9.escape#1.#2 - main.component#9.namevalue#1.qvalue#9.escape#1.#1 - main.component#9.namevalue#1.qvalue#9.escape#1.#2 - - Forward route : (from state 17) - (START)->6:[\055]->10:[=]->3:["]->12:[\\]->(HERE) - Transitions : - 3:["] -> 29 - 12:[\\] -> 29 - -DFA state 24 - NFA states : - main.component#2.namevalue#1.#15 - main.component#2.namevalue#1.optwhite#15.in - main.component#2.namevalue#1.optwhite#15.out - main.component#2.namevalue#1.qvalue#16.in - main.component#2.namevalue#1.#17 - main.component#2.namevalue#1.optwhite#18.in - main.component#2.namevalue#1.optwhite#18.out - main.component#2.namevalue#1.value#19.in - main.component#5.namevalue#1.#15 - main.component#5.namevalue#1.optwhite#15.in - main.component#5.namevalue#1.optwhite#15.out - main.component#5.namevalue#1.qvalue#16.in - main.component#5.namevalue#1.#17 - main.component#5.namevalue#1.optwhite#18.in - main.component#5.namevalue#1.optwhite#18.out - main.component#5.namevalue#1.value#19.in - main.component#9.namevalue#1.#15 - main.component#9.namevalue#1.optwhite#15.in - main.component#9.namevalue#1.optwhite#15.out - main.component#9.namevalue#1.qvalue#16.in - main.component#9.namevalue#1.#17 - main.component#9.namevalue#1.optwhite#18.in - main.component#9.namevalue#1.optwhite#18.out - main.component#9.namevalue#1.value#19.in - - Forward route : (from state 19) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 24 - 1:[\r] -> 24 - 2:[!#-),:<>-@[]^`{-~] -> 25 - 3:["] -> 26 - 4:[*] -> 25 - 5:[+.] -> 25 - 6:[\055] -> 25 - 7:[/] -> 25 - 8:[0-9] -> 25 - 10:[=] -> 25 - 11:[A-Z_a-z] -> 25 - -DFA state 25 - NFA states : - main.#2 - main.component#2.namevalue#1.#18 - main.component#2.namevalue#1.value#19.v1 - main.component#2.namevalue#1.value#19.#1 - main.component#2.namevalue#1.value#19.out - main.component#2.namevalue#1.optwhite#20.in - main.component#2.namevalue#1.optwhite#20.out - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.#18 - main.component#5.namevalue#1.value#19.v1 - main.component#5.namevalue#1.value#19.#1 - main.component#5.namevalue#1.value#19.out - main.component#5.namevalue#1.optwhite#20.in - main.component#5.namevalue#1.optwhite#20.out - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.#18 - main.component#9.namevalue#1.value#19.v1 - main.component#9.namevalue#1.value#19.#1 - main.component#9.namevalue#1.value#19.out - main.component#9.namevalue#1.optwhite#20.in - main.component#9.namevalue#1.optwhite#20.out - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 19) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->2:[!#-),:<>-@[]^`{-~]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 30 - 1:[\r] -> 30 - 2:[!#-),:<>-@[]^`{-~] -> 25 - 4:[*] -> 25 - 5:[+.] -> 25 - 6:[\055] -> 25 - 7:[/] -> 25 - 8:[0-9] -> 25 - 9:[;] -> 8 - 10:[=] -> 25 - 11:[A-Z_a-z] -> 25 - NFA exit tags applying : - GOT_NAMEVALUE_CONT - COPY_TO_VALUE - GOT_NAMEVALUE_CONT - COPY_TO_VALUE - GOT_NAMEVALUE_CONT - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - Attributes for <action> : GOT_NAMEVALUE_CONT - -DFA state 26 - NFA states : - main.component#2.namevalue#1.qvalue#16.qv0 - main.component#2.namevalue#1.qvalue#16.escape#1.in - main.component#5.namevalue#1.qvalue#16.qv0 - main.component#5.namevalue#1.qvalue#16.escape#1.in - main.component#9.namevalue#1.qvalue#16.qv0 - main.component#9.namevalue#1.qvalue#16.escape#1.in - - Forward route : (from state 19) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->3:["]->(HERE) - Transitions : - 0:[\t ] -> 31 - 2:[!#-),:<>-@[]^`{-~] -> 31 - 4:[*] -> 31 - 5:[+.] -> 31 - 6:[\055] -> 31 - 7:[/] -> 31 - 8:[0-9] -> 31 - 9:[;] -> 31 - 10:[=] -> 31 - 11:[A-Z_a-z] -> 31 - 12:[\\] -> 32 - -DFA state 27 - NFA states : - main.#2 - main.component#2.namevalue#1.#10 - main.component#2.namevalue#1.qvalue#9.out - main.component#2.namevalue#1.optwhite#10.in - main.component#2.namevalue#1.optwhite#10.out - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.#10 - main.component#5.namevalue#1.qvalue#9.out - main.component#5.namevalue#1.optwhite#10.in - main.component#5.namevalue#1.optwhite#10.out - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.#10 - main.component#9.namevalue#1.qvalue#9.out - main.component#9.namevalue#1.optwhite#10.in - main.component#9.namevalue#1.optwhite#10.out - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 22) - (START)->6:[\055]->10:[=]->3:["]->0:[\t ]->3:["]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 33 - 1:[\r] -> 33 - 9:[;] -> 8 - NFA exit tags applying : - GOT_NAMEVALUE - GOT_NAMEVALUE - GOT_NAMEVALUE - Attributes for <action> : GOT_NAMEVALUE - -DFA state 28 - NFA states : - main.component#2.namevalue#1.qvalue#9.escape#2.#1 - main.component#2.namevalue#1.qvalue#9.escape#2.#2 - main.component#5.namevalue#1.qvalue#9.escape#2.#1 - main.component#5.namevalue#1.qvalue#9.escape#2.#2 - main.component#9.namevalue#1.qvalue#9.escape#2.#1 - main.component#9.namevalue#1.qvalue#9.escape#2.#2 - - Forward route : (from state 22) - (START)->6:[\055]->10:[=]->3:["]->0:[\t ]->12:[\\]->(HERE) - Transitions : - 3:["] -> 34 - 12:[\\] -> 34 - -DFA state 29 - NFA states : - main.component#2.namevalue#1.qvalue#9.escape#1.out - main.component#2.namevalue#1.qvalue#9.qv1 - main.component#2.namevalue#1.qvalue#9.#1 - main.component#2.namevalue#1.qvalue#9.escape#2.in - main.component#2.namevalue#1.qvalue#9.qv2 - main.component#5.namevalue#1.qvalue#9.escape#1.out - main.component#5.namevalue#1.qvalue#9.qv1 - main.component#5.namevalue#1.qvalue#9.#1 - main.component#5.namevalue#1.qvalue#9.escape#2.in - main.component#5.namevalue#1.qvalue#9.qv2 - main.component#9.namevalue#1.qvalue#9.escape#1.out - main.component#9.namevalue#1.qvalue#9.qv1 - main.component#9.namevalue#1.qvalue#9.#1 - main.component#9.namevalue#1.qvalue#9.escape#2.in - main.component#9.namevalue#1.qvalue#9.qv2 - - Forward route : (from state 23) - (START)->6:[\055]->10:[=]->3:["]->12:[\\]->3:["]->(HERE) - Transitions : - 0:[\t ] -> 22 - 2:[!#-),:<>-@[]^`{-~] -> 22 - 3:["] -> 27 - 4:[*] -> 22 - 5:[+.] -> 22 - 6:[\055] -> 22 - 7:[/] -> 22 - 8:[0-9] -> 22 - 9:[;] -> 22 - 10:[=] -> 22 - 11:[A-Z_a-z] -> 22 - 12:[\\] -> 28 - NFA exit tags applying : - COPY_TO_VALUE - COPY_TO_VALUE - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - -DFA state 30 - NFA states : - main.#2 - main.component#2.namevalue#1.optwhite#20.in - main.component#2.namevalue#1.optwhite#20.out - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.optwhite#20.in - main.component#5.namevalue#1.optwhite#20.out - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.optwhite#20.in - main.component#9.namevalue#1.optwhite#20.out - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 25) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->2:[!#-),:<>-@[]^`{-~]->0:[\t ]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 30 - 1:[\r] -> 30 - 9:[;] -> 8 - NFA exit tags applying : - GOT_NAMEVALUE_CONT - GOT_NAMEVALUE_CONT - GOT_NAMEVALUE_CONT - Attributes for <action> : GOT_NAMEVALUE_CONT - -DFA state 31 - NFA states : - main.component#2.namevalue#1.qvalue#16.qv1 - main.component#2.namevalue#1.qvalue#16.#1 - main.component#2.namevalue#1.qvalue#16.escape#2.in - main.component#2.namevalue#1.qvalue#16.qv2 - main.component#5.namevalue#1.qvalue#16.qv1 - main.component#5.namevalue#1.qvalue#16.#1 - main.component#5.namevalue#1.qvalue#16.escape#2.in - main.component#5.namevalue#1.qvalue#16.qv2 - main.component#9.namevalue#1.qvalue#16.qv1 - main.component#9.namevalue#1.qvalue#16.#1 - main.component#9.namevalue#1.qvalue#16.escape#2.in - main.component#9.namevalue#1.qvalue#16.qv2 - - Forward route : (from state 26) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->3:["]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 31 - 2:[!#-),:<>-@[]^`{-~] -> 31 - 3:["] -> 35 - 4:[*] -> 31 - 5:[+.] -> 31 - 6:[\055] -> 31 - 7:[/] -> 31 - 8:[0-9] -> 31 - 9:[;] -> 31 - 10:[=] -> 31 - 11:[A-Z_a-z] -> 31 - 12:[\\] -> 36 - NFA exit tags applying : - COPY_TO_VALUE - COPY_TO_VALUE - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - -DFA state 32 - NFA states : - main.component#2.namevalue#1.qvalue#16.escape#1.#1 - main.component#2.namevalue#1.qvalue#16.escape#1.#2 - main.component#5.namevalue#1.qvalue#16.escape#1.#1 - main.component#5.namevalue#1.qvalue#16.escape#1.#2 - main.component#9.namevalue#1.qvalue#16.escape#1.#1 - main.component#9.namevalue#1.qvalue#16.escape#1.#2 - - Forward route : (from state 26) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->3:["]->12:[\\]->(HERE) - Transitions : - 3:["] -> 37 - 12:[\\] -> 37 - -DFA state 33 - NFA states : - main.#2 - main.component#2.namevalue#1.optwhite#10.in - main.component#2.namevalue#1.optwhite#10.out - main.component#2.namevalue#1.out_normal - main.component#2.namevalue#1.#19 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.optwhite#10.in - main.component#5.namevalue#1.optwhite#10.out - main.component#5.namevalue#1.out_normal - main.component#5.namevalue#1.#19 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.optwhite#10.in - main.component#9.namevalue#1.optwhite#10.out - main.component#9.namevalue#1.out_normal - main.component#9.namevalue#1.#19 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 27) - (START)->6:[\055]->10:[=]->3:["]->0:[\t ]->3:["]->0:[\t ]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 33 - 1:[\r] -> 33 - 9:[;] -> 8 - NFA exit tags applying : - GOT_NAMEVALUE - GOT_NAMEVALUE - GOT_NAMEVALUE - Attributes for <action> : GOT_NAMEVALUE - -DFA state 34 - NFA states : - main.component#2.namevalue#1.qvalue#9.qv1 - main.component#2.namevalue#1.qvalue#9.#1 - main.component#2.namevalue#1.qvalue#9.escape#2.in - main.component#2.namevalue#1.qvalue#9.escape#2.out - main.component#2.namevalue#1.qvalue#9.qv2 - main.component#5.namevalue#1.qvalue#9.qv1 - main.component#5.namevalue#1.qvalue#9.#1 - main.component#5.namevalue#1.qvalue#9.escape#2.in - main.component#5.namevalue#1.qvalue#9.escape#2.out - main.component#5.namevalue#1.qvalue#9.qv2 - main.component#9.namevalue#1.qvalue#9.qv1 - main.component#9.namevalue#1.qvalue#9.#1 - main.component#9.namevalue#1.qvalue#9.escape#2.in - main.component#9.namevalue#1.qvalue#9.escape#2.out - main.component#9.namevalue#1.qvalue#9.qv2 - - Forward route : (from state 28) - (START)->6:[\055]->10:[=]->3:["]->0:[\t ]->12:[\\]->3:["]->(HERE) - Transitions : - 0:[\t ] -> 22 - 2:[!#-),:<>-@[]^`{-~] -> 22 - 3:["] -> 27 - 4:[*] -> 22 - 5:[+.] -> 22 - 6:[\055] -> 22 - 7:[/] -> 22 - 8:[0-9] -> 22 - 9:[;] -> 22 - 10:[=] -> 22 - 11:[A-Z_a-z] -> 22 - 12:[\\] -> 28 - NFA exit tags applying : - COPY_TO_VALUE - COPY_TO_VALUE - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - -DFA state 35 - NFA states : - main.#2 - main.component#2.namevalue#1.#16 - main.component#2.namevalue#1.qvalue#16.out - main.component#2.namevalue#1.optwhite#17.in - main.component#2.namevalue#1.optwhite#17.out - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.#16 - main.component#5.namevalue#1.qvalue#16.out - main.component#5.namevalue#1.optwhite#17.in - main.component#5.namevalue#1.optwhite#17.out - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.#16 - main.component#9.namevalue#1.qvalue#16.out - main.component#9.namevalue#1.optwhite#17.in - main.component#9.namevalue#1.optwhite#17.out - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 31) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->3:["]->0:[\t ]->3:["]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 38 - 1:[\r] -> 38 - 9:[;] -> 8 - NFA exit tags applying : - GOT_NAMEVALUE_CONT - GOT_NAMEVALUE_CONT - GOT_NAMEVALUE_CONT - Attributes for <action> : GOT_NAMEVALUE_CONT - -DFA state 36 - NFA states : - main.component#2.namevalue#1.qvalue#16.escape#2.#1 - main.component#2.namevalue#1.qvalue#16.escape#2.#2 - main.component#5.namevalue#1.qvalue#16.escape#2.#1 - main.component#5.namevalue#1.qvalue#16.escape#2.#2 - main.component#9.namevalue#1.qvalue#16.escape#2.#1 - main.component#9.namevalue#1.qvalue#16.escape#2.#2 - - Forward route : (from state 31) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->3:["]->0:[\t ]->12:[\\]->(HERE) - Transitions : - 3:["] -> 39 - 12:[\\] -> 39 - -DFA state 37 - NFA states : - main.component#2.namevalue#1.qvalue#16.escape#1.out - main.component#2.namevalue#1.qvalue#16.qv1 - main.component#2.namevalue#1.qvalue#16.#1 - main.component#2.namevalue#1.qvalue#16.escape#2.in - main.component#2.namevalue#1.qvalue#16.qv2 - main.component#5.namevalue#1.qvalue#16.escape#1.out - main.component#5.namevalue#1.qvalue#16.qv1 - main.component#5.namevalue#1.qvalue#16.#1 - main.component#5.namevalue#1.qvalue#16.escape#2.in - main.component#5.namevalue#1.qvalue#16.qv2 - main.component#9.namevalue#1.qvalue#16.escape#1.out - main.component#9.namevalue#1.qvalue#16.qv1 - main.component#9.namevalue#1.qvalue#16.#1 - main.component#9.namevalue#1.qvalue#16.escape#2.in - main.component#9.namevalue#1.qvalue#16.qv2 - - Forward route : (from state 32) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->3:["]->12:[\\]->3:["]->(HERE) - Transitions : - 0:[\t ] -> 31 - 2:[!#-),:<>-@[]^`{-~] -> 31 - 3:["] -> 35 - 4:[*] -> 31 - 5:[+.] -> 31 - 6:[\055] -> 31 - 7:[/] -> 31 - 8:[0-9] -> 31 - 9:[;] -> 31 - 10:[=] -> 31 - 11:[A-Z_a-z] -> 31 - 12:[\\] -> 36 - NFA exit tags applying : - COPY_TO_VALUE - COPY_TO_VALUE - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - -DFA state 38 - NFA states : - main.#2 - main.component#2.namevalue#1.optwhite#17.in - main.component#2.namevalue#1.optwhite#17.out - main.component#2.namevalue#1.out_continue - main.component#2.namevalue#1.#20 - main.component#2.namevalue#1.out - main.component#2.out - main.#3 - main.optwhite#3.in - main.optwhite#3.out - main.#5 - main.component#5.namevalue#1.optwhite#17.in - main.component#5.namevalue#1.optwhite#17.out - main.component#5.namevalue#1.out_continue - main.component#5.namevalue#1.#20 - main.component#5.namevalue#1.out - main.component#5.out - main.#6 - main.optwhite#6.in - main.optwhite#6.out - main.#10 - main.component#9.namevalue#1.optwhite#17.in - main.component#9.namevalue#1.optwhite#17.out - main.component#9.namevalue#1.out_continue - main.component#9.namevalue#1.#20 - main.component#9.namevalue#1.out - main.component#9.out - main.#11 - main.optwhite#10.in - main.optwhite#10.out - - Forward route : (from state 35) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->3:["]->0:[\t ]->3:["]->0:[\t ]->(HERE) - Transitions : - EOS -> 3 - 0:[\t ] -> 38 - 1:[\r] -> 38 - 9:[;] -> 8 - NFA exit tags applying : - GOT_NAMEVALUE_CONT - GOT_NAMEVALUE_CONT - GOT_NAMEVALUE_CONT - Attributes for <action> : GOT_NAMEVALUE_CONT - -DFA state 39 - NFA states : - main.component#2.namevalue#1.qvalue#16.qv1 - main.component#2.namevalue#1.qvalue#16.#1 - main.component#2.namevalue#1.qvalue#16.escape#2.in - main.component#2.namevalue#1.qvalue#16.escape#2.out - main.component#2.namevalue#1.qvalue#16.qv2 - main.component#5.namevalue#1.qvalue#16.qv1 - main.component#5.namevalue#1.qvalue#16.#1 - main.component#5.namevalue#1.qvalue#16.escape#2.in - main.component#5.namevalue#1.qvalue#16.escape#2.out - main.component#5.namevalue#1.qvalue#16.qv2 - main.component#9.namevalue#1.qvalue#16.qv1 - main.component#9.namevalue#1.qvalue#16.#1 - main.component#9.namevalue#1.qvalue#16.escape#2.in - main.component#9.namevalue#1.qvalue#16.escape#2.out - main.component#9.namevalue#1.qvalue#16.qv2 - - Forward route : (from state 36) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->3:["]->0:[\t ]->12:[\\]->3:["]->(HERE) - Transitions : - 0:[\t ] -> 31 - 2:[!#-),:<>-@[]^`{-~] -> 31 - 3:["] -> 35 - 4:[*] -> 31 - 5:[+.] -> 31 - 6:[\055] -> 31 - 7:[/] -> 31 - 8:[0-9] -> 31 - 9:[;] -> 31 - 10:[=] -> 31 - 11:[A-Z_a-z] -> 31 - 12:[\\] -> 36 - NFA exit tags applying : - COPY_TO_VALUE - COPY_TO_VALUE - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - - -Entry states in DFA: -Entry <in> : 0 -Searching for dead states... -(no dead states found) - ------------------------------ ------- COMPRESSING DFA ------ ------------------------------ -Old DFA state 0 becomes 0 -Old DFA state 1 becomes 0 (formerly 0) -Old DFA state 2 becomes 1 -Old DFA state 3 becomes 2 -Old DFA state 4 becomes 3 -Old DFA state 5 becomes 4 -Old DFA state 6 becomes 5 -Old DFA state 7 becomes 6 -Old DFA state 8 becomes 7 -Old DFA state 9 becomes 8 -Old DFA state 10 becomes 9 -Old DFA state 11 becomes 10 -Old DFA state 12 becomes 11 -Old DFA state 13 becomes 12 -Old DFA state 14 becomes 13 -Old DFA state 15 becomes 8 (formerly 9) -Old DFA state 16 becomes 14 -Old DFA state 17 becomes 15 -Old DFA state 18 becomes 16 -Old DFA state 19 becomes 17 -Old DFA state 20 becomes 18 -Old DFA state 21 becomes 19 -Old DFA state 22 becomes 20 -Old DFA state 23 becomes 21 -Old DFA state 24 becomes 17 (formerly 19) -Old DFA state 25 becomes 22 -Old DFA state 26 becomes 23 -Old DFA state 27 becomes 19 (formerly 21) -Old DFA state 28 becomes 21 (formerly 23) -Old DFA state 29 becomes 20 (formerly 22) -Old DFA state 30 becomes 24 -Old DFA state 31 becomes 25 -Old DFA state 32 becomes 26 -Old DFA state 33 becomes 19 (formerly 21) -Old DFA state 34 becomes 20 (formerly 22) -Old DFA state 35 becomes 24 (formerly 30) -Old DFA state 36 becomes 26 (formerly 32) -Old DFA state 37 becomes 25 (formerly 31) -Old DFA state 38 becomes 24 (formerly 30) -Old DFA state 39 becomes 25 (formerly 31) -Entry <in>, formerly state 0, now state 0 -------------------------------- -DFA structure after compression -------------------------------- -DFA state 0 - Forward route : - (START)->(HERE) - Transitions : - 0:[\t ] -> 0 - 1:[\r] -> 0 - 6:[\055] -> 1 - 8:[0-9] -> 1 - 11:[A-Z_a-z] -> 1 - -DFA state 1 - Forward route : (from state 0) - (START)->6:[\055]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 3 - 1:[\r] -> 4 - 4:[*] -> 5 - 6:[\055] -> 1 - 7:[/] -> 6 - 8:[0-9] -> 1 - 9:[;] -> 7 - 10:[=] -> 8 - 11:[A-Z_a-z] -> 1 - NFA exit tags applying : - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - Attributes for <copier> : COPY_TO_NAME - Attributes for <action> : GOT_NAME - -DFA state 2 - Forward route : (from state 1) - (START)->6:[\055]->EOS->(HERE) - Transitions : - NFA exit tags applying : - GOT_TERMINATOR - Attributes for <action> : GOT_TERMINATOR - -DFA state 3 - Forward route : (from state 1) - (START)->6:[\055]->0:[\t ]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 3 - 1:[\r] -> 4 - 4:[*] -> 5 - 6:[\055] -> 9 - 8:[0-9] -> 9 - 9:[;] -> 7 - 10:[=] -> 8 - 11:[A-Z_a-z] -> 9 - Use state 1 as basis (4 fixups) - NFA exit tags applying : - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - GOT_NAME_TRAILING_SPACE - COPY_TO_NAME - Attributes for <copier> : COPY_TO_NAME - Attributes for <action> : GOT_NAME_TRAILING_SPACE - -DFA state 4 - Forward route : (from state 1) - (START)->6:[\055]->1:[\r]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 4 - 1:[\r] -> 4 - 9:[;] -> 7 - 10:[=] -> 8 - -DFA state 5 - Forward route : (from state 1) - (START)->6:[\055]->4:[*]->(HERE) - Transitions : - 8:[0-9] -> 10 - -DFA state 6 - Forward route : (from state 1) - (START)->6:[\055]->7:[/]->(HERE) - Transitions : - 5:[+.] -> 11 - 6:[\055] -> 11 - 8:[0-9] -> 11 - 11:[A-Z_a-z] -> 11 - 12:[\\] -> 11 - -DFA state 7 - Forward route : (from state 1) - (START)->6:[\055]->9:[;]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 12 - 1:[\r] -> 12 - 6:[\055] -> 1 - 8:[0-9] -> 1 - 11:[A-Z_a-z] -> 1 - NFA exit tags applying : - GOT_TERMINATOR - Attributes for <action> : GOT_TERMINATOR - -DFA state 8 - Forward route : (from state 1) - (START)->6:[\055]->10:[=]->(HERE) - Transitions : - EOS -> 13 - 0:[\t ] -> 8 - 1:[\r] -> 8 - 2:[!#-),:<>-@[]^`{-~] -> 14 - 3:["] -> 15 - 4:[*] -> 14 - 5:[+.] -> 14 - 6:[\055] -> 14 - 7:[/] -> 14 - 8:[0-9] -> 14 - 10:[=] -> 14 - 11:[A-Z_a-z] -> 14 - -DFA state 9 - Forward route : (from state 3) - (START)->6:[\055]->0:[\t ]->6:[\055]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 3 - 1:[\r] -> 4 - 4:[*] -> 5 - 6:[\055] -> 9 - 8:[0-9] -> 9 - 9:[;] -> 7 - 10:[=] -> 8 - 11:[A-Z_a-z] -> 9 - Use state 1 as basis (4 fixups) - NFA exit tags applying : - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - GOT_NAME - COPY_TO_NAME - Attributes for <copier> : COPY_TO_NAME - Attributes for <action> : GOT_NAME - -DFA state 10 - Forward route : (from state 5) - (START)->6:[\055]->4:[*]->8:[0-9]->(HERE) - Transitions : - 0:[\t ] -> 16 - 1:[\r] -> 16 - 8:[0-9] -> 10 - 10:[=] -> 17 - -DFA state 11 - Forward route : (from state 6) - (START)->6:[\055]->7:[/]->5:[+.]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 18 - 1:[\r] -> 18 - 5:[+.] -> 11 - 6:[\055] -> 11 - 8:[0-9] -> 11 - 9:[;] -> 7 - 11:[A-Z_a-z] -> 11 - 12:[\\] -> 11 - Use state 6 as basis (4 fixups) - NFA exit tags applying : - GOT_MAJORMINOR - COPY_TO_MINOR - GOT_MAJORMINOR - COPY_TO_MINOR - GOT_MAJORMINOR - COPY_TO_MINOR - Attributes for <copier> : COPY_TO_MINOR - Attributes for <action> : GOT_MAJORMINOR - -DFA state 12 - Forward route : (from state 7) - (START)->6:[\055]->9:[;]->0:[\t ]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 12 - 1:[\r] -> 12 - 6:[\055] -> 1 - 8:[0-9] -> 1 - 11:[A-Z_a-z] -> 1 - Use state 7 as basis (0 fixups) - -DFA state 13 - Forward route : (from state 8) - (START)->6:[\055]->10:[=]->EOS->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 18 - 1:[\r] -> 18 - 9:[;] -> 7 - NFA exit tags applying : - GOT_NAMEVALUE - GOT_NAMEVALUE - GOT_NAMEVALUE - Attributes for <action> : GOT_NAMEVALUE - -DFA state 14 - Forward route : (from state 8) - (START)->6:[\055]->10:[=]->2:[!#-),:<>-@[]^`{-~]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 19 - 1:[\r] -> 19 - 2:[!#-),:<>-@[]^`{-~] -> 14 - 4:[*] -> 14 - 5:[+.] -> 14 - 6:[\055] -> 14 - 7:[/] -> 14 - 8:[0-9] -> 14 - 9:[;] -> 7 - 10:[=] -> 14 - 11:[A-Z_a-z] -> 14 - Use state 8 as basis (5 fixups) - NFA exit tags applying : - GOT_NAMEVALUE - COPY_TO_VALUE - GOT_NAMEVALUE - COPY_TO_VALUE - GOT_NAMEVALUE - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - Attributes for <action> : GOT_NAMEVALUE - -DFA state 15 - Forward route : (from state 8) - (START)->6:[\055]->10:[=]->3:["]->(HERE) - Transitions : - 0:[\t ] -> 20 - 2:[!#-),:<>-@[]^`{-~] -> 20 - 4:[*] -> 20 - 5:[+.] -> 20 - 6:[\055] -> 20 - 7:[/] -> 20 - 8:[0-9] -> 20 - 9:[;] -> 20 - 10:[=] -> 20 - 11:[A-Z_a-z] -> 20 - 12:[\\] -> 21 - -DFA state 16 - Forward route : (from state 10) - (START)->6:[\055]->4:[*]->8:[0-9]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 16 - 1:[\r] -> 16 - 10:[=] -> 17 - -DFA state 17 - Forward route : (from state 10) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->(HERE) - Transitions : - 0:[\t ] -> 17 - 1:[\r] -> 17 - 2:[!#-),:<>-@[]^`{-~] -> 22 - 3:["] -> 23 - 4:[*] -> 22 - 5:[+.] -> 22 - 6:[\055] -> 22 - 7:[/] -> 22 - 8:[0-9] -> 22 - 10:[=] -> 22 - 11:[A-Z_a-z] -> 22 - -DFA state 18 - Forward route : (from state 11) - (START)->6:[\055]->7:[/]->5:[+.]->0:[\t ]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 18 - 1:[\r] -> 18 - 9:[;] -> 7 - Use state 13 as basis (0 fixups) - -DFA state 19 - Forward route : (from state 14) - (START)->6:[\055]->10:[=]->2:[!#-),:<>-@[]^`{-~]->0:[\t ]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 19 - 1:[\r] -> 19 - 9:[;] -> 7 - NFA exit tags applying : - GOT_NAMEVALUE - GOT_NAMEVALUE - GOT_NAMEVALUE - Attributes for <action> : GOT_NAMEVALUE - -DFA state 20 - Forward route : (from state 15) - (START)->6:[\055]->10:[=]->3:["]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 20 - 2:[!#-),:<>-@[]^`{-~] -> 20 - 3:["] -> 19 - 4:[*] -> 20 - 5:[+.] -> 20 - 6:[\055] -> 20 - 7:[/] -> 20 - 8:[0-9] -> 20 - 9:[;] -> 20 - 10:[=] -> 20 - 11:[A-Z_a-z] -> 20 - 12:[\\] -> 21 - Use state 15 as basis (1 fixups) - NFA exit tags applying : - COPY_TO_VALUE - COPY_TO_VALUE - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - -DFA state 21 - Forward route : (from state 15) - (START)->6:[\055]->10:[=]->3:["]->12:[\\]->(HERE) - Transitions : - 3:["] -> 20 - 12:[\\] -> 20 - -DFA state 22 - Forward route : (from state 17) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->2:[!#-),:<>-@[]^`{-~]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 24 - 1:[\r] -> 24 - 2:[!#-),:<>-@[]^`{-~] -> 22 - 4:[*] -> 22 - 5:[+.] -> 22 - 6:[\055] -> 22 - 7:[/] -> 22 - 8:[0-9] -> 22 - 9:[;] -> 7 - 10:[=] -> 22 - 11:[A-Z_a-z] -> 22 - Use state 17 as basis (5 fixups) - NFA exit tags applying : - GOT_NAMEVALUE_CONT - COPY_TO_VALUE - GOT_NAMEVALUE_CONT - COPY_TO_VALUE - GOT_NAMEVALUE_CONT - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - Attributes for <action> : GOT_NAMEVALUE_CONT - -DFA state 23 - Forward route : (from state 17) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->3:["]->(HERE) - Transitions : - 0:[\t ] -> 25 - 2:[!#-),:<>-@[]^`{-~] -> 25 - 4:[*] -> 25 - 5:[+.] -> 25 - 6:[\055] -> 25 - 7:[/] -> 25 - 8:[0-9] -> 25 - 9:[;] -> 25 - 10:[=] -> 25 - 11:[A-Z_a-z] -> 25 - 12:[\\] -> 26 - -DFA state 24 - Forward route : (from state 22) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->2:[!#-),:<>-@[]^`{-~]->0:[\t ]->(HERE) - Transitions : - EOS -> 2 - 0:[\t ] -> 24 - 1:[\r] -> 24 - 9:[;] -> 7 - NFA exit tags applying : - GOT_NAMEVALUE_CONT - GOT_NAMEVALUE_CONT - GOT_NAMEVALUE_CONT - Attributes for <action> : GOT_NAMEVALUE_CONT - -DFA state 25 - Forward route : (from state 23) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->3:["]->0:[\t ]->(HERE) - Transitions : - 0:[\t ] -> 25 - 2:[!#-),:<>-@[]^`{-~] -> 25 - 3:["] -> 24 - 4:[*] -> 25 - 5:[+.] -> 25 - 6:[\055] -> 25 - 7:[/] -> 25 - 8:[0-9] -> 25 - 9:[;] -> 25 - 10:[=] -> 25 - 11:[A-Z_a-z] -> 25 - 12:[\\] -> 26 - Use state 23 as basis (1 fixups) - NFA exit tags applying : - COPY_TO_VALUE - COPY_TO_VALUE - COPY_TO_VALUE - Attributes for <copier> : COPY_TO_VALUE - -DFA state 26 - Forward route : (from state 23) - (START)->6:[\055]->4:[*]->8:[0-9]->10:[=]->3:["]->12:[\\]->(HERE) - Transitions : - 3:["] -> 25 - 12:[\\] -> 25 - - -Entry states in DFA: -Entry <in> : 0 diff --git a/src/mairix/nvptypes.h b/src/mairix/nvptypes.h @@ -1,43 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2006,2007 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#ifndef NVPTYPES_H -#define NVPTYPES_H - -enum nvp_action { - GOT_NAMEVALUE, - GOT_NAMEVALUE_CONT, - GOT_NAME, - GOT_NAME_TRAILING_SPACE, - GOT_MAJORMINOR, - GOT_TERMINATOR, - GOT_NOTHING -}; - -enum nvp_copier { - COPY_TO_NAME, - COPY_TO_MINOR, - COPY_TO_VALUE, - COPY_NOWHERE -}; - -#endif diff --git a/src/mairix/old_docs/mairix.texi b/src/mairix/old_docs/mairix.texi @@ -1,885 +0,0 @@ -\input texinfo -@c {{{ Main header stuff -@afourwide -@paragraphindent 0 -@setfilename mairix.info -@settitle User guide for the mairix program -@c @setchapternewpage off - -@ifinfo -@dircategory Utilities -@direntry -* mairix: (mairix). Indexing/searching utility for maildir folders -@end direntry -@end ifinfo - -@titlepage -@sp 10 -@title The mairix program -@subtitle This manual describes how to use -@subtitle the mairix program for indexing and -@subtitle searching email messages stored in maildir folders. -@author Richard P. Curnow -@page -@vskip 0pt plus 1filll -Copyright @copyright{} 2002,2003,2004,2005 Richard P. Curnow -@end titlepage - -@contents -@c }}} - -@ifnottex -@node Top -@top -@menu -* Introduction:: -* Installation:: Compiling and installing the software -* Use:: Quickstart guide and examples of use -@end menu -@end ifnottex - -@node Introduction -@chapter Introduction -@menu -* Background:: How mairix came to be written. -@end menu - -@node Background -@section Background -The @emph{mairix} program arose from a need to index and search 100's or 1000's -of email messages in an efficient way. It began life supporting just Maildir -format folder, but now MH and mbox formats are also supported. - -I use the @emph{mutt} email client. @emph{mutt} has a feature called -@emph{limit}, where the display of messages in the current folder can be -filtered based on matching regular expressions in particular parts of the -messages. I find this really useful. But there is a snag - it only works on -the current folder. If you have messages spread across many folders, you're -out of luck with limit. OK - so why not keep all messages in a single folder? -The problem is that the performance drops badly. This is true regardless of -folder format - mbox, maildir etc, though probably worse for some formats than -others depending on the sizes of messages in the folders. - -So on the one hand, we want small folders to keep the performance high. But on -the other hand, we want useful searching. - -I use the maildir format for my incoming folders. This scheme has one file per -message. On my inboxes@footnote{of which I have many, because I (naturally) -use @emph{procmail} to split my incoming mail}, I like this for 2 reasons : - -@itemize @bullet -@item Fast deletion of messages I don't want to keep (spam, circulars, mailing -list threads I'm not interested in etc). (Compare mbox, where the whole file -would need to be rewritten.) -@item No locking issues whatever. Maybe I'm over cautious, but I don't really -trust all that locking stuff to protect a single mbox file in all cases, and a -single file seems just too vulnerable to corruption.) Also, I sometimes read -the mail over NFS mounted filesystems, where locking tends to be a real -disaster area. -@end itemize - -Since I'm using maildir for inboxes, I've traditionally used it for all my -folders, for uniformity. - -So, I hear you ask, if you use a one-file-per-message format, why not just use -find + egrep to search for messages? I saw the following problems with this: - -@itemize @bullet -@item What if I want to find all messages to/cc me, from Homer Simpson, dated -between 1 and 2 months ago, with the word "wubble" in the body? This would -involve a pretty nasty set of regexps in a pipeline of separate egreps (and -bear in mind, headers could be split over line boundaries...) -@item What if the message body has quoted-printable (or worse, base64) transfer -encoding? The egrep for "wubble" could come very unstuck. -@item How would the matching messages be conveniently arranged into a new -folder to allow browsing with mutt? -@item What if I wanted to see all messages in the same threads as those -matching the above condition? -@item If I had 1000's of messages, this wasn't going to be quick, especially if -I wanted to keep tuning the search condition.@footnote{This may be a non-issue -for people with the lastest technology under their desk, but at the time I -started writing mairix, I had a 1996 model 486 at home}. -@end itemize - -So find + egrep was a non-starter. I looked around for other technology. I -found @emph{grepmail}, but this only works for mbox format folders, and -involved scanning each message every time (so lost on the speed issue). - -I decided that this was going to be my next project, and mairix was born. By -the way, the name originally came from abbreviating @emph{MAildIR IndeX}, but -this is now an anachronism since MH and mbox are supported too. - -@node Installation -@chapter Installation - -There is not much to this. In the simplest case you can just do - -@example -./configure -make -make install -@end example - -You need to be root to run the final step unless you're installing under your -own home directory somewhere. - -However, you might want to tune the options further. The @file{configure} -script shares its common options with the usual autoconf-generated scripts, -even though it's not autoconf-generated itself. For example, a fuller build could use - -@example -CC=gcc CFLAGS="-O2 -Wall" ./configure \ - --prefix=/opt/mairix \ - --infodir=/usr/share/info -make -make install -make docs -make install_docs -@end example - -The final step is to create a @file{~/.mairixrc} file. An example is included -in the file @file{dotmairixrc.eg}. Just copy that to @file{~/.mairixrc} and edit -it. - -@node Use -@chapter Use - -@menu -* use_intro:: Overview of use -* capabilities:: Indexing strategy and search capabilities -* mairixrc:: The @file{~/.mairixrc} file -* mfolder_setup:: Setting up the match folder -* command_line:: Command line options -* date_syntax:: Syntax used for date searches -@end menu - -@node use_intro -@section Overview of use - -@emph{mairix} has two modes of use : index building and searching. The -searching mode runs whenever the command line contains any expressions to -search for. Otherwise, the indexing mode is run. - -To begin with, an indexing run must be performed before searching will work at -all. Otherwise your search will be operating on an empty database and won't -produce any output. - -The output of the search mode is usually placed in a @emph{match folder}. You -can select the type of folder that is used. For Maildir, it is just a normal -maildir directory (i.e. containing @file{new}, @file{tmp} and @file{cur}) -subdirectories. If you select MH it is a directory containing entries with -numerical filenames, so you can open it as a normal MH folder in your mail -program. If you select mbox, it is a single file in mbox format. - -You configure the path for the match folder in your @file{~/.mairixrc} file. -When writing to a mfolder in maildir or MH format, mairix will populate it with -symbolic links pointing to the paths of the real messages that were matched by -the search expression.@footnote{Although symlinks use up more inodes than hard -links, I decided they were more useful because it makes it possible to see the -filenames of the original messages via @command{ls -l}.} If a message in a -mbox folder matches, mairix will copy the message contents to a single file in -the mfolder directory. - -If the mfolder is in mbox format, mairix will copy the message contents of each -matching message into the mfolder file. (There is no way of exploiting -symlinks to avoid the copying in this case.) - -If desired, mairix can produce just a list of files that match the search -expression and omit the building of the match folder (the so-called 'raw' -output mode). This mode of operation may be useful in communicating the -results of the search to other programs. - -@node capabilities -@section Indexing strategy and search capabilities - -@emph{mairix} works exclusively in terms of @emph{words}. The index that's -built in non-search mode contains a table of which words occur in which -messages. Hence, the search capability is based on finding messages that -contain particular words. @emph{mairix} defines a word as any string of -alphanumeric characters + underscore. Any whitespace, punctuation, hyphens etc -are treated as word boundaries. - -@emph{mairix} has special handling for the @t{To:}, @t{Cc:} and @t{From:} -headers. Besides the normal word scan, these headers are scanned a second -time, where the characters @samp{@@}, @samp{-} and @samp{.} are also treated as -word characters. This allows most (if not all) email addresses to appear in -the database as single words. So if you have a mail from -@t{wibble@@foobar.zzz}, it will match on both these searches - -@example -mairix f:foobar -mairix f:wibble@@foobar.zzz -@end example - -It should be clear by now that the searching cannot be used to find messages -matching general regular expressions. Personally, I don't find that much use -anyway for locating old messages - I'm far more likely to remember particular -keywords that were in the messages, or details of the recipients, or the -approximate date. - -It's also worth pointing out that there is no 'locality' information stored, so -you can't search for messages that have one words 'close' to some other word. -For every message and every word, there is a simple yes/no condition stored - -whether the message contains the word in a particular header or in the body. -So far this has proved to be adequate. mairix has a similar feel to using an -Internet search engine. - -There are three further searching criteria that are supported (besides word -searching): - -@itemize @bullet -@item Searching for messages whose @t{Date:} header is in a particular range -@item Searching for messages whose size is in a particular range. (I see this -being used mainly for finding 'huge' messages, as you're most likely to want to -cull these to recover disc space.) -@item Searching for messages with a particular substring in their paths. You -can use this feature to limit the search to particular folders in your mail -hierarchy, for example. -@end itemize - -@node mairixrc -@section The @file{~/.mairixrc} file - -@subsection Overview - -This file contains information about where you keep your mail folders, where -you want the index file to be stored and where you want the match folder to -be, into which the search mode places the symlinks. - -mairix searches for this file at @file{~/.mairixrc} unless you specify the -@samp{-f} command line option. - -If a # character appears in the file, the rest of that line is ignored. This -allows you to specify comments. - -There are 3 entries (@samp{base}, @samp{mfolder} and @samp{database}) that must -appear in the file. Also at least one of @samp{maildir}, @samp{mh} and -@samp{mbox} must appear. Optionally, the @samp{mformat} entry may -appear. An example illustrates: - -@example -base=/home/richard/mail -maildir=new-mail:new-chrony -maildir=recent...:ancient... -mh=an_mh_folder -mbox=archive1:archive2 -mfolder=mfolder -mformat=maildir -database=/home/richard/.mairix_database -@end example - -@subsection mairixrc file keys -The keys are as follows: - -@table @asis -@item base -This is the path to the common parent directory of all your maildir folders. -@item maildir -This is a colon-separated list of the Maildir folders (relative to @samp{base}) -that you want indexed. Any entry that ends @samp{...} is recursively scanned -to find any Maildir folders underneath it. - -More than one line starting with @samp{maildir} can be included. In this case, -mairix joins the lines together with colons as though a single list of folders had -been given on a single very long line. - -Each colon-separated entry may be a wildcard. See the discussion under mbox (below) for the -wildcard syntax. For example - -@example -maildir=zzz/foo*... -@end example - -will match maildir folders like these (relative to the folder_base) - -@example -zzz/foobar/xyz -zzz/fooquux -zzz/foo -zzz/fooabc/u/v/w -@end example - -and - -@example -maildir=zzz/foo[abc]* -@end example - -will match maildir folders like these (relative to the folder_base) - -@example -zzz/fooa -zzz/fooaaaxyz -zzz/foobcd -zzz/fooccccccc -@end example - -If a folder name contains a colon, you can write this by using the sequence -@samp{\:} to escape the colon. Otherwise, the backslash character is treated -normally. (If the folder name actually contains the sequence @samp{\:}, you're -out of luck.) - -@item mh -This is a colon-separated list of the MH folders (relative to @samp{base}) that -you want indexed. Any entry that ends @samp{...} is recursively scanned to -find any MH folders underneath it. - -More than one line starting with @samp{mh} can be included. In this case, -mairix joins the lines together with colons as though a single list of folders had -been given on a single very long line. - -Each colon-separated entry may be a wildcard, see the discussion under maildir -(above) and mbox (below) for the syntax and semantics of specifying wildcards. - -@item mbox -This is a colon-separated list of the mbox folders (relative to @samp{base}) that -you want indexed. - -Each colon-separated item in the list can be suffixed by @samp{...}. If the -item matches a regular file, that file is treated as a mbox folder and the -@samp{...} suffix is ignored. If the item matches a directory, a recursive -scan of everything inside that directory is made, and all regular files are -initially considered as mbox folders. (Any directories found in this scan are -themselves scanned, since the scan is recursive.) - -Each colon-separated item may contain wildcard operators, but only in its final -path component. The wildcard operators currently supported are - -@table @asis -@item * -Match zero or more characters (each character matched is arbitrary) -@item ? -Match exactly one arbitrary character -@item [abcs-z] -Character class : match a single character from the set a, b, c, s, t, u, v, w, -x, y and z. - -To include a literal @samp{]} in the class, place it immediately after the opening @samp{[}. -To include a literal @samp{-} in the class, place it immediately before the closing @samp{]}. - -@end table - -If these metacharacters are included in non-final path components, they have no -special meaning. - -Here are some examples - -@table @asis -@item mbox=foo/bar* -matches @file{foo/bar}, @file{foo/bar1}, @file{foo/barrrr} etc -@item mbox=foo*/bar* -matches @file{foo*/bar}, @file{foo*/bar1}, @file{foo*/barrrr} etc -@item mbox=foo/* -matches @file{foo/bar}, @file{foo/bar1}, @file{foo/barrrr}, @file{foo/foo}, @file{foo/x} etc -@item mbox=foo... -matches any regular file in the tree rooted at @file{foo} -@item mbox=foo/*... -same as before -@item mbox=foo/[a-z]*... -matches @file{foo/a}, @file{foo/aardvark/xxx}, @file{foo/zzz/foobar}, -@file{foo/w/x/y/zzz}, but @b{not} @file{foo/A/foobar} -@end table - -Regular files that are mbox folder candidates are examined internally. Only -files containing standard mbox @samp{From } separator lines will be scanned for -messages. - -If a regular file has a name ending in @file{.gz}, and gzip support is compiled -into the mairix binary, the file will be treated as a gzipped mbox. - -If a regular file has a name ending in @file{.bz2}, and bzip support is compiled -into the mairix binary, the file will be treated as a bzip2'd mbox. - -More than one line starting with @samp{mbox} can be included. In this case, -mairix joins the lines together with colons as though a single list of folders had -been given on a single very long line. - -mairix performs @b{no} locking of mbox folders when it is accessing them. If a -mail delivery program is modifying the mbox at the same time, it is likely that -one or messages in the mbox will never get indexed by mairix (until the -database is removed and recreated from scratch, anyway.) The assumption is -that mairix will be used to index archive folders rather than incoming ones, so -this is unlikely to be much of a problem in reality. - -@emph{mairix} can support a maximum of 65536 separate mboxes, and a maximum of -65536 messages within any one mbox. - -@item omit -This is a colon-separated list of glob patterns for folders to be -omitted from the indexing. This allows wide wildcards to be used in the -@emph{maildir}, @emph{mh} and @emph{mbox} arguments, with the @emph{omit} -option used to selectively remove unwanted folders from the folder lists. -Within the glob patterns, a single @samp{*} matches any sequence of characters -other than @samp{/}. However @samp{**} matches any sequence of characters -including @samp{/}. This allows glob patterns to be constructed which have a -wildcard for just one directory component, or for any number of directory -components. - -The @emph{omit} option can be specified as many times as required so that the -list of patterns doesn't all have to fit on one line. - -As an example, - -@example -mbox=bulk... -omit=bulk/spam* -@end example - -will index all mbox folders at any level under the @file{bulk} subdirectory of -the base folder, except for those folders whose names start @file{bulk/spam}, -e.g. @file{bulk/spam}, @file{bulk/spam2005} etc. In constrast, - -@example -mbox=bulk... -omit=bulk/spam** -@end example - -will index all mbox folders at any level under the @file{bulk} subdirectory of -the base folder, except for those folders whose names start @file{bulk/spam}, -e.g. @file{bulk/spam}, @file{bulk/spam2005}, @file{bulk/spam/2005}, -@file{bulk/spam/2005/jan} etc. - -@item nochecks -This takes no arguments. If a line starting with @samp{nochecks} is present, -it is the equivalent of specifying the @samp{-Q} flag to every indexing run. - -@item mfolder -This defines the name of the @emph{match} folder (within the directory -specified by @samp{base}) into which the search mode writes its output. -(If the mformat used is @samp{raw}, then this setting is not -used and may be excluded.) - -If the first character of the @b{mfolder} value is @samp{/} or @samp{.}, it is -taken as a pathname in its own right. This allows you to specify absolute -paths and paths relative to the current directory where the mfolder should be -written. Otherwise, the value of @b{mfolder} is appended to the value of -@b{base}, in the same way as for the source folders. - -@item mformat -This defines the type of folder used for the @emph{match folder} where the -search results go. There are four valid settings for this @samp{mh}, -@samp{maildir}, @samp{mbox} or @samp{raw}. If the @samp{raw} setting is used then -mairix will just print out the path names of the files that match and -no match folder will be created. @samp{maildir} is the default if this -option is not defined. The setting is case-insensitive. - -@item database -This defines the path where mairix's index database is kept. You can keep this -file anywhere you like. -@end table - -It is illegal to have a folder listed twice. Once mairix has built a list of -all the messages currently in your folders, it will search for duplicates -before proceeding. If any duplicates are found (arising from the same folder -being specified twice), it will give an error message and exit. This is to -prevent corrupting the index database file. - -@subsection mairixrc expansions - -The part of each line in @file{.mairixrc} following the equals sign can contain -the following types of expansion: - -@table @asis -@item Home directory expansion -If the sequence @samp{~/} appears at the start of the text after the equals -sign, it is expanded to the user's home directory. Example: - -@example -database=~/Mail/mairix_database -@end example - -@item Environment expansion -If a @samp{$} is followed by a sequence of alpha-numeric characters (or -@samp{_}), the whole string is replaced by looking up the corresponding -environment variable. Similarly, if @samp{$} is followed by an open brace -(@samp{@{}), everything up to the next close brace is looked up as an -environment variable and the result replaces the entire sequence. - -Suppose in the shell we do -@example -export FOO=bar -@end example - -and the @file{.mairixrc} file contains -@example -maildir=xxx/$FOO -mbox=yyy/a$@{FOO@}b -@end example - -this is equivalent to -@example -maildir=xxx/bar -mbox=yyy/abarb -@end example - -If the specified environment variable is not set, the replacement is the empty -string. - -@end table - -@node mfolder_setup -@section Setting up the match folder -If the match folder does not exist when running in search mode, it is -automatically created. For @samp{mformat=maildir} (the default), this -should be all you need to do. If you use @samp{mformat=mh}, you may -have to run some commands before your mailer will recognize the folder. e.g. -for mutt, you could do - -@example -mkdir -p /home/richard/Mail/mfolder -touch /home/richard/Mail/mfolder/.mh_sequences -@end example - -which seems to work. Alternatively, within mutt, you could set @var{mbox_type} -to @samp{mh} and save a message to @samp{+mfolder} to have mutt set up the -structure for you in advance. - -If you use Sylpheed, the best way seems to be to create the new folder from -within Sylpheed before letting mairix write into it. This seems to be all you -need to do. - -@node command_line -@section Command line options - -The command line syntax is - -For indexing mode: -@example -mairix [-f path] [-p] [-v] [-Q] -@end example -For search mode -@example -mairix [-f path] [-t] [-v] [-a] [-r] [-o mfolder] expr1 [expr2] ... [exprn] -@end example -For database dump mode -@example -mairix [-f path] -d -@end example - -The @samp{-f} or @samp{--rcfile} flag allows a different path to the -@file{mairixrc} file to be given, replacing the default of @file{~/.mairixrc}. - -The @samp{-p} or @samp{--purge} flag is used in indexing mode. Indexing works -incrementally. When new messages are found, they are scanned and information -about the words they contain is appended onto the existing information. When -messages are deleted, holes are normally left in the message sequence. These -holes take up space in the database file. This flag will compress the deleted -paths out of the database to save space. Additionally, where @samp{mbox} -folders are in use, information in the database about folders that no longer -exist, or which are no longer referenced in the rc-file, will be purged also. - -The @samp{-v} or @samp{--verbose} flag is used in indexing mode. It causes -more information to be shown during the indexing process. In search mode, it -causes debug information to be shown if there are problems creating the -symlinks. (Normally this would be an annoyance. If a message matches multiple -queries when using @samp{-a}, mairix will try to create the same symlink -multiple times. This prevents the same message being shown multiple times in -the match folder.) - -The @samp{-Q} or @samp{--no-integrity-checks} flag is used in indexing mode. -Normally, mairix will do various integrity checks on the database after loading -it in, and before writing the modified database out again. The checking helps -to detect mairix bugs much earlier, but it has a performance penalty. This -flag skips the checks, at the cost of some loss in robustness. See also the -@samp{nochecks} directive in @ref{mairixrc}. - -The @samp{--unlock} flag is used in any mode. mairix dot-locks the database -file to prevent corruption due to concurrent accesses. If the process holding -the lock exits prematurely for any reason, the lockfile will be left behind. -By using the @samp{--unlock} option, an unwanted lockfile can be conveniently -removed. - -The @samp{-t} or @samp{--threads} option applies to search mode. Normally, -only the messages matching all the specified expressions are included in the -@emph{match folder} that is built. With the @samp{-t} flag, any message in -the same thread as one of the matched messages will be included too. Note, the -threading is based on processing the @t{Message-ID}, @t{In-Reply-To} and -@t{References} headers in the messages. Some mailers don't generate these -headers in a co-operative way and will cause problems with this threading -support. (Outlook seems to be one culprit.) If you are plagued by this -problem, the 'edit threads' patch to mutt may be useful to you. - -The @samp{-d} or @samp{--dump} option causes mairix to dump the database -contents in human-readable form to stdout. It is mainly for use in debugging. -If this option is specified, neither indexing nor searching are performed. - -The @samp{-a} or @samp{--augment} option also applies to search mode. -Normally, the first action of the search mode is to clear any existing message -links from the match folder. With the @samp{-a} flag, this step is -suppressed. It allows the folder contents to be built up by matching with 2 or -more diverse sets of match expressions. If this mode is used, and a message -matches multiple queries, only a single symlink will be created for it. - -The @samp{-r} or @samp{--raw-output} option is used to force the raw output -mode for a particular search, in preference to the output format defined by the -@samp{mformat} line in the @file{mairixrc} file. This may be useful for -identifying which mbox contains a particular match, since there is way to see -this when the matching messages are placed in the mfolder in this case. (Note -for matches in maildir and MH folders when @samp{mformat} is maildir or MH, the -symbolic links in the mfolder will show the path to the matching message.) - -The @samp{-o} or @samp{--mfolder} option is used in search mode to specify a -match folder different to the one specified in the @file{mairixrc} to be -used. The path given by the @samp{mfolder} argument after this flag is -relative to the folder base directory given in the @file{mairixrc} file, in the -same way as the directory in the mfolder specification in that file is. So if -your @file{mairixrc} file contains - -@example -base=/home/foobar/Mail -@end example - -and you run mairix like this - -@example -mairix -o mfolder2 make,money,fast -@end example - -mairix will find all of your saved junk emails containing these three words and -put the results into @file{/home/foobar/Mail/mfolder2}. - -The @samp{-o} argument obeys the same conventions regarding initial @samp{/} -and @samp{.} characters as the @b{mfolder} line in the @file{.mairixrc} file -does. - -@emph{Mairix} will refuse to output search results (whether specified -by the @samp{-o} or in the @file{.mairixrc} file) into one of the -folders that are indexed; it figures out that list by looking in the -@file{.mairixrc} file, or in the file you specify using the @samp{-f} -option. This sanity check prevents you inadvertantly destroying one -of your important folders (but won't catch all such cases, sadly). - -The search mode runs when there is at least one search expression. Search -expressions can take forms such as (in increasing order of complexity): - -@itemize @bullet -@item A date expression. The format for specifying the date is described in section @ref{date_syntax}. - -@item A size expression. This matches all messages whose size in bytes is in a -particular range. For example, to match all messages bigger than 1 Megabyte -the following command can be used - -@example -mairix z:1m- -@end example - -To match all messages between 10kbytes and 20kbytes in size, the following -command can be used: - -@example -mairix z:10k-20k -@end example - -@item A word, e.g. @samp{pointer}. This matches any message with the word -@samp{pointer} in the @t{To}, @t{Cc}, @t{From} or @t{Subject} headers, or in -the message body.@footnote{Message body is taken to mean any body part of type -text/plain or text/html. For text/html, text within meta tags is ignored. In -particular, the URLs inside <A HREF="..."> tags are not currently indexed. -Non-text attachments are ignored. If there's an attachment of type -message/rfc822, this is parsed and the match is performed on this sub-message -too. If a hit occurs, the enclosing message is treated as having a hit.} - -@item A word in a particular part of the message, e.g. @samp{s:pointer}. This -matches any message with the word @samp{pointer} in the subject. The -qualifiers for this are : - -@table @asis -@item @t{t:pointer} -to match @samp{pointer} in the @t{To:} header, -@item @t{c:pointer} -to match @samp{pointer} in the @t{Cc:} header, -@item @t{a:pointer} -to match @samp{pointer} in the @t{To:}, @t{Cc:} or @t{From:} headers (@samp{a} meaning @samp{address}), -@item @t{f:pointer} -to match @samp{pointer} in the @t{From:} header, -@item @t{s:pointer} -to match @samp{pointer} in the @t{Subject:} header, -@item @t{b:pointer} -to match @samp{pointer} in the message body. -@item @t{m:pointer} -to match messages having a Message-ID header of @samp{pointer}. -@end table - -Multiple fields may be specified, e.g. @t{sb:pointer} to match in the -@t{Subject:} header or the body. - -@item A negated word, e.g. @samp{s:~pointer}. This matches all messages that -don't have the word @samp{pointer} in the subject line. - -@item A substring match, e.g. @samp{s:point=}. This matches all messages -containing a word in their subject line where the word has @samp{point} as a -substring, e.g. @samp{pointer}, @samp{disappoint}. - -@item An approximate match, e.g. @samp{s:point=1}. This matches all messages -containing a word in their subject line where the word has @samp{point} as a -substring with at most one error, e.g. @samp{jointed} contains @samp{joint} -which can be got from @samp{point} with one letter changed. An error can be a -single letter changed, inserted or deleted. - -@item A left-anchored substring match, e.g. @samp{s:^point=}. This matches all -messages containing a word in their subject line where the word begins with the -string @samp{point}. (This feature is intended to be useful for inflected -languages where the substring search is used to avoid the grammatical ending on -the word.) This left-anchored facility can be combined with the approximate -match facility, e.g. @samp{s:^point=1}. - -Note, if the @samp{^} prefix is used without the @samp{=} suffix, it is ignored. -For example, @samp{s:^point} means the same thing as @samp{s:point}. - -@item A disjunction, e.g. @samp{s:pointer/dereference}. This matches all -messages with one or both of the words @samp{pointer} and @samp{dereference} in -their subject lines. - -@item Each disjunction may be a conjunction, e.g. -@samp{s:null,pointer/dereference=2} matches all messages whose subject lines -either contain both the words @samp{null} and @samp{pointer}, or contain the -word @samp{dereference} with up to 2 errors (or both). - -@item A path expression. This matches all messages with a particular substring -in their path. The syntax is very similar to that for words within the message -(above), and all the rules for @samp{+}, @samp{,}, approximate matching etc are -the same. The word prefix used for a path expression is @samp{p:}. Examples: - -@example -mairix p:/archive/ -@end example - -matches all messages with @samp{/archive/} in their path, and - -@example -mairix p:wibble=1 s:wibble=1 -@end example - -matches all messages with @samp{wibble} in their path and in their subject -line, allowing up to 1 error in each case (the errors may be different for a -particular message.) - -Path expressions always use substring matches and never exact matches (it's -very unlikely you want to type in the whole of a message path as a search -expression!) The matches are always @b{case-sensitive}. (All matches on words -within messages are case-insensitive.) There is a limit of 32 characters on -the match expression. - -@end itemize - -The binding order of the constructions is: - -@enumerate -@item Individual command line arguments define separate conditions which are -AND-ed together - -@item Within a single argument, the letters before the colon define which -message parts the expression applies to. If there is no colon, the expression -applies to all the headers listed earlier and the body. - -@item After the colon, commas delineate separate disjuncts, which are OR-ed together. - -@item Each disjunct may contain separate conjuncts, which are separated by plus -signs. These conditions are AND-ed together. - -@item Each conjunct may start with a tilde to negate it, and may be followed by -a slash to indicate a substring match, optionally followed by an integer to -define the maximum number of errors allowed. - -@end enumerate - -Now some examples. Suppose my email address is @email{richard@@doesnt.exist}. - -The following will match all messages newer than 3 months from me with the word -@samp{chrony} in the subject line: - -@example -mairix d:3m- f:richard+doesnt+exist s:chrony -@end example - -Suppose I don't mind a few spurious matches on the address, I want a wider date -range, and I suspect that some messages I replied to might have had the subject -keyword spelt wrongly (let's allow up to 2 errors): - -@example -mairix d:6m- f:richard s:chrony=2 -@end example - -@node date_syntax -@section Syntax used for specifying dates -This section describes the syntax used for specifying dates when searching -using the @samp{d:} option. - -Dates are specified as a range. The start and end of the range can both be -specified. Alternatively, if the start is omitted, it is treated as being the -beginning of time. If the end is omitted, it is treated as the current time. - -There are 4 basic formats: -@table @samp -@item d:start-end -Specify both start and end explicitly -@item d:start- -Specify start, end is the current time -@item d:-end -Specify end, start is 'a long time ago' (i.e. early enough to include any message). -@item d:period -Specify start and end implicitly, as the start and end of the period given. -@end table - -The start and end can be specified either absolute or relative. A relative -endpoint is given as a number followed by a single letter defining the scaling: - -@multitable @columnfractions 0.15 0.2 0.2 0.45 -@item @b{letter} @tab @b{meaning} @tab @b{example} @tab @b{meaning} -@item d @tab days @tab 3d @tab 3 days -@item w @tab weeks @tab 2w @tab 2 weeks (14 days) -@item m @tab months @tab 5m @tab 5 months (150 days) -@item y @tab years @tab 4y @tab 4 years (4*365 days) -@end multitable - -Months are always treated as 30 days, and years as 365 days, for this purpose. - -Absolute times can be specified in a lot of forms. Some forms have different -meanings when they define a start date from that when they define an end date. -Where a single expression specifies both the start and end (i.e. where the -argument to d: doesn't contain a @samp{-}), it will usually have different -interpretations in the two cases. - -In the examples below, suppose the current date is Sunday May 18th, 2003 (when -I started to write this material.) - -@multitable @columnfractions 0.24 0.24 0.24 0.28 -@item @b{Example} @tab @b{Start date} @tab @b{End date} @tab @b{Notes} -@item d:20030301@minus{}20030425 @tab March 1st, 2003 @tab 25th April, 2003 -@item d:030301@minus{}030425 @tab March 1st, 2003 @tab April 25th, 2003 @tab century assumed -@item d:mar1@minus{}apr25 @tab March 1st, 2003 @tab April 25th, 2003 -@item d:Mar1@minus{}Apr25 @tab March 1st, 2003 @tab April 25th, 2003 @tab case insensitive -@item d:MAR1@minus{}APR25 @tab March 1st, 2003 @tab April 25th, 2003 @tab case insensitive -@item d:1mar@minus{}25apr @tab March 1st, 2003 @tab April 25th, 2003 @tab date and month in either order -@item d:2002 @tab January 1st, 2002 @tab December 31st, 2002 @tab whole year -@item d:mar @tab March 1st, 2003 @tab March 31st, 2003 @tab most recent March -@item d:oct @tab October 1st, 2002 @tab October 31st, 2002 @tab most recent October -@item d:21oct@minus{}mar @tab October 21st, 2002 @tab March 31st, 2003 @tab start before end -@item d:21apr@minus{}mar @tab April 21st, 2002 @tab March 31st, 2003 @tab start before end -@item d:21apr@minus{} @tab April 21st, 2003 @tab May 18th, 2003 @tab end omitted -@item d:@minus{}21apr @tab January 1st, 1900 @tab April 21st, 2003 @tab start omitted -@item d:6w@minus{}2w @tab April 6th, 2003 @tab May 4th, 2003 @tab both dates relative -@item d:21apr@minus{}1w @tab April 21st, 2003 @tab May 11th, 2003 @tab one date relative -@item d:21apr@minus{}2y @tab April 21st, 2001 @tab May 11th, 2001 @tab start before end -@item d:99@minus{}11 @tab January 1st, 1999 @tab May 11th, 2003 @tab 2 digits are a day of the month if possible, otherwise a year -@item d:99oct@minus{}1oct @tab October 1st, 1999 @tab October 1st, 2002 @tab end before now, single digit is a day of the month -@item d:99oct@minus{}01oct @tab October 1st, 1999 @tab October 31st, 2001 @tab 2 digits starting with zero treated as a year -@item d:oct99@minus{}oct1 @tab October 1st, 1999 @tab October 1st, 2002 @tab day and month in either order -@item d:oct99@minus{}oct01 @tab October 1st, 1999 @tab October 31st, 2001 @tab year and month in either order -@end multitable - -The principles in the table work as follows. -@itemize @bullet -@item -When the expression defines a period of more than a day (i.e. if a month or -year is specified), the earliest day in the period is taken when the start date -is defined, and the last day in the period if the end of the range is being -defined. -@item -The end date is always taken to be on or before the current date. -@item -The start date is always taken to be on or before the end date. -@end itemize - -@bye -@c vim:cms=@c\ %s:fdm=marker:fdc=5:syntax=off diff --git a/src/mairix/reader.c b/src/mairix/reader.c @@ -1,212 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002,2003,2004,2005 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -/* Database reader */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <assert.h> -#include <sys/mman.h> - -#include "reader.h" -#include "memmac.h" -#include "mairix.h" - -int read_increment(unsigned char **encpos) {/*{{{*/ - unsigned char *j = *encpos; - int result; - unsigned char x0, x1, x2, x3; - - x0 = *j++; - if ((x0 & 0xc0) == 0xc0) { - /* 4 byte encoding */ - x1 = *j++; - x2 = *j++; - x3 = *j++; - result = ((x0 & 0x3f) << 24) + (x1 << 16) + (x2 << 8) + x3; - } else if (x0 & 0x80) { - /* 2 byte encoding */ - x1 = *j++; - result = ((x0 & 0x7f) << 8) + x1; - } else { - /* Single byte encoding */ - result = x0; - } - - *encpos = j; - return result; -} -/*}}}*/ -static void read_toktable_db(char *data, struct toktable_db *toktable, int start, unsigned int *uidata)/*{{{*/ -{ - int n; - n = toktable->n = uidata[start]; - toktable->tok_offsets = uidata + uidata[start+1]; - toktable->enc_offsets = uidata + uidata[start+2]; - return; -} -/*}}}*/ -static void read_toktable2_db(char *data, struct toktable2_db *toktable, int start, unsigned int *uidata)/*{{{*/ -{ - int n; - n = toktable->n = uidata[start]; - toktable->tok_offsets = uidata + uidata[start+1]; - toktable->enc0_offsets = uidata + uidata[start+2]; - toktable->enc1_offsets = uidata + uidata[start+3]; - return; -} -/*}}}*/ -struct read_db *open_db(char *filename)/*{{{*/ -{ - int fd, len; - char *data; - struct stat sb; - struct read_db *result; - unsigned int *uidata; - unsigned char *ucdata; - - fd = open(filename, O_RDONLY); - if (fd < 0) { - report_error("open", filename); - unlock_and_exit (2); - } - - if (fstat(fd, &sb) < 0) { - report_error("stat", filename); - unlock_and_exit(2); - } - - len = sb.st_size; - - data = (char *) mmap(0, len, PROT_READ, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) { - report_error("reader:mmap", filename); - unlock_and_exit(2); - } - - if (!data) { - /* Empty file opened => database corrupt for sure */ - if (close(fd) < 0) { - report_error("close", filename); - unlock_and_exit(2); - } - return NULL; - } - - if (close(fd) < 0) { - report_error("close", filename); - unlock_and_exit(2); - } - - result = new(struct read_db); - uidata = (unsigned int *) data; /* alignment is assured */ - ucdata = (unsigned char *) data; - result->len = len; - result->data = data; - - /*{{{ Magic number check */ - if (ucdata[0] == HEADER_MAGIC0 || - ucdata[1] == HEADER_MAGIC1 || - ucdata[2] == HEADER_MAGIC2) { - if (ucdata[3] != HEADER_MAGIC3) { - fprintf(stderr, "Another version of this program produced the existing database! Please rebuild.\n"); - unlock_and_exit(2); - } - } else { - fprintf(stderr, "The existing database wasn't produced by this program! Please rebuild.\n"); - unlock_and_exit(2); - } - /*}}}*/ - /* {{{ Endianness check */ - if (uidata[UI_ENDIAN] == 0x11223344) { - fprintf(stderr, "The endianness of the database is reversed for this machine\n"); - unlock_and_exit(2); - } else if (uidata[UI_ENDIAN] != 0x44332211) { - fprintf(stderr, "The endianness of this machine is strange (or database is corrupt)\n"); - unlock_and_exit(2); - } - /* }}} */ - - /* Now build tables of where things are in the file */ - result->n_msgs = uidata[UI_N_MSGS]; - result->msg_type_and_flags = ucdata + uidata[UI_MSG_TYPE_AND_FLAGS]; - result->path_offsets = uidata + uidata[UI_MSG_CDATA]; - result->mtime_table = uidata + uidata[UI_MSG_MTIME]; - result->size_table = uidata + uidata[UI_MSG_SIZE]; - result->date_table = uidata + uidata[UI_MSG_DATE]; - result->tid_table = uidata + uidata[UI_MSG_TID]; - - result->n_mboxen = uidata[UI_MBOX_N]; - result->mbox_paths_table = uidata + uidata[UI_MBOX_PATHS]; - result->mbox_entries_table = uidata + uidata[UI_MBOX_ENTRIES]; - result->mbox_mtime_table = uidata + uidata[UI_MBOX_MTIME]; - result->mbox_size_table = uidata + uidata[UI_MBOX_SIZE]; - result->mbox_checksum_table = uidata + uidata[UI_MBOX_CKSUM]; - - result->hash_key = uidata[UI_HASH_KEY]; - - read_toktable_db(data, &result->to, UI_TO_BASE, uidata); - read_toktable_db(data, &result->cc, UI_CC_BASE, uidata); - read_toktable_db(data, &result->from, UI_FROM_BASE, uidata); - read_toktable_db(data, &result->subject, UI_SUBJECT_BASE, uidata); - read_toktable_db(data, &result->body, UI_BODY_BASE, uidata); - read_toktable_db(data, &result->attachment_name, UI_ATTACHMENT_NAME_BASE, uidata); - read_toktable2_db(data, &result->msg_ids, UI_MSGID_BASE, uidata); - - return result; -} -/*}}}*/ -static void free_toktable_db(struct toktable_db *x)/*{{{*/ -{ - /* Nothing to do */ -} -/*}}}*/ -static void free_toktable2_db(struct toktable2_db *x)/*{{{*/ -{ - /* Nothing to do */ -} -/*}}}*/ -void close_db(struct read_db *x)/*{{{*/ -{ - free_toktable_db(&x->to); - free_toktable_db(&x->cc); - free_toktable_db(&x->from); - free_toktable_db(&x->subject); - free_toktable_db(&x->body); - free_toktable_db(&x->attachment_name); - free_toktable2_db(&x->msg_ids); - - if (munmap(x->data, x->len) < 0) { - perror("munmap"); - unlock_and_exit(2); - } - free(x); - return; -} -/*}}}*/ - diff --git a/src/mairix/reader.h b/src/mairix/reader.h @@ -1,182 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002-2004,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#ifndef READER_H -#define READER_H - -/* MX, then a high byte, then the version no. */ -#define HEADER_MAGIC0 'M' -#define HEADER_MAGIC1 'X' -#define HEADER_MAGIC2 0xA5 -#define HEADER_MAGIC3 0x03 - -/*{{{ Constants for file data positions */ -#define UI_ENDIAN 1 -#define UI_N_MSGS 2 - -/* Offset to byte-per-message table encoding message types */ -#define UI_MSG_TYPE_AND_FLAGS 3 - -/* Header positions containing offsets to the per-message tables. */ -/* Character data: - * for maildir/MH : the path of the box. - * for mbox : index of mbox containing the message */ - -#define UI_MSG_CDATA 4 -/* For maildir/MH : mtime of file containing message */ -#define UI_MSG_MTIME 5 -/* For mbox msgs : the offset into the file */ -#define UI_MSG_OFFSET 5 -/* For all formats : message size */ -#define UI_MSG_SIZE 6 -/* For mbox msgs : offset into file */ -#define UI_MSG_START 6 -/* These are common to Maildir,MH,mbox messages */ -#define UI_MSG_DATE 7 -#define UI_MSG_TID 8 - -/* Header positions for mbox (file-level) information */ -/* Number of mboxes */ -#define UI_MBOX_N 9 -#define UI_MBOX_PATHS 10 -#define UI_MBOX_ENTRIES 11 -/* mtime of mboxes */ -#define UI_MBOX_MTIME 12 -/* Size in bytes */ -#define UI_MBOX_SIZE 13 -/* Base of checksums for messages in each mbox */ -#define UI_MBOX_CKSUM 14 - -#define UI_HASH_KEY 15 - -/* Header positions for token tables */ -#define UI_TO_BASE 16 -#define UI_CC_BASE 19 -#define UI_FROM_BASE 22 -#define UI_SUBJECT_BASE 25 -#define UI_BODY_BASE 28 -#define UI_ATTACHMENT_NAME_BASE 31 -#define UI_MSGID_BASE 34 - -/* Larger than the last table offset. */ -#define UI_HEADER_LEN 40 -#define UC_HEADER_LEN ((UI_HEADER_LEN) << 2) - -#define UI_N_OFFSET 0 -#define UI_TOK_OFFSET 1 -#define UI_ENC_OFFSET 2 - -#define UI_TO_N (UI_TO_BASE + UI_N_OFFSET) -#define UI_TO_TOK (UI_TO_BASE + UI_TOK_OFFSET) -#define UI_TO_ENC (UI_TO_BASE + UI_ENC_OFFSET) -#define UI_CC_N (UI_CC_BASE + UI_N_OFFSET) -#define UI_CC_TOK (UI_CC_BASE + UI_TOK_OFFSET) -#define UI_CC_ENC (UI_CC_BASE + UI_ENC_OFFSET) -#define UI_FROM_N (UI_FROM_BASE + UI_N_OFFSET) -#define UI_FROM_TOK (UI_FROM_BASE + UI_TOK_OFFSET) -#define UI_FROM_ENC (UI_FROM_BASE + UI_ENC_OFFSET) -#define UI_SUBJECT_N (UI_SUBJECT_BASE + UI_N_OFFSET) -#define UI_SUBJECT_TOK (UI_SUBJECT_BASE + UI_TOK_OFFSET) -#define UI_SUBJECT_ENC (UI_SUBJECT_BASE + UI_ENC_OFFSET) -#define UI_BODY_N (UI_BODY_BASE + UI_N_OFFSET) -#define UI_BODY_TOK (UI_BODY_BASE + UI_TOK_OFFSET) -#define UI_BODY_ENC (UI_BODY_BASE + UI_ENC_OFFSET) -#define UI_ATTACHMENT_NAME_N (UI_ATTACHMENT_NAME_BASE + UI_N_OFFSET) -#define UI_ATTACHMENT_NAME_TOK (UI_ATTACHMENT_NAME_BASE + UI_TOK_OFFSET) -#define UI_ATTACHMENT_NAME_ENC (UI_ATTACHMENT_NAME_BASE + UI_ENC_OFFSET) -#define UI_MSGID_N (UI_MSGID_BASE + UI_N_OFFSET) -#define UI_MSGID_TOK (UI_MSGID_BASE + UI_TOK_OFFSET) -#define UI_MSGID_ENC0 (UI_MSGID_BASE + UI_ENC_OFFSET) -#define UI_MSGID_ENC1 (UI_MSGID_ENC0 + 1) - -/*}}}*/ - -/*{{{ Literals used for encoding messages types in database file */ -#define DB_MSG_DEAD 0 -/* maildir/MH : one file per message */ -#define DB_MSG_FILE 1 -/* mbox : multiple files per message */ -#define DB_MSG_MBOX 2 -/*}}}*/ - -#define FLAG_SEEN (1<<3) -#define FLAG_REPLIED (1<<4) -#define FLAG_FLAGGED (1<<5) - -struct toktable_db {/*{{{*/ - unsigned int n; /* number of entries in this table */ - unsigned int *tok_offsets; /* offset to table of token offsets */ - unsigned int *enc_offsets; /* offset to table of encoding offsets */ -}; -/*}}}*/ -struct toktable2_db {/*{{{*/ - unsigned int n; /* number of entries in this table */ - unsigned int *tok_offsets; /* offset to table of token offsets */ - unsigned int *enc0_offsets; /* offset to table of encoding offsets */ - unsigned int *enc1_offsets; /* offset to table of encoding offsets */ -}; -/*}}}*/ -struct read_db {/*{{{*/ - /* Raw file parameters, needed later for munmap */ - char *data; - int len; - - /* Pathname information */ - int n_msgs; - unsigned char *msg_type_and_flags; - unsigned int *path_offsets; /* or (mbox index, msg index) */ - unsigned int *mtime_table; /* or offset into mbox */ - unsigned int *size_table; /* either file size or span inside mbox */ - unsigned int *date_table; - unsigned int *tid_table; - - int n_mboxen; - unsigned int *mbox_paths_table; - unsigned int *mbox_entries_table; /* table of number of messages per mbox */ - unsigned int *mbox_mtime_table; - unsigned int *mbox_size_table; - unsigned int *mbox_checksum_table; - - unsigned int hash_key; - - struct toktable_db to; - struct toktable_db cc; - struct toktable_db from; - struct toktable_db subject; - struct toktable_db body; - struct toktable_db attachment_name; - struct toktable2_db msg_ids; - -}; -/*}}}*/ - -struct read_db *open_db(char *filename); -void close_db(struct read_db *x); - -static inline int rd_msg_type(struct read_db *db, int i) { - return db->msg_type_and_flags[i] & 0x7; -} - -/* Common to search and db reader. */ -int read_increment(unsigned char **encpos); - -#endif /* READER_H */ diff --git a/src/mairix/rfc822.c b/src/mairix/rfc822.c @@ -1,1536 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002,2003,2004,2005,2006,2007,2010 - * rfc2047 decode: - * Copyright (C) Mikael Ylikoski 2002 - * gzip mbox support: - * Copyright (C) Ico Doornekamp 2005 - * Copyright (C) Felipe Gustavo de Almeida 2005 - * bzip2 mbox support: - * Copyright (C) Paramjit Oberoi 2005 - * caching uncompressed mbox data: - * Copyright (C) Chris Mason 2006 - * memory leak fixes: - * Copyright (C) Samuel Tardieu 2008 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "mairix.h" -#include "nvp.h" - -#include <assert.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/mman.h> -#ifdef USE_GZIP_MBOX -# include <zlib.h> -#endif -#ifdef USE_BZIP_MBOX -# include <bzlib.h> -#endif - -struct DLL {/*{{{*/ - struct DLL *next; - struct DLL *prev; -}; -/*}}}*/ -static void enqueue(void *head, void *x)/*{{{*/ -{ - /* Declare this way so it can be used with any kind of double linked list - * having next & prev pointers in its first two words. */ - struct DLL *h = (struct DLL *) head; - struct DLL *xx = (struct DLL *) x; - xx->next = h; - xx->prev = h->prev; - h->prev->next = xx; - h->prev = xx; - return; -} -/*}}}*/ - -enum encoding_type {/*{{{*/ - ENC_UNKNOWN, - ENC_NONE, - ENC_BINARY, - ENC_7BIT, - ENC_8BIT, - ENC_QUOTED_PRINTABLE, - ENC_BASE64, - ENC_UUENCODE -}; -/*}}}*/ -struct content_type_header {/*{{{*/ - const char *major; /* e.g. text */ - const char *minor; /* e.g. plain */ - const char *boundary; /* for multipart */ - /* charset? */ -}; -/*}}}*/ -struct line {/*{{{*/ - struct line *next; - struct line *prev; - char *text; -}; -/*}}}*/ - -static void init_headers(struct headers *hdrs)/*{{{*/ -{ - hdrs->to = NULL; - hdrs->cc = NULL; - hdrs->from = NULL; - hdrs->subject = NULL; - hdrs->message_id = NULL; - hdrs->in_reply_to = NULL; - hdrs->references = NULL; - hdrs->date = 0; - hdrs->flags.seen = 0; - hdrs->flags.replied = 0; - hdrs->flags.flagged = 0; -}; -/*}}}*/ -static void splice_header_lines(struct line *header)/*{{{*/ -{ - /* Deal with newline then tab in header */ - struct line *x, *next; - for (x=header->next; x!=header; x=next) { -#if 0 - printf("next header, x->text=%08lx\n", x->text); - printf("header=<%s>\n", x->text); -#endif - next = x->next; - if (isspace(x->text[0] & 0xff)) { - /* Glue to previous line */ - char *p, *newbuf, *oldbuf; - struct line *y; - for (p=x->text; *p; p++) { - if (!isspace(*(unsigned char *)p)) break; - } - p--; /* point to final space */ - y = x->prev; -#if 0 - printf("y=%08lx p=%08lx\n", y->text, p); -#endif - newbuf = new_array(char, strlen(y->text) + strlen(p) + 1); - strcpy(newbuf, y->text); - strcat(newbuf, p); - oldbuf = y->text; - y->text = newbuf; - free(oldbuf); - y->next = x->next; - x->next->prev = y; - free(x->text); - free(x); - } - } - return; -} -/*}}}*/ -static int audit_header(struct line *header)/*{{{*/ -{ - /* Check for obvious broken-ness - * 1st line has no leading spaces, single word then colon - * following lines have leading spaces or single word followed by colon - * */ - struct line *x; - int first=1; - int count=1; - for (x=header->next; x!=header; x=x->next) { - int has_leading_space=0; - int is_blank; - int has_word_colon=0; - - if (1 || first) { - /* Ignore any UUCP or mbox style From line at the start */ - if (!strncmp("From ", x->text, 5)) { - continue; - } - /* Ignore escaped From line at the start */ - if (!strncmp(">From ", x->text, 6)) { - continue; - } - } - - is_blank = !(x->text[0]); - if (!is_blank) { - char *p; - int saw_char = 0; - has_leading_space = isspace(x->text[0] & 0xff); - has_word_colon = 0; /* default */ - p = x->text; - while(*p) { - if(*p == ':') { - has_word_colon = saw_char; - break; - } else if (isspace(*(unsigned char *) p)) { - has_word_colon = 0; - break; - } else { - saw_char = 1; - } - p++; - } - } - - if (( first && (is_blank || has_leading_space || !has_word_colon)) || - (!first && (is_blank || !(has_leading_space || has_word_colon)))) { -#if 0 - fprintf(stderr, "Header line %d <%s> fails because:", count, x->text); - if (first && is_blank) { fprintf(stderr, " [first && is_blank]"); } - if (first && has_leading_space) { fprintf(stderr, " [first && has_leading_space]"); } - if (first && !has_word_colon) { fprintf(stderr, " [first && !has_word_colon]"); } - if (!first && is_blank) { fprintf(stderr, " [!first && is_blank]"); } - if (!first && !(has_leading_space||has_word_colon)) { fprintf(stderr, " [!first && !has_leading_space||has_word_colon]"); } - fprintf(stderr, "\n"); -#endif - /* Header fails the audit */ - return 0; - } - first = 0; - count++; - } - /* If we get here the header must have been OK */ - return 1; -}/*}}}*/ -static int match_string(const char *ref, const char *candidate)/*{{{*/ -{ - int len = strlen(ref); - return !strncasecmp(ref, candidate, len); -} -/*}}}*/ - -static char equal_table[] = {/*{{{*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00-0f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10-1f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20-2f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 30-3f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40-4f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50-5f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60-6f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70-7f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80-8f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90-9f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a0-af */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b0-bf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c0-cf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d0-df */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e0-ef */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* f0-ff */ -}; -/*}}}*/ -static int base64_table[] = {/*{{{*/ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00-0f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10-1f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 20-2f */ - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, /* 30-3f */ - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 40-4f */ - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 50-5f */ - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 60-6f */ - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 70-7f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80-8f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90-9f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a0-af */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b0-bf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c0-cf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d0-df */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0-ef */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* f0-ff */ -}; -/*}}}*/ -static int hex_to_val(char x) {/*{{{*/ - switch (x) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return (x - '0'); - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - return 10 + (x - 'a'); - break; - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - return 10 + (x - 'A'); - break; - default: - return 0; - } -} -/*}}}*/ -static void decode_header_value(char *text){/*{{{*/ - /* rfc2047 decode, written by Mikael Ylikoski */ - - char *s, *a, *b, *e, *p, *q; - - for (p = q = s = text; (s = strstr(s, "=?")); s = e + 2) { - if (p == q) - p = q = s; - else - while (q != s) - *p++ = *q++; - s += 2; - a = strchr(s, '?'); - if (!a) break; - a++; - b = strchr(a, '?'); - if (!b) break; - b++; - e = strstr(b, "?="); - if (!e) break; - /* have found an encoded-word */ - if (b - a != 2) - continue; /* unknown encoding */ - if (*a == 'q' || *a == 'Q') { - int val; - q = b; - while (q < e) { - if (*q == '_') { - *p++ = 0x20; - q++; - } else if (*q == '=') { - q++; - val = hex_to_val(*q++) << 4; - val += hex_to_val(*q++); - *p++ = val; - } else - *p++ = *q++; - } - } else if (*a == 'b' || *a == 'B') { - int reg, nc, eq; /* register, #characters in reg, #equals */ - int dc; /* decoded character */ - eq = reg = nc = 0; - for (q = b; q < e; q++) { - unsigned char cq = *(unsigned char *)q; - dc = base64_table[cq]; - eq += equal_table[cq]; - - if (dc >= 0) { - reg <<= 6; - reg += dc; - nc++; - if (nc == 4) { - *p++ = ((reg >> 16) & 0xff); - if (eq < 2) *p++ = ((reg >> 8) & 0xff); - if (eq < 1) *p++ = reg & 0xff; - nc = reg = 0; - if (eq) break; - } - } - } - } else { - continue; /* unknown encoding */ - } - q = e + 2; - } - if (p == q) return; - while (*q != '\0') - *p++ = *q++; - *p = '\0'; -} -/*}}}*/ -static char *copy_header_value(char *text){/*{{{*/ - char *p; - for (p = text; *p && (*p != ':'); p++) ; - if (!*p) return NULL; - p++; - p = new_string(p); - decode_header_value(p); - return p; -} -/*}}}*/ -static void copy_or_concat_header_value(char **previous, char *text){/*{{{*/ - char *p = copy_header_value(text); - if (*previous) - { - *previous = extend_string(*previous, ", "); - *previous = extend_string(*previous, p); - free(p); - } - else - *previous = p; -} -/*}}}*/ -static enum encoding_type decode_encoding_type(const char *e)/*{{{*/ -{ - enum encoding_type result; - const char *p; - if (!e) { - result = ENC_NONE; - } else { - for (p=e; *p && isspace(*(unsigned char *)p); p++) ; - if ( match_string("7bit", p) - || match_string("7-bit", p) - || match_string("7 bit", p)) { - result = ENC_7BIT; - } else if (match_string("8bit", p) - || match_string("8-bit", p) - || match_string("8 bit", p)) { - result = ENC_8BIT; - } else if (match_string("quoted-printable", p)) { - result = ENC_QUOTED_PRINTABLE; - } else if (match_string("base64", p)) { - result = ENC_BASE64; - } else if (match_string("binary", p)) { - result = ENC_BINARY; - } else if (match_string("x-uuencode", p)) { - result = ENC_UUENCODE; - } else { - fprintf(stderr, "Warning: unknown encoding type: '%s'\n", e); - result = ENC_UNKNOWN; - } - } - return result; -} -/*}}}*/ -static void parse_content_type(struct nvp *ct_nvp, struct content_type_header *result)/*{{{*/ -{ - result->major = NULL; - result->minor = NULL; - result->boundary = NULL; - - result->major = nvp_major(ct_nvp); - if (result->major) { - result->minor = nvp_minor(ct_nvp); - } else { - result->minor = NULL; - result->major = nvp_first(ct_nvp); - } - - result->boundary = nvp_lookupcase(ct_nvp, "boundary"); -} - -/*}}}*/ -static char *looking_at_ws_then_newline(char *start)/*{{{*/ -{ - char *result; - result = start; - do { - if (*result == '\n') return result; - else if (!isspace(*(unsigned char *) result)) return NULL; - else result++; - } while (1); - - /* Can't get here */ - assert(0); -} -/*}}}*/ - -static char *unencode_data(struct msg_src *src, char *input, int input_len, const char *enc, int *output_len)/*{{{*/ -{ - enum encoding_type encoding; - char *result, *end_result; - char *end_input; - - encoding = decode_encoding_type(enc); - end_input = input + input_len; - - /* All mime encodings result in expanded data, so this is guaranteed to - * safely oversize the output array */ - result = new_array(char, input_len + 1); - - /* Now decode */ - switch (encoding) { - case ENC_7BIT:/*{{{*/ - case ENC_8BIT: - case ENC_BINARY: - case ENC_NONE: - { - memcpy(result, input, input_len); - end_result = result + input_len; - } - break; -/*}}}*/ - case ENC_QUOTED_PRINTABLE:/*{{{*/ - { - char *p, *q; - p = result; - for (p=result, q=input; - q<end_input; ) { - - if (*q == '=') { - /* followed by optional whitespace then \n? discard them. */ - char *r; - int val; - q++; - r = looking_at_ws_then_newline(q); - if (r) { - q = r + 1; /* Point into next line */ - continue; - } - /* not that case. */ - val = hex_to_val(*q++) << 4; - val += hex_to_val(*q++); - *p++ = val; - - } else { - /* Normal character */ - *p++ = *q++; - } - } - end_result = p; - } - break; -/*}}}*/ - case ENC_BASE64:/*{{{*/ - { - char *p, *q; - int reg, nc, eq; /* register, #characters in reg, #equals */ - int dc; /* decoded character */ - eq = reg = nc = 0; - for (q=input, p=result; q<end_input; q++) { - unsigned char cq = * (unsigned char *)q; - /* Might want a 256 entry array instead of this sub-optimal mess - * eventually. */ - dc = base64_table[cq]; - eq += equal_table[cq]; - - if (dc >= 0) { - reg <<= 6; - reg += dc; - nc++; - if (nc == 4) { - *p++ = ((reg >> 16) & 0xff); - if (eq < 2) *p++ = ((reg >> 8) & 0xff); - if (eq < 1) *p++ = reg & 0xff; - nc = reg = 0; - if (eq) goto done_base_64; - } - } - } - done_base_64: - end_result = p; - } - break; - /*}}}*/ - case ENC_UUENCODE:/*{{{*/ - { - char *p, *q; - /* Find 'begin ' */ - for (q = input; q < end_input - 6 && memcmp(q, "begin ", 6); q++) - ; - q += 6; - /* skip to EOL */ - while (q < end_input && *q != '\n') - q++; - p = result; - while (q < end_input) { /* process line */ -#define DEC(c) (((c) - ' ') & 077) - int len = DEC(*q++); - if (len == 0) - break; - for (; len > 0; q += 4, len -= 3) { - if (len >= 3) { - *p++ = DEC(q[0]) << 2 | DEC(q[1]) >> 4; - *p++ = DEC(q[1]) << 4 | DEC(q[2]) >> 2; - *p++ = DEC(q[2]) << 6 | DEC(q[3]); - } else { - if (len >= 1) - *p++ = DEC(q[0]) << 2 | DEC(q[1]) >> 4; - if (len >= 2) - *p++ = DEC(q[1]) << 4 | DEC(q[2]) >> 2; - } - } - while (q < end_input && *q != '\n') - q++; - } - end_result = p; - } - break; - /*}}}*/ - case ENC_UNKNOWN:/*{{{*/ - fprintf(stderr, "Unknown encoding type in %s\n", format_msg_src(src)); - /* fall through - ignore this data */ - /*}}}*/ - default:/*{{{*/ - end_result = result; - break; - /*}}}*/ - } - *output_len = end_result - result; - result[*output_len] = '\0'; /* for convenience with text/plain etc to make it printable */ - return result; -} -/*}}}*/ -char *format_msg_src(struct msg_src *src)/*{{{*/ -{ - static char *buffer = NULL; - static int buffer_len = 0; - char *result; - int len; - switch (src->type) { - case MS_FILE: - result = src->filename; - break; - case MS_MBOX: - len = strlen(src->filename); - len += 32; - if (!buffer || (len > buffer_len)) { - free(buffer); - buffer = new_array(char, len); - buffer_len = len; - } - sprintf(buffer, "%s[%d,%d)", src->filename, - (int) src->start, (int) (src->start + src->len)); - result = buffer; - break; - default: - result = NULL; - break; - } - return result; -} -/*}}}*/ -static int split_and_splice_header(struct msg_src *src, char *data, struct line *header, char **body_start)/*{{{*/ -{ - char *sol, *eol; - int blank_line; - header->next = header->prev = header; - sol = data; - do { - if (!*sol) break; - blank_line = 1; /* until proven otherwise */ - eol = sol; - while (*eol && (*eol != '\n')) { - if (!isspace(*(unsigned char *) eol)) blank_line = 0; - eol++; - } - if (*eol == '\n') { - if (!blank_line) { - int line_length = eol - sol; - char *line_text = new_array(char, 1 + line_length); - struct line *new_header; - - strncpy(line_text, sol, line_length); - line_text[line_length] = '\0'; - new_header = new(struct line); - new_header->text = line_text; - enqueue(header, new_header); - } - sol = eol + 1; /* Start of next line */ - } else { /* must be null char */ - fprintf(stderr, "Got null character whilst processing header of %s\n", - format_msg_src(src)); - return -1; /* & leak memory */ - } - } while (!blank_line); - - *body_start = sol; - - if (audit_header(header)) { - splice_header_lines(header); - return 0; - } else { -#if 0 - /* Caller generates message */ - fprintf(stderr, "Message had bad rfc822 headers, ignoring\n"); -#endif - return -1; - } -} -/*}}}*/ - -/* Forward prototypes */ -static void do_multipart(struct msg_src *src, char *input, int input_len, - const char *boundary, struct attachment *atts, - enum data_to_rfc822_error *error); - -/*{{{ do_body() */ -static void do_body(struct msg_src *src, - char *body_start, int body_len, - struct nvp *ct_nvp, struct nvp *cte_nvp, - struct nvp *cd_nvp, - struct attachment *atts, - enum data_to_rfc822_error *error) -{ - char *decoded_body; - int decoded_body_len; - const char *content_transfer_encoding; - content_transfer_encoding = NULL; - if (cte_nvp) { - content_transfer_encoding = nvp_first(cte_nvp); - if (!content_transfer_encoding) { - fprintf(stderr, "Giving up on %s, content_transfer_encoding header not parseable\n", - format_msg_src(src)); - return; - } - } - - decoded_body = unencode_data(src, body_start, body_len, content_transfer_encoding, &decoded_body_len); - - if (ct_nvp) { - struct content_type_header ct; - parse_content_type(ct_nvp, &ct); - if (ct.major && !strcasecmp(ct.major, "multipart")) { - do_multipart(src, decoded_body, decoded_body_len, ct.boundary, atts, error); - /* Don't need decoded body any longer - copies have been taken if - * required when handling multipart attachments. */ - free(decoded_body); - if (error && (*error == DTR8_MISSING_END)) return; - } else { - /* unipart */ - struct attachment *new_att; - const char *disposition; - new_att = new(struct attachment); - disposition = cd_nvp ? nvp_first(cd_nvp) : NULL; - if (disposition && !strcasecmp(disposition, "attachment")) { - const char *lookup; - lookup = nvp_lookupcase(cd_nvp, "filename"); - if (lookup) { - new_att->filename = new_string(lookup); - } else { - /* Some messages have name=... in content-type: instead of - * filename=... in content-disposition. */ - lookup = nvp_lookup(ct_nvp, "name"); - if (lookup) { - new_att->filename = new_string(lookup); - } else { - new_att->filename = NULL; - } - } - } else { - new_att->filename = NULL; - } - if (ct.major && !strcasecmp(ct.major, "text")) { - if (ct.minor && !strcasecmp(ct.minor, "plain")) { - new_att->ct = CT_TEXT_PLAIN; - } else if (ct.minor && !strcasecmp(ct.minor, "html")) { - new_att->ct = CT_TEXT_HTML; - } else { - new_att->ct = CT_TEXT_OTHER; - } - } else if (ct.major && !strcasecmp(ct.major, "message") && - ct.minor && !strcasecmp(ct.minor, "rfc822")) { - new_att->ct = CT_MESSAGE_RFC822; - } else { - new_att->ct = CT_OTHER; - } - - if (new_att->ct == CT_MESSAGE_RFC822) { - new_att->data.rfc822 = data_to_rfc822(src, decoded_body, decoded_body_len, error); - free(decoded_body); /* data no longer needed */ - } else { - new_att->data.normal.len = decoded_body_len; - new_att->data.normal.bytes = decoded_body; - } - enqueue(atts, new_att); - } - } else { - /* Treat as text/plain {{{*/ - struct attachment *new_att; - new_att = new(struct attachment); - new_att->filename = NULL; - new_att->ct = CT_TEXT_PLAIN; - new_att->data.normal.len = decoded_body_len; - /* Add null termination on the end */ - new_att->data.normal.bytes = new_array(char, decoded_body_len + 1); - memcpy(new_att->data.normal.bytes, decoded_body, decoded_body_len + 1); - free(decoded_body); - enqueue(atts, new_att);/*}}}*/ - } -} -/*}}}*/ -/*{{{ do_attachment() */ -static void do_attachment(struct msg_src *src, - char *start, char *after_end, - struct attachment *atts) -{ - /* decode attachment and add to attachment list */ - struct line header, *x, *nx; - char *body_start; - int body_len; - - struct nvp *ct_nvp, *cte_nvp, *cd_nvp, *nvp; - - if (split_and_splice_header(src, start, &header, &body_start) < 0) { - fprintf(stderr, "Giving up on attachment with bad header in %s\n", - format_msg_src(src)); - return; - } - - /* Extract key headers */ - ct_nvp = cte_nvp = cd_nvp = NULL; - for (x=header.next; x!=&header; x=x->next) { - if ((nvp = make_nvp(src, x->text, "content-type:"))) { - ct_nvp = nvp; - } else if ((nvp = make_nvp(src, x->text, "content-transfer-encoding:"))) { - cte_nvp = nvp; - } else if ((nvp = make_nvp(src, x->text, "content-disposition:"))) { - cd_nvp = nvp; - } - } - -#if 0 - if (ct_nvp) { - fprintf(stderr, "======\n"); - fprintf(stderr, "Dump of content-type hdr\n"); - nvp_dump(ct_nvp, stderr); - free(ct_nvp); - } - - if (cte_nvp) { - fprintf(stderr, "======\n"); - fprintf(stderr, "Dump of content-transfer-encoding hdr\n"); - nvp_dump(cte_nvp, stderr); - free(cte_nvp); - } -#endif - - if (body_start > after_end) { - /* This is a (maliciously?) b0rken attachment, e.g. maybe empty */ - if (verbose) { - fprintf(stderr, "Message %s contains an invalid attachment, length=%d bytes\n", - format_msg_src(src), (int)(after_end - start)); - } - } else { - body_len = after_end - body_start; - /* Ignore errors in nested body parts. */ - do_body(src, body_start, body_len, ct_nvp, cte_nvp, cd_nvp, atts, NULL); - } - - /* Free header memory */ - for (x=header.next; x!=&header; x=nx) { - nx = x->next; - free(x->text); - free(x); - } - - if (ct_nvp) free_nvp(ct_nvp); - if (cte_nvp) free_nvp(cte_nvp); - if (cd_nvp) free_nvp(cd_nvp); -} -/*}}}*/ -/*{{{ do_multipart() */ -static void do_multipart(struct msg_src *src, - char *input, int input_len, - const char *boundary, - struct attachment *atts, - enum data_to_rfc822_error *error) -{ - char *b0, *b1, *be, *bx; - char *line_after_b0, *start_b1_search_from; - int boundary_len; - int looking_at_end_boundary; - - if (!boundary) { - fprintf(stderr, "Can't process multipart message %s with no boundary string\n", - format_msg_src(src)); - if (error) *error = DTR8_MULTIPART_SANS_BOUNDARY; - return; - } - - boundary_len = strlen(boundary); - - b0 = NULL; - line_after_b0 = input; - be = input + input_len; - - do { - int boundary_ok; - start_b1_search_from = line_after_b0; - do { - /* reject boundaries that aren't a whole line */ - b1 = NULL; - for (bx = start_b1_search_from; bx < be - (boundary_len + 4); bx++) { - if (bx[0] == '-' && bx[1] == '-' && - !strncmp(bx+2, boundary, boundary_len)) { - b1 = bx; - break; - } - } - if (!b1) { - if (error) - *error = DTR8_MISSING_END; - return; - } - - looking_at_end_boundary = (b1[boundary_len+2] == '-' && - b1[boundary_len+3] == '-'); - boundary_ok = 1; - if ((b1 > input) && (*(b1-1) != '\n')) - boundary_ok = 0; - if (!looking_at_end_boundary && (b1 + boundary_len + 2 < input + input_len) && (*(b1 + boundary_len + 2) != '\n')) - boundary_ok = 0; - if (!boundary_ok) { - char *eol = strchr(b1, '\n'); - if (!eol) { - fprintf(stderr, "Oops, didn't find another normal boundary in %s\n", - format_msg_src(src)); - return; - } - start_b1_search_from = 1 + eol; - } - } while (!boundary_ok); - - /* b1 is now looking at a good boundary, which might be the final one */ - - if (b0) { - /* don't treat preamble as an attachment */ - do_attachment(src, line_after_b0, b1, atts); - } - - b0 = b1; - line_after_b0 = strchr(b0, '\n'); - if (line_after_b0 == 0) - line_after_b0 = b0 + strlen(b0); - else - ++line_after_b0; - } while (b1 < be && !looking_at_end_boundary); -} -/*}}}*/ -static time_t parse_rfc822_date(char *date_string)/*{{{*/ -{ - struct tm tm; - char *s, *z; - /* Format [weekday ,] day-of-month month year hour:minute:second timezone. - - Some of the ideas, sanity checks etc taken from parse.c in the mutt - sources, credit to Michael R. Elkins et al - */ - - s = date_string; - z = strchr(s, ','); - if (z) s = z + 1; - while (*s && isspace(*s)) s++; - /* Should now be looking at day number */ - if (!isdigit(*s)) goto tough_cheese; - tm.tm_mday = atoi(s); - if (tm.tm_mday > 31) goto tough_cheese; - - while (isdigit(*s)) s++; - while (*s && isspace(*s)) s++; - if (!*s) goto tough_cheese; - if (!strncasecmp(s, "jan", 3)) tm.tm_mon = 0; - else if (!strncasecmp(s, "feb", 3)) tm.tm_mon = 1; - else if (!strncasecmp(s, "mar", 3)) tm.tm_mon = 2; - else if (!strncasecmp(s, "apr", 3)) tm.tm_mon = 3; - else if (!strncasecmp(s, "may", 3)) tm.tm_mon = 4; - else if (!strncasecmp(s, "jun", 3)) tm.tm_mon = 5; - else if (!strncasecmp(s, "jul", 3)) tm.tm_mon = 6; - else if (!strncasecmp(s, "aug", 3)) tm.tm_mon = 7; - else if (!strncasecmp(s, "sep", 3)) tm.tm_mon = 8; - else if (!strncasecmp(s, "oct", 3)) tm.tm_mon = 9; - else if (!strncasecmp(s, "nov", 3)) tm.tm_mon = 10; - else if (!strncasecmp(s, "dec", 3)) tm.tm_mon = 11; - else goto tough_cheese; - - while (!isspace(*s)) s++; - while (*s && isspace(*s)) s++; - if (!isdigit(*s)) goto tough_cheese; - tm.tm_year = atoi(s); - if (tm.tm_year < 70) { - tm.tm_year += 100; - } else if (tm.tm_year >= 1900) { - tm.tm_year -= 1900; - } - - while (isdigit(*s)) s++; - while (*s && isspace(*s)) s++; - if (!*s) goto tough_cheese; - - /* Now looking at hms */ - /* For now, forget this. The searching will be vague enough that nearest day is good enough. */ - - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = 0; - return mktime(&tm); - -tough_cheese: - return (time_t) -1; /* default value */ -} -/*}}}*/ - -static void scan_status_flags(const char *s, struct headers *hdrs)/*{{{*/ -{ - const char *p; - for (p=s; *p; p++) { - switch (*p) { - case 'R': hdrs->flags.seen = 1; break; - case 'A': hdrs->flags.replied = 1; break; - case 'F': hdrs->flags.flagged = 1; break; - default: break; - } - } -} -/*}}}*/ - -/*{{{ data_to_rfc822() */ -struct rfc822 *data_to_rfc822(struct msg_src *src, - char *data, int length, - enum data_to_rfc822_error *error) -{ - struct rfc822 *result; - char *body_start; - struct line header; - struct line *x, *nx; - struct nvp *ct_nvp, *cte_nvp, *cd_nvp, *nvp; - int body_len; - - if (error) *error = DTR8_OK; /* default */ - result = new(struct rfc822); - init_headers(&result->hdrs); - result->atts.next = result->atts.prev = &result->atts; - - if (split_and_splice_header(src, data, &header, &body_start) < 0) { - if (verbose) { - fprintf(stderr, "Giving up on message %s with bad header\n", - format_msg_src(src)); - } - if (error) *error = DTR8_BAD_HEADERS; - return NULL; - } - - /* Extract key headers {{{*/ - ct_nvp = cte_nvp = cd_nvp = NULL; - for (x=header.next; x!=&header; x=x->next) { - if (match_string("to", x->text)) - copy_or_concat_header_value(&result->hdrs.to, x->text); - else if (match_string("cc", x->text)) - copy_or_concat_header_value(&result->hdrs.cc, x->text); - else if (!result->hdrs.from && match_string("from", x->text)) - result->hdrs.from = copy_header_value(x->text); - else if (!result->hdrs.subject && match_string("subject", x->text)) - result->hdrs.subject = copy_header_value(x->text); - else if (!ct_nvp && (nvp = make_nvp(src, x->text, "content-type:"))) - ct_nvp = nvp; - else if (!cte_nvp && (nvp = make_nvp(src, x->text, "content-transfer-encoding:"))) - cte_nvp = nvp; - else if (!cd_nvp && (nvp = make_nvp(src, x->text, "content-disposition:"))) - cd_nvp = nvp; - else if (!result->hdrs.date && match_string("date", x->text)) { - char *date_string = copy_header_value(x->text); - result->hdrs.date = parse_rfc822_date(date_string); - free(date_string); - } else if (!result->hdrs.message_id && match_string("message-id", x->text)) - result->hdrs.message_id = copy_header_value(x->text); - else if (!result->hdrs.in_reply_to && match_string("in-reply-to", x->text)) - result->hdrs.in_reply_to = copy_header_value(x->text); - else if (!result->hdrs.references && match_string("references", x->text)) - result->hdrs.references = copy_header_value(x->text); - else if (match_string("status", x->text)) - scan_status_flags(x->text + sizeof("status:"), &result->hdrs); - else if (match_string("x-status", x->text)) - scan_status_flags(x->text + sizeof("x-status:"), &result->hdrs); - } -/*}}}*/ - - /* Process body */ - body_len = length - (body_start - data); - do_body(src, body_start, body_len, ct_nvp, cte_nvp, cd_nvp, &result->atts, error); - - /* Free header memory */ - for (x=header.next; x!=&header; x=nx) { - nx = x->next; - free(x->text); - free(x); - } - - if (ct_nvp) free_nvp(ct_nvp); - if (cte_nvp) free_nvp(cte_nvp); - if (cd_nvp) free_nvp(cd_nvp); - - return result; - -} -/*}}}*/ - -#define ALLOC_NONE 1 -#define ALLOC_MMAP 2 -#define ALLOC_MALLOC 3 - -int data_alloc_type; - -#if USE_GZIP_MBOX || USE_BZIP_MBOX - -#define SIZE_STEP (8 * 1024 * 1024) - -#define COMPRESSION_NONE 0 -#define COMPRESSION_GZIP 1 -#define COMPRESSION_BZIP 2 - -static int get_compression_type(const char *filename) {/*{{{*/ - size_t len = strlen(filename); - int ptr; - -#ifdef USE_GZIP_MBOX - ptr = len - 3; - if (len > 3 && strncasecmp(filename + ptr, ".gz", 3) == 0) { - return COMPRESSION_GZIP; - } -#endif - -#ifdef USE_BZIP_MBOX - ptr = len - 4; - if (len > 3 && strncasecmp(filename + ptr, ".bz2", 4) == 0) { - return COMPRESSION_BZIP; - } -#endif - - return COMPRESSION_NONE; -} -/*}}}*/ - -static int is_compressed(const char *filename) {/*{{{*/ - return (get_compression_type(filename) != COMPRESSION_NONE); -} -/*}}}*/ - -struct zFile {/*{{{*/ - union { - /* Both gzFile and BZFILE* are defined as void pointers - * in their respective header files. - */ -#ifdef USE_GZIP_MBOX - gzFile gzf; -#endif -#ifdef USE_BZIP_MBOX - BZFILE *bzf; -#endif - void *zptr; - } foo; - int type; -}; -/*}}}*/ - -static struct zFile * xx_zopen(const char *filename, const char *mode) {/*{{{*/ - struct zFile *zf = new(struct zFile); - - zf->type = get_compression_type(filename); - switch (zf->type) { -#ifdef USE_GZIP_MBOX - case COMPRESSION_GZIP: - zf->foo.gzf = gzopen(filename, "rb"); - break; -#endif -#ifdef USE_BZIP_MBOX - case COMPRESSION_BZIP: - zf->foo.bzf = BZ2_bzopen(filename, "rb"); - break; -#endif - default: - zf->foo.zptr = NULL; - break; - } - - if (!zf->foo.zptr) { - free(zf); - return 0; - } - - return zf; -} -/*}}}*/ -static void xx_zclose(struct zFile *zf) {/*{{{*/ - switch (zf->type) { -#ifdef USE_GZIP_MBOX - case COMPRESSION_GZIP: - gzclose(zf->foo.gzf); - break; -#endif -#ifdef USE_BZIP_MBOX - case COMPRESSION_BZIP: - BZ2_bzclose(zf->foo.bzf); - break; -#endif - default: - zf->foo.zptr = NULL; - break; - } - free(zf); -} -/*}}}*/ -static int xx_zread(struct zFile *zf, void *buf, int len) {/*{{{*/ - switch (zf->type) { -#ifdef USE_GZIP_MBOX - case COMPRESSION_GZIP: - return gzread(zf->foo.gzf, buf, len); - break; -#endif -#ifdef USE_BZIP_MBOX - case COMPRESSION_BZIP: - return BZ2_bzread(zf->foo.bzf, buf, len); - break; -#endif - default: - return 0; - break; - } -} -/*}}}*/ -#endif - -#if USE_GZIP_MBOX || USE_BZIP_MBOX -/* do we need ROCACHE_SIZE > 1? the code supports any number here */ -#define ROCACHE_SIZE 1 -struct ro_mapping { - char *filename; - unsigned char *map; - size_t len; -}; -static int ro_cache_init = 0; -static struct ro_mapping ro_mapping_cache[ROCACHE_SIZE]; - -/* find a temp file in the mapping cache. If nothing is found lasti is - * set to the next slot to use for insertion. You have to check that slot - * to see if it is currently in use - */ -static struct ro_mapping *find_ro_cache(const char *filename, int *lasti) -{ - int i = 0; - struct ro_mapping *ro = NULL; - if (lasti) - *lasti = 0; - if (!ro_cache_init) - return NULL; - for (i = 0 ; i < ROCACHE_SIZE ; i++) { - ro = ro_mapping_cache + i; - if (!ro->map) { - if (lasti) - *lasti = i; - return NULL; - } - if (strcmp(filename, ro->filename) == 0) - return ro; - } - /* if we're here, the map is full. They will reuse slot 0 */ - return NULL; -} - -/* - * put a new tempfile into the cache. It is mmaped as part of this function - * so you can safely close the file handle after calling this. - */ -static struct ro_mapping *add_ro_cache(const char *filename, int fd, size_t len) -{ - int i = 0; - struct ro_mapping *ro = NULL; - if (!ro_cache_init) { - memset(&ro_mapping_cache, 0, sizeof(ro_mapping_cache)); - ro_cache_init = 1; - } - ro = find_ro_cache(filename, &i); - if (ro) { - fprintf(stderr, "%s already in ro cache\n", filename); - return NULL; - } - ro = ro_mapping_cache + i; - if (ro->map) { - munmap(ro->map, ro->len); - ro->map = NULL; - free(ro->filename); - } - ro->map = (unsigned char *)mmap(0, len, PROT_READ, MAP_SHARED, fd, 0); - if (ro->map == MAP_FAILED) { - ro->map = NULL; - perror("rfc822:mmap"); - return NULL; - } - ro->len = len; - ro->filename = new_string(filename); - return ro; -} -#endif /* USE_GZIP_MBOX || USE_BZIP_MBOX */ - -void create_ro_mapping(const char *filename, unsigned char **data, int *len)/*{{{*/ -{ - struct stat sb; - int fd; - -#if USE_GZIP_MBOX || USE_BZIP_MBOX - struct zFile *zf; -#endif - - if (stat(filename, &sb) < 0) - { - report_error("stat", filename); - *data = NULL; - return; - } - -#if USE_GZIP_MBOX || USE_BZIP_MBOX - if(is_compressed(filename)) { - unsigned char *p; - size_t cur_read; - struct ro_mapping *ro; - FILE *tmpf; - - /* this branch never returns things that are freeable */ - data_alloc_type = ALLOC_NONE; - ro = find_ro_cache(filename, NULL); - if (ro) { - *data = ro->map; - *len = ro->len; - return; - } - - if(verbose) { - fprintf(stderr, "Decompressing %s...\n", filename); - } - - tmpf = tmpfile(); - if (!tmpf) { - perror("tmpfile"); - goto comp_error; - } - zf = xx_zopen(filename, "rb"); - if (!zf) { - fprintf(stderr, "Could not open %s\n", filename); - goto comp_error; - } - p = new_array(unsigned char, SIZE_STEP); - cur_read = xx_zread(zf, p, SIZE_STEP); - if (fwrite(p, cur_read, 1, tmpf) != 1) { - fprintf(stderr, "failed writing to temp file for %s\n", filename); - goto comp_error; - } - *len = cur_read; - if (cur_read >= SIZE_STEP) { - while(1) { - int ret; - cur_read = xx_zread(zf, p, SIZE_STEP); - if (cur_read <= 0) - break; - *len += cur_read; - ret = fwrite(p, cur_read, 1, tmpf); - if (ret != 1) { - fprintf(stderr, "failed writing to temp file for %s\n", filename); - goto comp_error; - } - } - } - free(p); - xx_zclose(zf); - - if(*len > 0) { - ro = add_ro_cache(filename, fileno(tmpf), *len); - if (!ro) - goto comp_error; - *data = ro->map; - *len = ro->len; - } else { - *data = NULL; - } - fclose(tmpf); - return; - -comp_error: - *data = NULL; - *len = 0; - if (tmpf) - fclose(tmpf); - return; - } -#endif /* USE_GZIP_MBOX || USE_BZIP_MBOX */ - - *len = sb.st_size; - if (*len == 0) { - *data = NULL; - return; - } - - if (!S_ISREG(sb.st_mode)) { - *data = NULL; - return; - } - - fd = open(filename, O_RDONLY); - if (fd < 0) - { - report_error("open", filename); - *data = NULL; - return; - } - - *data = (unsigned char *) mmap(0, *len, PROT_READ, MAP_SHARED, fd, 0); - if (close(fd) < 0) - report_error("close", filename); - if (*data == MAP_FAILED) { - report_error("rfc822:mmap", filename); - *data = NULL; - return; - } - data_alloc_type = ALLOC_MMAP; -} -/*}}}*/ -void free_ro_mapping(unsigned char *data, int len)/*{{{*/ -{ - int r; - - if(data_alloc_type == ALLOC_MALLOC) { - free(data); - } - - if(data_alloc_type == ALLOC_MMAP) { - r = munmap(data, len); - if(r < 0) { - fprintf(stderr, "munmap() errord\n"); - exit(1); - } - } -} -/*}}}*/ - -static struct msg_src *setup_msg_src(char *filename)/*{{{*/ -{ - static struct msg_src result; - result.type = MS_FILE; - result.filename = filename; - return &result; -} -/*}}}*/ -struct rfc822 *make_rfc822(char *filename)/*{{{*/ -{ - int len; - unsigned char *data; - struct rfc822 *result; - - create_ro_mapping(filename, &data, &len); - - /* Don't process empty files */ - result = NULL; - - if (data) - { - struct msg_src *src; - /* Now process the data */ - src = setup_msg_src(filename); - /* For one message per file, ignore missing end boundary condition. */ - result = data_to_rfc822(src, (char *) data, len, NULL); - - free_ro_mapping(data, len); - } - - return result; -} -/*}}}*/ -void free_rfc822(struct rfc822 *msg)/*{{{*/ -{ - struct attachment *a, *na; - - if (!msg) return; - - if (msg->hdrs.to) free(msg->hdrs.to); - if (msg->hdrs.cc) free(msg->hdrs.cc); - if (msg->hdrs.from) free(msg->hdrs.from); - if (msg->hdrs.subject) free(msg->hdrs.subject); - if (msg->hdrs.message_id) free(msg->hdrs.message_id); - if (msg->hdrs.in_reply_to) free(msg->hdrs.in_reply_to); - if (msg->hdrs.references) free(msg->hdrs.references); - - for (a = msg->atts.next; a != &msg->atts; a = na) { - na = a->next; - if (a->filename) free(a->filename); - if (a->ct == CT_MESSAGE_RFC822) { - free_rfc822(a->data.rfc822); - } else { - free(a->data.normal.bytes); - } - free(a); - } - free(msg); -} -/*}}}*/ - -#ifdef TEST - -static void do_indent(int indent)/*{{{*/ -{ - int i; - for (i=indent; i>0; i--) { - putchar(' '); - } -} -/*}}}*/ -static void show_header(char *tag, char *x, int indent)/*{{{*/ -{ - if (x) { - do_indent(indent); - printf("%s: %s\n", tag, x); - } -} -/*}}}*/ -static void show_rfc822(struct rfc822 *msg, int indent)/*{{{*/ -{ - struct attachment *a; - show_header("From", msg->hdrs.from, indent); - show_header("To", msg->hdrs.to, indent); - show_header("Cc", msg->hdrs.cc, indent); - show_header("Date", msg->hdrs.date, indent); - show_header("Subject", msg->hdrs.subject, indent); - - for (a = msg->atts.next; a != &msg->atts; a=a->next) { - printf("========================\n"); - switch (a->ct) { - case CT_TEXT_PLAIN: printf("Attachment type text/plain\n"); break; - case CT_TEXT_HTML: printf("Attachment type text/html\n"); break; - case CT_TEXT_OTHER: printf("Attachment type text/non-plain\n"); break; - case CT_MESSAGE_RFC822: printf("Attachment type message/rfc822\n"); break; - case CT_OTHER: printf("Attachment type other\n"); break; - } - if (a->ct != CT_MESSAGE_RFC822) { - printf("%d bytes\n", a->data.normal.len); - } - if ((a->ct == CT_TEXT_PLAIN) || (a->ct == CT_TEXT_HTML) || (a->ct == CT_TEXT_OTHER)) { - printf("----------\n"); - printf("%s\n", a->data.normal.bytes); - } - if (a->ct == CT_MESSAGE_RFC822) { - show_rfc822(a->data.rfc822, indent + 4); - } - } -} -/*}}}*/ - -int main (int argc, char **argv)/*{{{*/ -{ - struct rfc822 *msg; - - if (argc < 2) { - fprintf(stderr, "Need a path\n"); - unlock_and_exit(2); - } - - msg = make_rfc822(argv[1]); - show_rfc822(msg, 0); - free_rfc822(msg); - - /* Print out some stuff */ - - return 0; -} -/*}}}*/ -#endif /* TEST */ diff --git a/src/mairix/search.c b/src/mairix/search.c @@ -1,1445 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002,2003,2004,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <time.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <unistd.h> -#include <assert.h> -#include <dirent.h> -#include <errno.h> - -/* Lame fix for systems where NAME_MAX isn't defined after including the above - * set of .h files (Solaris, FreeBSD so far). Probably grossly oversized but - * it'll do. */ - -#if !defined(NAME_MAX) -#define NAME_MAX 4096 -#endif - -#include "mairix.h" -#include "reader.h" -#include "memmac.h" - -static void mark_hits_in_table(struct read_db *db, struct toktable_db *tt, int hit_tok, char *hits)/*{{{*/ -{ - /* mark files containing matched token */ - int idx; - unsigned char *j, *first_char; - idx = 0; - first_char = (unsigned char *) db->data + tt->enc_offsets[hit_tok]; - for (j = first_char; *j != 0xff; ) { - idx += read_increment(&j); - assert(idx < db->n_msgs); - hits[idx] = 1; - } -} -/*}}}*/ -static void mark_hits_in_table2(struct read_db *db, struct toktable2_db *tt, int hit_tok, char *hits)/*{{{*/ -{ - /* mark files containing matched token */ - int idx; - unsigned char *j, *first_char; - idx = 0; - first_char = (unsigned char *) db->data + tt->enc1_offsets[hit_tok]; - for (j = first_char; *j != 0xff; ) { - idx += read_increment(&j); - assert(idx < db->n_msgs); - hits[idx] = 1; - } -} -/*}}}*/ - -/* See "Fast text searching with errors, Sun Wu and Udi Manber, TR 91-11, - University of Arizona. I have been informed that this algorithm is NOT - patented. This implementation of it is entirely the work of Richard P. - Curnow - I haven't looked at any related source (webglimpse, agrep etc) in - writing this. -*/ -static void build_match_vector(char *substring, unsigned long *a, unsigned long *hit)/*{{{*/ -{ - int len; - char *p; - int i; - - len = strlen(substring); - if (len > 31 || len == 0) { - fprintf(stderr, "Can't match patterns longer than 31 characters or empty\n"); - unlock_and_exit(2); - } - memset(a, 0xff, 256 * sizeof(unsigned long)); - for (p=substring, i=0; *p; p++, i++) { - a[(unsigned int) *(unsigned char *)p] &= ~(1UL << i); - } - *hit = ~(1UL << (len-1)); - return; -} -/*}}}*/ -static int substring_match_0(unsigned long *a, unsigned long hit, int left_anchor, char *token)/*{{{*/ -{ - int got_hit=0; - char *p; - unsigned long r0; - unsigned long anchor, anchor1; - - r0 = ~0; - got_hit = 0; - anchor = 0; - anchor1 = left_anchor ? 0x1 : 0x0; - for(p=token; *p; p++) { - int idx = (unsigned int) *(unsigned char *)p; - r0 = (r0<<1) | anchor | a[idx]; - if (~(r0 | hit)) { - got_hit = 1; - break; - } - anchor = anchor1; - } - return got_hit; -} -/*}}}*/ -static int substring_match_1(unsigned long *a, unsigned long hit, int left_anchor, char *token)/*{{{*/ -{ - int got_hit=0; - char *p; - unsigned long r0, r1, nr0; - unsigned long anchor, anchor1; - - r0 = ~0; - r1 = r0<<1; - got_hit = 0; - anchor = 0; - anchor1 = left_anchor ? 0x1 : 0x0; - for(p=token; *p; p++) { - int idx = (unsigned int) *(unsigned char *)p; - nr0 = (r0<<1) | anchor | a[idx]; - r1 = ((r1<<1) | anchor | a[idx]) & ((r0 & nr0) << 1) & r0; - r0 = nr0; - if (~((r0 & r1) | hit)) { - got_hit = 1; - break; - } - anchor = anchor1; - } - return got_hit; -} -/*}}}*/ -static int substring_match_2(unsigned long *a, unsigned long hit, int left_anchor, char *token)/*{{{*/ -{ - int got_hit=0; - char *p; - unsigned long r0, r1, r2, nr0, nr1; - unsigned long anchor, anchor1; - - r0 = ~0; - r1 = r0<<1; - r2 = r1<<1; - got_hit = 0; - anchor = 0; - anchor1 = left_anchor ? 0x1 : 0x0; - for(p=token; *p; p++) { - int idx = (unsigned int) *(unsigned char *)p; - nr0 = (r0<<1) | anchor | a[idx]; - nr1 = ((r1<<1) | anchor | a[idx]) & ((r0 & nr0) << 1) & r0; - r2 = ((r2<<1) | anchor | a[idx]) & ((r1 & nr1) << 1) & r1; - r0 = nr0; - r1 = nr1; - if (~((r0 & r1 & r2) | hit)) { - got_hit = 1; - break; - } - anchor = anchor1; - } - return got_hit; -} -/*}}}*/ -static int substring_match_3(unsigned long *a, unsigned long hit, int left_anchor, char *token)/*{{{*/ -{ - int got_hit=0; - char *p; - unsigned long r0, r1, r2, r3, nr0, nr1, nr2; - unsigned long anchor, anchor1; - - r0 = ~0; - r1 = r0<<1; - r2 = r1<<1; - r3 = r2<<1; - got_hit = 0; - anchor = 0; - anchor1 = left_anchor ? 0x1 : 0x0; - for(p=token; *p; p++) { - int idx = (unsigned int) *(unsigned char *)p; - nr0 = (r0<<1) | anchor | a[idx]; - nr1 = ((r1<<1) | anchor | a[idx]) & ((r0 & nr0) << 1) & r0; - nr2 = ((r2<<1) | anchor | a[idx]) & ((r1 & nr1) << 1) & r1; - r3 = ((r3<<1) | anchor | a[idx]) & ((r2 & nr2) << 1) & r2; - r0 = nr0; - r1 = nr1; - r2 = nr2; - if (~((r0 & r1 & r2 & r3) | hit)) { - got_hit = 1; - break; - } - anchor = anchor1; - } - return got_hit; -} -/*}}}*/ -static int substring_match_general(unsigned long *a, unsigned long hit, int left_anchor, char *token, int max_errors, unsigned long *r, unsigned long *nr)/*{{{*/ -{ - int got_hit=0; - char *p; - int j; - unsigned long anchor, anchor1; - - r[0] = ~0; - anchor = 0; - anchor1 = left_anchor ? 0x1 : 0x0; - for (j=1; j<=max_errors; j++) { - r[j] = r[j-1] << 1; - } - got_hit = 0; - for(p=token; *p; p++) { - int idx = (unsigned int) *(unsigned char *)p; - int d; - unsigned int compo; - - compo = nr[0] = ((r[0]<<1) | anchor | a[idx]); - for (d=1; d<=max_errors; d++) { - nr[d] = ((r[d]<<1) | anchor | a[idx]) - & ((r[d-1] & nr[d-1])<<1) - & r[d-1]; - compo &= nr[d]; - } - memcpy(r, nr, (1 + max_errors) * sizeof(unsigned long)); - if (~(compo | hit)) { - got_hit = 1; - break; - } - anchor = anchor1; - } - return got_hit; -} -/*}}}*/ - -static void match_substring_in_table(struct read_db *db, struct toktable_db *tt, char *substring, int max_errors, int left_anchor, char *hits)/*{{{*/ -{ - - int i, got_hit; - unsigned long a[256]; - unsigned long *r=NULL, *nr=NULL; - unsigned long hit; - char *token; - - build_match_vector(substring, a, &hit); - - got_hit = 0; - if (max_errors > 3) { - r = new_array(unsigned long, 1 + max_errors); - nr = new_array(unsigned long, 1 + max_errors); - } - for (i=0; i<tt->n; i++) { - token = db->data + tt->tok_offsets[i]; - switch (max_errors) { - /* Optimise common cases for few errors to allow optimizer to keep bitmaps - * in registers */ - case 0: - got_hit = substring_match_0(a, hit, left_anchor, token); - break; - case 1: - got_hit = substring_match_1(a, hit, left_anchor, token); - break; - case 2: - got_hit = substring_match_2(a, hit, left_anchor, token); - break; - case 3: - got_hit = substring_match_3(a, hit, left_anchor, token); - break; - default: - got_hit = substring_match_general(a, hit, left_anchor, token, max_errors, r, nr); - break; - } - if (got_hit) { - mark_hits_in_table(db, tt, i, hits); - } - } - if (r) free(r); - if (nr) free(nr); -} -/*}}}*/ -static void match_substring_in_paths(struct read_db *db, char *substring, int max_errors, int left_anchor, char *hits)/*{{{*/ -{ - - int i; - unsigned long a[256]; - unsigned long *r=NULL, *nr=NULL; - unsigned long hit; - - build_match_vector(substring, a, &hit); - - if (max_errors > 3) { - r = new_array(unsigned long, 1 + max_errors); - nr = new_array(unsigned long, 1 + max_errors); - } - for (i=0; i<db->n_msgs; i++) { - char *token = NULL; - unsigned int mbix, msgix; - switch (rd_msg_type(db, i)) { - case DB_MSG_FILE: - token = db->data + db->path_offsets[i]; - break; - case DB_MSG_MBOX: - decode_mbox_indices(db->path_offsets[i], &mbix, &msgix); - token = db->data + db->mbox_paths_table[mbix]; - break; - case DB_MSG_DEAD: - hits[i] = 0; /* never match on dead paths */ - goto next_message; - } - - assert(token); - - switch (max_errors) { - /* Optimise common cases for few errors to allow optimizer to keep bitmaps - * in registers */ - case 0: - hits[i] = substring_match_0(a, hit, left_anchor, token); - break; - case 1: - hits[i] = substring_match_1(a, hit, left_anchor, token); - break; - case 2: - hits[i] = substring_match_2(a, hit, left_anchor, token); - break; - case 3: - hits[i] = substring_match_3(a, hit, left_anchor, token); - break; - default: - hits[i] = substring_match_general(a, hit, left_anchor, token, max_errors, r, nr); - break; - } -next_message: - (void) 0; - } - - if (r) free(r); - if (nr) free(nr); -} -/*}}}*/ -static void match_string_in_table(struct read_db *db, struct toktable_db *tt, char *key, char *hits)/*{{{*/ -{ - /* TODO : replace with binary search? */ - int i; - - for (i=0; i<tt->n; i++) { - if (!strcmp(key, db->data + tt->tok_offsets[i])) { - /* get all matching files */ - mark_hits_in_table(db, tt, i, hits); - } - } -} -/*}}}*/ -static void match_string_in_table2(struct read_db *db, struct toktable2_db *tt, char *key, char *hits)/*{{{*/ -{ - /* TODO : replace with binary search? */ - int i; - - for (i=0; i<tt->n; i++) { - if (!strcmp(key, db->data + tt->tok_offsets[i])) { - /* get all matching files */ - mark_hits_in_table2(db, tt, i, hits); - } - } -} -/*}}}*/ -static int parse_size_expr(char *x)/*{{{*/ -{ - int result; - int n; - - if (1 == sscanf(x, "%d%n", &result, &n)) { - x += n; - switch (*x) { - case 'k': - case 'K': - result <<= 10; - break; - case 'm': - case 'M': - result <<= 20; - break; - default: - break; - } - - return result; - } else { - fprintf(stderr, "Could not parse message size expression <%s>\n", x); - return -1; - } -} -/*}}}*/ -static void parse_size_range(char *size_expr, int *has_start, int *start, int *has_end, int *end)/*{{{*/ -{ - char *x = size_expr; - char *dash; - int len; - - if (*x == ':') x++; - len = strlen(x); - dash = strchr(x, '-'); - *has_start = *has_end = 0; - if (dash) { - char *p, *q; - if (dash > x) { - char *s; - s = new_array(char, dash - x + 1); - for (p=s, q=x; q<dash; ) *p++ = *q++; - *p = 0; - *start = parse_size_expr(s); - *has_start = 1; - free(s); - } - if (dash[1]) { /* dash not at end of arg */ - char *e; - e = new_array(char, (x + len) - dash); - for (p=e, q=dash+1; *q; ) *p++ = *q++; - *p = 0; - *end = parse_size_expr(e); - *has_end = 1; - free(e); - } - } else { - *has_start = 0; - *end = parse_size_expr(size_expr); - *has_end = 1; - } - return; -} -/*}}}*/ -static void find_size_matches_in_table(struct read_db *db, char *size_expr, char *hits)/*{{{*/ -{ - int start, end; - int has_start, has_end, start_cond, end_cond; - int i; - - start = end = -1; /* avoid compiler warning about uninitialised variables. */ - parse_size_range(size_expr, &has_start, &start, &has_end, &end); - if (has_start && has_end) { - /* Allow user to put the endpoints in backwards */ - if (start > end) { - int temp = start; - start = end; - end = temp; - } - } - - for (i=0; i<db->n_msgs; i++) { - start_cond = has_start ? (db->size_table[i] > start) : 1; - end_cond = has_end ? (db->size_table[i] < end ) : 1; - if (start_cond && end_cond) { - hits[i] = 1; - } - } -} -/*}}}*/ -static void find_date_matches_in_table(struct read_db *db, char *date_expr, char *hits)/*{{{*/ -{ - time_t start, end; - int has_start, has_end, start_cond, end_cond; - int i; - int status; - - status = scan_date_string(date_expr, &start, &has_start, &end, &has_end); - if (status) { - unlock_and_exit (2); - } - - if (has_start && has_end) { - /* Allow user to put the endpoints in backwards */ - if (start > end) { - time_t temp = start; - start = end; - end = temp; - } - } - - for (i=0; i<db->n_msgs; i++) { - start_cond = has_start ? (db->date_table[i] > start) : 1; - end_cond = has_end ? (db->date_table[i] < end ) : 1; - if (start_cond && end_cond) { - hits[i] = 1; - } - } -} -/*}}}*/ -static void find_flag_matches_in_table(struct read_db *db, char *flag_expr, char *hits)/*{{{*/ -{ - int pos_seen, neg_seen; - int pos_replied, neg_replied; - int pos_flagged, neg_flagged; - int negate; - char *p; - int i; - - negate = 0; - pos_seen = neg_seen = 0; - pos_replied = neg_replied = 0; - pos_flagged = neg_flagged = 0; - for (p=flag_expr; *p; p++) { - switch (*p) { - case '-': - negate = 1; - break; - case 's': - case 'S': - if (negate) neg_seen = 1; - else pos_seen = 1; - negate = 0; - break; - case 'r': - case 'R': - if (negate) neg_replied = 1; - else pos_replied = 1; - negate = 0; - break; - case 'f': - case 'F': - if (negate) neg_flagged = 1; - else pos_flagged = 1; - negate = 0; - break; - default: - fprintf(stderr, "Did not understand the character '%c' (0x%02x) in the flags argument F:%s\n", - isprint(*p) ? *p : '.', - (int) *(unsigned char *) p, - flag_expr); - break; - } - } - - for (i=0; i<db->n_msgs; i++) { - if ((!pos_seen || (db->msg_type_and_flags[i] & FLAG_SEEN)) && - (!neg_seen || !(db->msg_type_and_flags[i] & FLAG_SEEN)) && - (!pos_replied || (db->msg_type_and_flags[i] & FLAG_REPLIED)) && - (!neg_replied || !(db->msg_type_and_flags[i] & FLAG_REPLIED)) && - (!pos_flagged || (db->msg_type_and_flags[i] & FLAG_FLAGGED)) && - (!neg_flagged || !(db->msg_type_and_flags[i] & FLAG_FLAGGED))) { - hits[i] = 1; - } - } -} -/*}}}*/ - -static char *mk_maildir_path(int token, char *output_dir, int is_in_new, - int is_seen, int is_replied, int is_flagged)/*{{{*/ -{ - char *result; - char uniq_buf[48]; - int len; - - len = strlen(output_dir) + 64; /* oversize */ - result = new_array(char, len + 1 + sizeof(":2,FRS")); - strcpy(result, output_dir); - strcat(result, is_in_new ? "/new/" : "/cur/"); - sprintf(uniq_buf, "123456789.%d.mairix", token); - strcat(result, uniq_buf); - if (is_seen || is_replied || is_flagged) { - strcat(result, ":2,"); - } - if (is_flagged) strcat(result, "F"); - if (is_replied) strcat(result, "R"); - if (is_seen) strcat(result, "S"); - return result; -} -/*}}}*/ -static char *mk_mh_path(int token, char *output_dir)/*{{{*/ -{ - char *result; - char uniq_buf[8]; - int len; - - len = strlen(output_dir) + 10; /* oversize */ - result = new_array(char, len); - strcpy(result, output_dir); - strcat(result, "/"); - sprintf(uniq_buf, "%d", token+1); - strcat(result, uniq_buf); - return result; -} -/*}}}*/ -static int looks_like_maildir_new_p(const char *p)/*{{{*/ -{ - const char *s1, *s2; - s2 = p; - while (*s2) s2++; - while ((s2 > p) && (*s2 != '/')) s2--; - if (s2 <= p) return 0; - s1 = s2 - 1; - while ((s1 > p) && (*s1 != '/')) s1--; - if (s1 <= p) return 0; - if (!strncmp(s1, "/new/", 5)) { - return 1; - } else { - return 0; - } -} -/*}}}*/ -static void create_symlink(char *link_target, char *new_link)/*{{{*/ -{ - // added possibility to move files (delete origin) - if (do_movefiles>0) { - if( rename(link_target, new_link) != 0) { - if (verbose) { - perror("rename"); - fprintf(stderr, "Failed rename <%s> -> <%s>\n", link_target, new_link); - } - } - - } else if ((!do_hardlinks && symlink(link_target, new_link) < 0) || link(link_target, new_link)) { - if (verbose) { - perror("symlink"); - fprintf(stderr, "Failed path <%s> -> <%s>\n", link_target, new_link); - } - } -} -/*}}}*/ -static void mbox_terminate(const unsigned char *data, int len, FILE *out)/*{{{*/ -{ - if (len == 0) - fputs("\n", out); - else if (len == 1) { - if (data[0] != '\n') - fputs("\n", out); - } - else if (data[len-1] != '\n') - fputs("\n\n", out); - else if (data[len-2] != '\n') - fputs("\n", out); -} -/*}}}*/ -static void append_file_to_mbox(const char *path, FILE *out)/*{{{*/ -{ - unsigned char *data; - int len; - create_ro_mapping(path, &data, &len); - if (data) { - fprintf(out, "From mairix@mairix Mon Jan 1 12:34:56 1970\n"); - fprintf(out, "X-source-folder: %s\n", path); - fwrite (data, sizeof(unsigned char), len, out); - mbox_terminate(data, len, out); - free_ro_mapping(data, len); - } - return; -} -/*}}}*/ - -static int had_failed_checksum; - -static void get_validated_mbox_msg(struct read_db *db, int msg_index,/*{{{*/ - int *mbox_index, - unsigned char **mbox_data, int *mbox_len, - unsigned char **msg_data, int *msg_len) -{ - /* msg_data==NULL if checksum mismatches */ - unsigned char *start; - checksum_t csum; - unsigned int mbi, msgi; - - *msg_data = NULL; - *msg_len = 0; - - decode_mbox_indices(db->path_offsets[msg_index], &mbi, &msgi); - *mbox_index = mbi; - - create_ro_mapping(db->data + db->mbox_paths_table[mbi], mbox_data, mbox_len); - if (!*mbox_data) return; - - start = *mbox_data + db->mtime_table[msg_index]; - - /* Ensure that we don't run off the end of the mmap'd file */ - if (db->mtime_table[msg_index] >= *mbox_len) - *msg_len = 0; - else if (db->mtime_table[msg_index] + db->size_table[msg_index] >= *mbox_len) - *msg_len = *mbox_len - db->mtime_table[msg_index]; - else - *msg_len = db->size_table[msg_index]; - - compute_checksum((char *)start, *msg_len, &csum); - if (!memcmp((db->data + db->mbox_checksum_table[mbi] + (msgi * sizeof(checksum_t))), &csum, sizeof(checksum_t))) { - *msg_data = start; - } else { - had_failed_checksum = 1; - } - return; -} -/*}}}*/ -static void append_mboxmsg_to_mbox(struct read_db *db, int msg_index, FILE *out)/*{{{*/ -{ - /* Need to common up code with try_copy_to_path */ - unsigned char *mbox_start, *msg_start; - int mbox_len, msg_len; - int mbox_index; - - get_validated_mbox_msg(db, msg_index, &mbox_index, &mbox_start, &mbox_len, &msg_start, &msg_len); - if (msg_start) { - /* Artificial from line, we don't have the envelope sender so this is - going to be artificial anyway. */ - fprintf(out, "From mairix@mairix Mon Jan 1 12:34:56 1970\n"); - fprintf(out, "X-source-folder: %s\n", - db->data + db->mbox_paths_table[mbox_index]); - fwrite(msg_start, sizeof(unsigned char), msg_len, out); - mbox_terminate(msg_start, msg_len, out); - } - if (mbox_start) { - free_ro_mapping(mbox_start, mbox_len); - } -} -/*}}}*/ -static void try_copy_to_path(struct read_db *db, int msg_index, char *target_path)/*{{{*/ -{ - unsigned char *data; - int mbox_len, msg_len; - int mbi; - FILE *out; - unsigned char *start; - - get_validated_mbox_msg(db, msg_index, &mbi, &data, &mbox_len, &start, &msg_len); - - if (start) { - out = fopen(target_path, "wb"); - if (out) { - fprintf(out, "X-source-folder: %s\n", - db->data + db->mbox_paths_table[mbi]); - fwrite(start, sizeof(char), msg_len?msg_len-1:0, out); - fclose(out); - } - } - - if (data) { - free_ro_mapping(data, mbox_len); - } - return; -} -/*}}}*/ -static struct msg_src *setup_mbox_msg_src(char *filename, off_t start, size_t len)/*{{{*/ -{ - static struct msg_src result; - result.type = MS_MBOX; - result.filename = filename; - result.start = start; - result.len = len; - return &result; -} -/*}}}*/ - -static void get_flags_from_file(struct read_db *db, int idx, int *is_seen, int *is_replied, int *is_flagged) -{ - *is_seen = (db->msg_type_and_flags[idx] & FLAG_SEEN) ? 1 : 0; - *is_replied = (db->msg_type_and_flags[idx] & FLAG_REPLIED) ? 1 : 0; - *is_flagged = (db->msg_type_and_flags[idx] & FLAG_FLAGGED) ? 1 : 0; -} - -static void string_tolower(char *str) -{ - char *p; - for (p=str; *p; p++) { - *p = tolower(*(unsigned char *)p); - } -} - -static int do_search(struct read_db *db, char **args, char *output_path, int show_threads, enum folder_type ft, int verbose)/*{{{*/ -{ - char *colon, *start_words; - int do_body, do_subject, do_from, do_to, do_cc, do_date, do_size; - int do_att_name; - int do_flags; - int do_path, do_msgid; - char *key; - char *hit0, *hit1, *hit2, *hit3; - int i; - int n_hits; - int left_anchor; - - had_failed_checksum = 0; - - hit0 = new_array(char, db->n_msgs); - hit1 = new_array(char, db->n_msgs); - hit2 = new_array(char, db->n_msgs); - hit3 = new_array(char, db->n_msgs); - - /* Argument structure is - * x:tokena+tokenb,~tokenc,tokend+tokene - * - * + (and) binds more tightly than , - * , (or) binds more tightly than separate args - * - * - * hit1 gathers the tokens and'ed with + - * hit2 gathers the tokens or'ed with , - * hit3 gathers the separate args and'ed with <gap> - * */ - - - /* Everything matches until proven otherwise */ - memset(hit3, 1, db->n_msgs); - - while (*args) { - /* key is a single argument, separate args are and-ed together */ - key = *args++; - - memset(hit2, 0, db->n_msgs); - memset(hit1, 1, db->n_msgs); - - do_to = 0; - do_cc = 0; - do_from = 0; - do_subject = 0; - do_body = 0; - do_date = 0; - do_size = 0; - do_path = 0; - do_msgid = 0; - do_att_name = 0; - do_flags = 0; - - colon = strchr(key, ':'); - - if (colon) { - char *p; - for (p=key; p<colon; p++) { - switch(*p) { - case 'b': do_body = 1; break; - case 's': do_subject = 1; break; - case 't': do_to = 1; break; - case 'c': do_cc = 1; break; - case 'f': do_from = 1; break; - case 'r': do_to = do_cc = 1; break; - case 'a': do_to = do_cc = do_from = 1; break; - case 'd': do_date = 1; break; - case 'z': do_size = 1; break; - case 'p': do_path = 1; break; - case 'm': do_msgid = 1; break; - case 'n': do_att_name = 1; break; - case 'F': do_flags = 1; break; - default: fprintf(stderr, "Unknown key type <%c>\n", *p); break; - } - } - if (do_msgid && (p-key) > 1) { - fprintf(stderr, "Message-ID key <m> can't be used with other keys\n"); - unlock_and_exit(2); - } - start_words = 1 + colon; - } else { - do_body = do_subject = do_to = do_cc = do_from = 1; - start_words = key; - } - - if (do_date || do_size || do_flags) { - memset(hit0, 0, db->n_msgs); - if (do_date) { - find_date_matches_in_table(db, start_words, hit0); - } else if (do_size) { - find_size_matches_in_table(db, start_words, hit0); - } else if (do_flags) { - find_flag_matches_in_table(db, start_words, hit0); - } - - /* AND-combine match vectors */ - for (i=0; i<db->n_msgs; i++) { - hit1[i] &= hit0[i]; - } - } else if (do_msgid) { - char *lower_word = new_string(start_words); - string_tolower(lower_word); - memset(hit0, 0, db->n_msgs); - match_string_in_table2(db, &db->msg_ids, lower_word, hit0); - free(lower_word); - /* AND-combine match vectors */ - for (i=0; i<db->n_msgs; i++) { - hit1[i] &= hit0[i]; - } - } else { -/*{{{ Scan over separate words within this argument */ - - do { - /* / = 'or' separator - * , = 'and' separator */ - char *orsep; - char *andsep; - char *word, *orig_word, *lower_word; - char *equal; - int negate; - int had_orsep; - int max_errors; - - orsep = strchr(start_words, '/'); - andsep = strchr(start_words, ','); - had_orsep = 0; - - if (andsep && (!orsep || (andsep < orsep))) { - char *p, *q; - word = new_array(char, 1 + (andsep - start_words)); /* maybe oversize */ - for (p=word, q=start_words; q < andsep; q++) { - if (!isspace(*(unsigned char *)q)) { - *p++ = *q; - } - } - *p = 0; - start_words = andsep + 1; - } else if (orsep) { /* comes before + if there's a + */ - char *p, *q; - word = new_array(char, 1 + (orsep - start_words)); /* maybe oversize */ - for (p=word, q=start_words; q < orsep; q++) { - if (!isspace(*(unsigned char *)q)) { - *p++ = *q; - } - } - *p = 0; - start_words = orsep + 1; - had_orsep = 1; - - } else { - word = new_string(start_words); - while (*start_words) ++start_words; - } - - orig_word = word; - - if (word[0] == '~') { - negate = 1; - word++; - } else { - negate = 0; - } - - if (word[0] == '^') { - left_anchor = 1; - word++; - } else { - left_anchor = 0; - } - - equal = strchr(word, '='); - if (equal) { - *equal = 0; - max_errors = atoi(equal + 1); - /* Extend this to do anchoring etc */ - } else { - max_errors = 0; /* keep GCC quiet */ - } - - /* Canonicalise search string to lowercase, since the database has all - * tokens handled that way. But not for path search! */ - lower_word = new_string(word); - string_tolower(lower_word); - - memset(hit0, 0, db->n_msgs); - if (equal) { - if (do_to) match_substring_in_table(db, &db->to, lower_word, max_errors, left_anchor, hit0); - if (do_cc) match_substring_in_table(db, &db->cc, lower_word, max_errors, left_anchor, hit0); - if (do_from) match_substring_in_table(db, &db->from, lower_word, max_errors, left_anchor, hit0); - if (do_subject) match_substring_in_table(db, &db->subject, lower_word, max_errors, left_anchor, hit0); - if (do_body) match_substring_in_table(db, &db->body, lower_word, max_errors, left_anchor, hit0); - if (do_att_name) match_substring_in_table(db, &db->attachment_name, lower_word, max_errors, left_anchor, hit0); - if (do_path) match_substring_in_paths(db, word, max_errors, left_anchor, hit0); - } else { - if (do_to) match_string_in_table(db, &db->to, lower_word, hit0); - if (do_cc) match_string_in_table(db, &db->cc, lower_word, hit0); - if (do_from) match_string_in_table(db, &db->from, lower_word, hit0); - if (do_subject) match_string_in_table(db, &db->subject, lower_word, hit0); - if (do_body) match_string_in_table(db, &db->body, lower_word, hit0); - if (do_att_name) match_string_in_table(db, &db->attachment_name, lower_word, hit0); - /* FIXME */ - if (do_path) match_substring_in_paths(db, word, 0, left_anchor, hit0); - } - - free(lower_word); - - /* AND-combine match vectors */ - for (i=0; i<db->n_msgs; i++) { - if (negate) { - hit1[i] &= !hit0[i]; - } else { - hit1[i] &= hit0[i]; - } - } - - if (had_orsep) { - /* OR-combine match vectors */ - for (i=0; i<db->n_msgs; i++) { - hit2[i] |= hit1[i]; - } - memset(hit1, 1, db->n_msgs); - } - - free(orig_word); - - } while (*start_words); -/*}}}*/ - } - - /* OR-combine match vectors */ - for (i=0; i<db->n_msgs; i++) { - hit2[i] |= hit1[i]; - } - - /* AND-combine match vectors */ - for (i=0; i<db->n_msgs; i++) { - hit3[i] &= hit2[i]; - } - } - - n_hits = 0; - - if (show_threads) {/*{{{*/ - char *tids; - tids = new_array(char, db->n_msgs); - memset(tids, 0, db->n_msgs); - for (i=0; i<db->n_msgs; i++) { - if (hit3[i]) { - tids[db->tid_table[i]] = 1; - } - } - for (i=0; i<db->n_msgs; i++) { - if (tids[db->tid_table[i]]) { - hit3[i] = 1; - } - } - free(tids); - } -/*}}}*/ - switch (ft) { - case FT_MAILDIR:/*{{{*/ - for (i=0; i<db->n_msgs; i++) { - if (hit3[i]) { - int is_seen, is_replied, is_flagged; - get_flags_from_file(db, i, &is_seen, &is_replied, &is_flagged); - switch (rd_msg_type(db, i)) { - case DB_MSG_FILE: - { - char *target_path; - char *message_path; - int is_in_new; - message_path = db->data + db->path_offsets[i]; - is_in_new = looks_like_maildir_new_p(message_path); - target_path = mk_maildir_path(i, output_path, is_in_new, is_seen, is_replied, is_flagged); - create_symlink(message_path, target_path); - free(target_path); - ++n_hits; - } - break; - case DB_MSG_MBOX: - { - char *target_path = mk_maildir_path(i, output_path, !is_seen, is_seen, is_replied, is_flagged); - try_copy_to_path(db, i, target_path); - free(target_path); - ++n_hits; - } - break; - case DB_MSG_DEAD: - break; - } - } - } - break; -/*}}}*/ - case FT_MH:/*{{{*/ - for (i=0; i<db->n_msgs; i++) { - if (hit3[i]) { - switch (rd_msg_type(db, i)) { - case DB_MSG_FILE: - { - char *target_path = mk_mh_path(i, output_path); - create_symlink(db->data + db->path_offsets[i], target_path); - free(target_path); - ++n_hits; - } - break; - case DB_MSG_MBOX: - { - char *target_path = mk_mh_path(i, output_path); - try_copy_to_path(db, i, target_path); - free(target_path); - ++n_hits; - } - break; - case DB_MSG_DEAD: - break; - } - } - } - break; -/*}}}*/ - case FT_MBOX:/*{{{*/ - { - FILE *out; - out = fopen(output_path, "ab"); - if (!out) { - fprintf(stderr, "Cannot open output folder %s\n", output_path); - unlock_and_exit(1); - } - - for (i=0; i<db->n_msgs; i++) { - if (hit3[i]) { - switch (rd_msg_type(db, i)) { - case DB_MSG_FILE: - { - append_file_to_mbox(db->data + db->path_offsets[i], out); - ++n_hits; - } - break; - case DB_MSG_MBOX: - { - append_mboxmsg_to_mbox(db, i, out); - ++n_hits; - } - break; - case DB_MSG_DEAD: - break; - } - } - } - fclose(out); - } - - break; -/*}}}*/ - case FT_RAW:/*{{{*/ - for (i=0; i<db->n_msgs; i++) { - if (hit3[i]) { - switch (rd_msg_type(db, i)) { - case DB_MSG_FILE: - { - ++n_hits; - printf("%s\n", db->data + db->path_offsets[i]); - } - break; - case DB_MSG_MBOX: - { - unsigned int mbix, msgix; - int start, len, after_end; - start = db->mtime_table[i]; - len = db->size_table[i]; - after_end = start + len; - ++n_hits; - decode_mbox_indices(db->path_offsets[i], &mbix, &msgix); - printf("mbox:%s [%d,%d)\n", db->data + db->mbox_paths_table[mbix], start, after_end); - } - break; - case DB_MSG_DEAD: - break; - } - } - } - break; -/*}}}*/ - case FT_EXCERPT:/*{{{*/ - for (i=0; i<db->n_msgs; i++) { - if (hit3[i]) { - struct rfc822 *parsed = NULL; - switch (rd_msg_type(db, i)) { - case DB_MSG_FILE: - { - char *filename; - ++n_hits; - printf("---------------------------------\n"); - filename = db->data + db->path_offsets[i]; - printf("%s\n", filename); - parsed = make_rfc822(filename); - } - break; - case DB_MSG_MBOX: - { - unsigned int mbix, msgix; - int start, len, after_end; - unsigned char *mbox_start, *msg_start; - int mbox_len, msg_len; - int mbox_index; - - start = db->mtime_table[i]; - len = db->size_table[i]; - after_end = start + len; - ++n_hits; - printf("---------------------------------\n"); - decode_mbox_indices(db->path_offsets[i], &mbix, &msgix); - printf("mbox:%s [%d,%d)\n", db->data + db->mbox_paths_table[mbix], start, after_end); - - get_validated_mbox_msg(db, i, &mbox_index, &mbox_start, &mbox_len, &msg_start, &msg_len); - if (msg_start) { - enum data_to_rfc822_error error; - struct msg_src *msg_src; - msg_src = setup_mbox_msg_src(db->data + db->mbox_paths_table[mbix], start, msg_len); - parsed = data_to_rfc822(msg_src, (char *) msg_start, msg_len, &error); - } - if (mbox_start) { - free_ro_mapping(mbox_start, mbox_len); - } - } - break; - case DB_MSG_DEAD: - break; - } - - if (parsed) { - char datebuf[64]; - struct tm *thetm; - if (parsed->hdrs.to) printf(" To: %s\n", parsed->hdrs.to); - if (parsed->hdrs.cc) printf(" Cc: %s\n", parsed->hdrs.cc); - if (parsed->hdrs.from) printf(" From: %s\n", parsed->hdrs.from); - if (parsed->hdrs.subject) printf(" Subject: %s\n", parsed->hdrs.subject); - if (parsed->hdrs.message_id) - printf(" Message-ID: %s\n", parsed->hdrs.message_id); - thetm = gmtime(&parsed->hdrs.date); - strftime(datebuf, sizeof(datebuf), "%a, %d %b %Y", thetm); - printf(" Date: %s\n", datebuf); - free_rfc822(parsed); - } - } - } - break; -/*}}}*/ - default: - assert(0); - break; - } - - free(hit0); - free(hit1); - free(hit2); - free(hit3); - if ((ft != FT_RAW) && (ft != FT_EXCERPT)) { - printf("Matched %d messages\n", n_hits); - } - fflush(stdout); - - if (had_failed_checksum) { - fprintf(stderr, - "WARNING : \n" - "Matches were found in mbox folders but the message checksums failed.\n" - "You may need to run mairix in indexing mode then repeat your search.\n"); - } - - /* Return error code 1 to the shell if no messages were matched. */ - return (n_hits == 0) ? 1 : 0; -} -/*}}}*/ - -static int directory_exists_remove_other(char *name)/*{{{*/ -{ - struct stat sb; - - if (stat(name, &sb) < 0) { - return 0; - } - if (S_ISDIR(sb.st_mode)) { - return 1; - } else { - /* Try to remove. */ - unlink(name); - return 0; - } -} -/*}}}*/ -static void create_dir(char *path)/*{{{*/ -{ - if (mkdir(path, 0700) < 0) { - fprintf(stderr, "Could not create directory %s\n", path); - unlock_and_exit(2); - } - fprintf(stderr, "Created directory %s\n", path); - return; -} -/*}}}*/ -static void maybe_create_maildir(char *path)/*{{{*/ -{ - char *subdir, *tailpos; - int len; - - if (!directory_exists_remove_other(path)) { - create_dir(path); - } - - len = strlen(path); - subdir = new_array(char, len + 5); - strcpy(subdir, path); - strcpy(subdir+len, "/"); - tailpos = subdir + len + 1; - - strcpy(tailpos,"cur"); - if (!directory_exists_remove_other(subdir)) { - create_dir(subdir); - } - strcpy(tailpos,"new"); - if (!directory_exists_remove_other(subdir)) { - create_dir(subdir); - } - strcpy(tailpos,"tmp"); - if (!directory_exists_remove_other(subdir)) { - create_dir(subdir); - } - free(subdir); - return; -} -/*}}}*/ -static void clear_maildir_subfolder(char *path, char *subdir)/*{{{*/ -{ - char *sdir; - char *fpath; - int len; - DIR *d; - struct dirent *de; - struct stat sb; - - len = strlen(path) + strlen(subdir); - - sdir = new_array(char, len + 2); - fpath = new_array(char, len + 3 + NAME_MAX); - strcpy(sdir, path); - strcat(sdir, "/"); - strcat(sdir, subdir); - - d = opendir(sdir); - if (d) { - while ((de = readdir(d))) { - strcpy(fpath, sdir); - strcat(fpath, "/"); - strcat(fpath, de->d_name); - if (lstat(fpath, &sb) >= 0) { - /* Deal with both symlinks to maildir/MH messages as well as real files - * where mbox messages have been written. */ - if (S_ISLNK(sb.st_mode) || S_ISREG(sb.st_mode)) { - /* FIXME : Can you unlink from a directory while doing a readdir loop over it? */ - if (unlink(fpath) < 0) { - fprintf(stderr, "Unlinking %s failed\n", fpath); - } - } - } - } - closedir(d); - } - - free(fpath); - free(sdir); -} -/*}}}*/ -static void clear_mh_folder(char *path)/*{{{*/ -{ - char *fpath; - int len; - DIR *d; - struct dirent *de; - struct stat sb; - - len = strlen(path); - - fpath = new_array(char, len + 3 + NAME_MAX); - - d = opendir(path); - if (d) { - while ((de = readdir(d))) { - if (valid_mh_filename_p(de->d_name)) { - strcpy(fpath, path); - strcat(fpath, "/"); - strcat(fpath, de->d_name); - if (lstat(fpath, &sb) >= 0) { - /* See under maildir above for explanation */ - if (S_ISLNK(sb.st_mode) || S_ISREG(sb.st_mode)) { - /* FIXME : Can you unlink from a directory while doing a readdir loop over it? */ - if (unlink(fpath) < 0) { - fprintf(stderr, "Unlinking %s failed\n", fpath); - } - } - } - } - } - closedir(d); - } - - free(fpath); -} -/*}}}*/ -static void clear_mbox_folder(char *path)/*{{{*/ -{ - unlink(path); -} -/*}}}*/ - -int search_top(int do_threads, int do_augment, char *database_path, char *complete_mfolder, char **argv, enum folder_type ft, int verbose)/*{{{*/ -{ - struct read_db *db; - int result; - - db = open_db(database_path); - - switch (ft) { - case FT_MAILDIR: - maybe_create_maildir(complete_mfolder); - break; - case FT_MH: - if (!directory_exists_remove_other(complete_mfolder)) { - create_dir(complete_mfolder); - } - break; - case FT_MBOX: - /* Nothing to do */ - break; - case FT_RAW: - case FT_EXCERPT: - break; - default: - assert(0); - } - - if (!do_augment) { - switch (ft) { - case FT_MAILDIR: - clear_maildir_subfolder(complete_mfolder, "new"); - clear_maildir_subfolder(complete_mfolder, "cur"); - break; - case FT_MH: - clear_mh_folder(complete_mfolder); - break; - case FT_MBOX: - clear_mbox_folder(complete_mfolder); - break; - case FT_RAW: - case FT_EXCERPT: - break; - default: - assert(0); - } - } - - result = do_search(db, argv, complete_mfolder, do_threads, ft, verbose); - free(complete_mfolder); - close_db(db); - return result; -} -/*}}}*/ - - diff --git a/src/mairix/stats.c b/src/mairix/stats.c @@ -1,128 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002-2004 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "mairix.h" -#include "memmac.h" -#include "reader.h" - -static void do_toktable(struct toktable *x, int *lc, int *elc, int *ec, int size, int *ml, int *mel, int *me) -{ - int i; - for (i=0; i<x->size; i++) { - struct token *tok = x->tokens[i]; - unsigned char *j, *last_char; - int incr; - - if (tok) { - int len = strlen(tok->text); - if (len > size) { - fprintf(stderr, "Token length %d exceeds size\n", len); - } else { - lc[len]++; - if (len > *ml) *ml = len; - } - - /* Deal with encoding length */ - if (tok->match0.n > size) { - fprintf(stderr, "Token encoding length %d exceeds size\n", tok->match0.n); - } else { - elc[tok->match0.n]++; - if (tok->match0.n > *mel) *mel = tok->match0.n; - } - - /* Deal with encoding */ - j = tok->match0.msginfo; - last_char = j + tok->match0.n; - while (j < last_char) { - incr = read_increment(&j); - if (incr > size) { - fprintf(stderr, "Encoding increment %d exceeds size\n", incr); - } else { - ec[incr]++; - if (incr > *me) *me = incr; - } - } - } - } -} - -void print_table(int *x, int max) { - int total, sum; - int i; - int kk, kk1; - - total = 0; - for (i = 0; i<=max; i++) { - total += x[i]; - } - sum = 0; - kk1 = 0; - for (i = 0; i<=max; i++) { - sum += x[i]; - kk = (int)((double)sum*256.0/(double)total); - printf("%5d : %5d %3d %3d\n", i, x[i], kk-kk1, kk); - kk1 = kk; - } -} - -void get_db_stats(struct database *db) -{ - /* Deal with paths later - problem is, they will be biased by length of folder_base at the moment. */ - - int size = 4096; - int *len_counts, *enc_len_counts, *enc_counts; - int max_len, max_enc_len, max_enc; - - max_len = 0; - max_enc_len = 0; - max_enc = 0; - - len_counts = new_array(int, size); - memset(len_counts, 0, size * sizeof(int)); - enc_len_counts = new_array(int, size); - memset(enc_len_counts, 0, size * sizeof(int)); - enc_counts = new_array(int, size); - memset(enc_counts, 0, size * sizeof(int)); - - do_toktable(db->to, len_counts, enc_len_counts, enc_counts, size, &max_len, &max_enc_len, &max_enc); - do_toktable(db->cc, len_counts, enc_len_counts, enc_counts, size, &max_len, &max_enc_len, &max_enc); - do_toktable(db->from, len_counts, enc_len_counts, enc_counts, size, &max_len, &max_enc_len, &max_enc); - do_toktable(db->subject, len_counts, enc_len_counts, enc_counts, size, &max_len, &max_enc_len, &max_enc); - do_toktable(db->body, len_counts, enc_len_counts, enc_counts, size, &max_len, &max_enc_len, &max_enc); -#if 0 - /* no longer works now that the msg_ids table has 2 encoding chains. fix - * this when required. */ - do_toktable(db->msg_ids, len_counts, enc_len_counts, enc_counts, size, &max_len, &max_enc_len, &max_enc); -#endif - - printf("Max token length : %d\n", max_len); - print_table(len_counts, max_len); - - printf("Max encoding vector length : %d\n", max_enc_len); - print_table(enc_len_counts, max_enc_len); - - printf("Max encoding increment : %d\n", max_enc); - print_table(enc_counts, max_enc); - - return; -} - diff --git a/src/mairix/tok.c b/src/mairix/tok.c @@ -1,344 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002-2004, 2005 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -/* Functions for handling tokens */ - -#include <assert.h> -#include <ctype.h> -#include "mairix.h" - -static void init_matches(struct matches *m) {/*{{{*/ - m->msginfo = NULL; - m->n = 0; - m->max = 0; - m->highest = 0; -} -/*}}}*/ -struct token *new_token(void)/*{{{*/ -{ - struct token *result = new(struct token); - result->text = NULL; - init_matches(&result->match0); - return result; -} -/*}}}*/ -struct token2 *new_token2(void)/*{{{*/ -{ - struct token2 *result = new(struct token2); - result->text = NULL; - init_matches(&result->match0); - init_matches(&result->match1); - return result; -} -/*}}}*/ -void free_token(struct token *x)/*{{{*/ -{ - if (x->text) free(x->text); - if (x->match0.msginfo) free(x->match0.msginfo); - free(x); -} -/*}}}*/ -void free_token2(struct token2 *x)/*{{{*/ -{ - if (x->text) free(x->text); - if (x->match0.msginfo) free(x->match0.msginfo); - if (x->match1.msginfo) free(x->match1.msginfo); - free(x); -} -/*}}}*/ -struct toktable *new_toktable(void)/*{{{*/ -{ - struct toktable *result = new(struct toktable); - result->tokens = NULL; - result->n = 0; - result->hwm = 0; - result->size = 0; - return result; -} -/*}}}*/ -struct toktable2 *new_toktable2(void)/*{{{*/ -{ - struct toktable2 *result = new(struct toktable2); - result->tokens = NULL; - result->n = 0; - result->hwm = 0; - result->size = 0; - return result; -} -/*}}}*/ -void free_toktable(struct toktable *x)/*{{{*/ -{ - if (x->tokens) { - int i; - for (i=0; i<x->size; i++) { - if (x->tokens[i]) { - free_token(x->tokens[i]); - } - } - free(x->tokens); - } - free(x); -} -/*}}}*/ -void free_toktable2(struct toktable2 *x)/*{{{*/ -{ - if (x->tokens) { - int i; - for (i=0; i<x->size; i++) { - if (x->tokens[i]) { - free_token2(x->tokens[i]); - } - } - free(x->tokens); - } - free(x); -} -/*}}}*/ -/* FIXME : This stuff really needs cleaning up. */ -static void enlarge_toktable(struct toktable *table)/*{{{*/ -{ - if (table->size == 0) { - int i; - /* initial allocation */ - table->size = 1024; - table->mask = table->size - 1; - table->tokens = new_array(struct token *, table->size); - for (i=0; i<table->size; i++) { - table->tokens[i] = NULL; - } - } else { - struct token **old_tokens; - int old_size = table->size; - int i; - /* reallocate */ - old_tokens = table->tokens; - table->size <<= 1; - table->mask = table->size - 1; - table->tokens = new_array(struct token *, table->size); - for (i=0; i<table->size; i++) { - table->tokens[i] = NULL; - } - for (i=0; i<old_size; i++) { - unsigned long new_index; - if (old_tokens[i]) { - new_index = old_tokens[i]->hashval & table->mask; - while (table->tokens[new_index]) { - new_index++; - new_index &= table->mask; - } - table->tokens[new_index] = old_tokens[i]; - } - } - free(old_tokens); - } - table->hwm = (table->size >> 2) + (table->size >> 3); /* allow 3/8 of nodes to be used */ -} -/*}}}*/ -static void enlarge_toktable2(struct toktable2 *table)/*{{{*/ -{ - if (table->size == 0) { - int i; - /* initial allocation */ - table->size = 1024; - table->mask = table->size - 1; - table->tokens = new_array(struct token2 *, table->size); - for (i=0; i<table->size; i++) { - table->tokens[i] = NULL; - } - } else { - struct token2 **old_tokens; - int old_size = table->size; - int i; - /* reallocate */ - old_tokens = table->tokens; - table->size <<= 1; - table->mask = table->size - 1; - table->tokens = new_array(struct token2 *, table->size); - for (i=0; i<table->size; i++) { - table->tokens[i] = NULL; - } - for (i=0; i<old_size; i++) { - unsigned long new_index; - if (old_tokens[i]) { - new_index = old_tokens[i]->hashval & table->mask; - while (table->tokens[new_index]) { - new_index++; - new_index &= table->mask; - } - table->tokens[new_index] = old_tokens[i]; - } - } - free(old_tokens); - } - table->hwm = (table->size >> 2) + (table->size >> 3); /* allow 3/8 of nodes to be used */ -} -/*}}}*/ -static int insert_value(unsigned char *x, int val)/*{{{*/ -{ - assert(val >= 0); - if (val <= 127) { - *x = val; - return 1; - } else if (val <= 16383) { - *x++ = (val >> 8) | 0x80; - *x = (val & 0xff); - return 2; - } else { - int a = (val >> 24); - assert (a <= 63); - *x++ = a | 0xc0; - *x++ = ((val >> 16) & 0xff); - *x++ = ((val >> 8) & 0xff); - *x = (val & 0xff); - return 4; - } -} -/*}}}*/ -void check_and_enlarge_encoding(struct matches *m)/*{{{*/ -{ - if (m->n + 4 >= m->max) { - if (m->max == 0) { - m->max = 16; - } else { - m->max += (m->max >> 1); - } - m->msginfo = grow_array(unsigned char, m->max, m->msginfo); - } -} -/*}}}*/ -void insert_index_on_encoding(struct matches *m, int idx)/*{{{*/ -{ - if (m->n == 0) { - /* Always encode value */ - m->n += insert_value(m->msginfo + m->n, idx); - } else { - assert(idx >= m->highest); - if (idx > m->highest) { - int increment = idx - m->highest; - m->n += insert_value(m->msginfo + m->n, increment); - } else { - /* token has already been seen in this file */ - } - } - m->highest = idx; -} -/*}}}*/ -void add_token_in_file(int file_index, unsigned int hash_key, char *tok_text, struct toktable *table)/*{{{*/ -{ - unsigned long hash; - int index; - struct token *tok; - char *lc_tok_text; - char *p; - - lc_tok_text = new_string((char*)tok_text); - for (p = lc_tok_text; *p; p++) { - *p = tolower(*(unsigned char *) p); - } - /* 2nd arg is string length */ - hash = hashfn((unsigned char *) lc_tok_text, p - lc_tok_text, hash_key); - - if (table->n >= table->hwm) { - enlarge_toktable(table); - } - - index = hash & table->mask; - while (table->tokens[index]) { - /* strcmp ok as text has been tolower'd earlier */ - if (!strcmp(lc_tok_text, table->tokens[index]->text)) - break; - index++; - index &= table->mask; - } - - if (!table->tokens[index]) { - /* Allocate new */ - struct token *new_tok = new_token(); - /* New token takes ownership of lc_tok_text, no need to free that later. */ - new_tok->text = (char *) lc_tok_text; - new_tok->hashval = hash; /* save full width for later */ - table->tokens[index] = new_tok; - ++table->n; - } else { - free(lc_tok_text); - } - - tok = table->tokens[index]; - - check_and_enlarge_encoding(&tok->match0); - insert_index_on_encoding(&tok->match0, file_index); -} -/*}}}*/ -void add_token2_in_file(int file_index, unsigned int hash_key, char *tok_text, struct toktable2 *table, int add_to_chain1)/*{{{*/ -{ - unsigned long hash; - int index; - struct token2 *tok; - char *lc_tok_text; - char *p; - - lc_tok_text = new_string(tok_text); - for (p = lc_tok_text; *p; p++) { - *p = tolower(*(unsigned char *) p); - } - /* 2nd arg is string length */ - hash = hashfn((unsigned char *) lc_tok_text, p - lc_tok_text, hash_key); - - if (table->n >= table->hwm) { - enlarge_toktable2(table); - } - - index = hash & table->mask; - while (table->tokens[index]) { - /* strcmp ok as text has been tolower'd earlier */ - if (!strcmp(lc_tok_text, table->tokens[index]->text)) - break; - index++; - index &= table->mask; - } - - if (!table->tokens[index]) { - /* Allocate new */ - struct token2 *new_tok = new_token2(); - /* New token takes ownership of lc_tok_text, no need to free that later. */ - new_tok->text = lc_tok_text; - new_tok->hashval = hash; /* save full width for later */ - table->tokens[index] = new_tok; - ++table->n; - } else { - free(lc_tok_text); - } - - tok = table->tokens[index]; - - check_and_enlarge_encoding(&tok->match0); - insert_index_on_encoding(&tok->match0, file_index); - if (add_to_chain1) { - check_and_enlarge_encoding(&tok->match1); - insert_index_on_encoding(&tok->match1, file_index); - } -} -/*}}}*/ - - - - diff --git a/src/mairix/version.h b/src/mairix/version.h @@ -1,4 +0,0 @@ -#ifndef VERSION_H -#define VERSION_H 1 -#define PROGRAM_VERSION "0.23" -#endif /* VERSION_H */ diff --git a/src/mairix/version.txt b/src/mairix/version.txt @@ -1 +0,0 @@ -0.23 diff --git a/src/mairix/writer.c b/src/mairix/writer.c @@ -1,614 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002,2003,2004,2005,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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -/* Write the database to disc. */ - -#include "mairix.h" -#include "reader.h" - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <assert.h> -#include <sys/mman.h> - -struct write_map_toktable {/*{{{*/ - - /* Table of character offsets to null-terminated token texts */ - int tok_offset; - - /* Table of character offsets to byte strings containing compressed - * delta-encoding of file indices matching the token */ - int enc_offset; -};/*}}}*/ -struct write_map_toktable2 {/*{{{*/ - - /* Table of character offsets to null-terminated token texts */ - int tok_offset; - - /* Table of character offsets to byte strings containing compressed - * delta-encoding of file indices matching the token */ - int enc0_offset; - int enc1_offset; -};/*}}}*/ - -struct write_map {/*{{{*/ -/* Contain offset information for the various tables. - UI stuff in 4 byte units rel to base addr. - Char stuff in byte units rel to base addr. */ - - /* Path information */ - int path_offset; - int mtime_offset; /* Message file mtimes (maildir/mh), mbox number (mbox) */ - int size_offset; /* Message sizes (maildir/mh), entry in respective mbox (mbox) */ - int date_offset; /* Message dates (all folder types) */ - int tid_offset; /* Thread group index table (all folder types) */ - - int mbox_paths_offset; - int mbox_entries_offset; - int mbox_mtime_offset; - int mbox_size_offset; - /* Character offset to checksum of first msg in the mbox. Positions of - * subsequent messages computed by indexing - no explicit table entries - * anywhere. */ - int mbox_checksum_offset; - - struct write_map_toktable to; - struct write_map_toktable cc; - struct write_map_toktable from; - struct write_map_toktable subject; - struct write_map_toktable body; - struct write_map_toktable attachment_name; - struct write_map_toktable2 msg_ids; - - /* To get base address for character data */ - int beyond_last_ui_offset; -}; -/*}}}*/ - -static void create_rw_mapping(char *filename, size_t len, int *out_fd, char **out_data)/*{{{*/ -{ - int fd; - char *data; - struct stat sb; - - fd = open(filename, O_RDWR | O_CREAT, 0600); - if (fd < 0) { - report_error("open", filename); - unlock_and_exit(2); - } - - if (fstat(fd, &sb) < 0) { - report_error("stat", filename); - unlock_and_exit(2); - } - - if (sb.st_size < len) { - /* Extend */ - if (lseek(fd, len - 1, SEEK_SET) < 0) { - report_error("lseek", filename); - unlock_and_exit(2); - } - if (write(fd, "\000", 1) < 0) { - report_error("write", filename); - unlock_and_exit(2); - } - } else if (sb.st_size > len) { - /* Truncate */ - if (ftruncate(fd, len) < 0) { - report_error("ftruncate", filename); - unlock_and_exit(2); - } - } else { - /* Exactly the right length already - nothing to do! */ - } - - data = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) { - report_error("writer:mmap", filename); - unlock_and_exit(2); - } - - *out_data = data; - *out_fd = fd; -} -/*}}}*/ - -static int toktable_char_length(struct toktable *tab)/*{{{*/ -{ - int result = 0; - int i; - for (i=0; i<tab->size; i++) { - if (tab->tokens[i]) { - result += (1 + strlen(tab->tokens[i]->text)); - result += (1 + tab->tokens[i]->match0.n); - } - } - return result; -} -/*}}}*/ -static int toktable2_char_length(struct toktable2 *tab)/*{{{*/ -{ - int result = 0; - int i; - for (i=0; i<tab->size; i++) { - if (tab->tokens[i]) { - result += (1 + strlen(tab->tokens[i]->text)); - result += (1 + tab->tokens[i]->match0.n); - result += (1 + tab->tokens[i]->match1.n); - } - } - return result; -} -/*}}}*/ -static int char_length(struct database *db)/*{{{*/ -{ - /* Return total length of character data to be written. */ - int result; - int i; - - result = 0; - - /* For type table. */ - result += db->n_msgs; - - for (i=0; i<db->n_msgs; i++) { - switch (db->type[i]) { - case MTY_DEAD: - break; - case MTY_MBOX: - break; - case MTY_FILE: - assert(db->msgs[i].src.mpf.path); - result += (1 + strlen(db->msgs[i].src.mpf.path)); - break; - } - } - - for (i=0; i<db->n_mboxen; i++) { - struct mbox *mb = &db->mboxen[i]; - result += mb->n_msgs * sizeof(checksum_t); - if (mb->path) { - result += (1 + strlen(mb->path)); - } - } - - result += toktable_char_length(db->to); - result += toktable_char_length(db->cc); - result += toktable_char_length(db->from); - result += toktable_char_length(db->subject); - result += toktable_char_length(db->body); - result += toktable_char_length(db->attachment_name); - result += toktable2_char_length(db->msg_ids); - - return result; -} -/*}}}*/ - -static void compute_mapping(struct database *db, struct write_map *map)/*{{{*/ -{ - int total = UI_HEADER_LEN; - - map->path_offset = total, total += db->n_msgs; - map->mtime_offset = total, total += db->n_msgs; - map->date_offset = total, total += db->n_msgs; - map->size_offset = total, total += db->n_msgs; - map->tid_offset = total, total += db->n_msgs; - - map->mbox_paths_offset = total, total += db->n_mboxen; - map->mbox_entries_offset = total, total += db->n_mboxen; - map->mbox_mtime_offset = total, total += db->n_mboxen; - map->mbox_size_offset = total, total += db->n_mboxen; - map->mbox_checksum_offset = total, total += db->n_mboxen; - - map->to.tok_offset = total, total += db->to->n; - map->to.enc_offset = total, total += db->to->n; - - map->cc.tok_offset = total, total += db->cc->n; - map->cc.enc_offset = total, total += db->cc->n; - - map->from.tok_offset = total, total += db->from->n; - map->from.enc_offset = total, total += db->from->n; - - map->subject.tok_offset = total, total += db->subject->n; - map->subject.enc_offset = total, total += db->subject->n; - - map->body.tok_offset = total, total += db->body->n; - map->body.enc_offset = total, total += db->body->n; - - map->attachment_name.tok_offset = total, total += db->attachment_name->n; - map->attachment_name.enc_offset = total, total += db->attachment_name->n; - - map->msg_ids.tok_offset = total, total += db->msg_ids->n; - map->msg_ids.enc0_offset = total, total += db->msg_ids->n; - map->msg_ids.enc1_offset = total, total += db->msg_ids->n; - - map->beyond_last_ui_offset = total; -} -/*}}}*/ -static void write_header(char *data, unsigned int *uidata, struct database *db, struct write_map *map)/*{{{*/ -{ - /* Endianness-independent writes - at least the magic number will be - * recognized if the database is read by this program on a machine of - * opposite endianness. */ - unsigned char *ucdata = (unsigned char *) data; - - ucdata[0] = HEADER_MAGIC0; - ucdata[1] = HEADER_MAGIC1; - ucdata[2] = HEADER_MAGIC2; - ucdata[3] = HEADER_MAGIC3; - - uidata[UI_ENDIAN] = 0x44332211; /* For checking reversed endianness on read */ - uidata[UI_N_MSGS] = db->n_msgs; - uidata[UI_MSG_CDATA] = map->path_offset; /* offset table of ptrs to filenames */ - uidata[UI_MSG_MTIME] = map->mtime_offset; /* offset of mtime table */ - uidata[UI_MSG_DATE] = map->date_offset; /* offset of table of message Date: header lines as time_t */ - uidata[UI_MSG_SIZE] = map->size_offset; /* offset of table of message sizes in bytes */ - uidata[UI_MSG_TID] = map->tid_offset; /* offset of table of thread group numbers */ - - uidata[UI_MBOX_N] = db->n_mboxen; - uidata[UI_MBOX_PATHS] = map->mbox_paths_offset; - uidata[UI_MBOX_ENTRIES] = map->mbox_entries_offset; - uidata[UI_MBOX_MTIME] = map->mbox_mtime_offset; - uidata[UI_MBOX_SIZE] = map->mbox_size_offset; - uidata[UI_MBOX_CKSUM] = map->mbox_checksum_offset; - - uidata[UI_HASH_KEY] = db->hash_key; - - uidata[UI_TO_N] = db->to->n; - uidata[UI_TO_TOK] = map->to.tok_offset; - uidata[UI_TO_ENC] = map->to.enc_offset; - - uidata[UI_CC_N] = db->cc->n; - uidata[UI_CC_TOK] = map->cc.tok_offset; - uidata[UI_CC_ENC] = map->cc.enc_offset; - - uidata[UI_FROM_N] = db->from->n; - uidata[UI_FROM_TOK] = map->from.tok_offset; - uidata[UI_FROM_ENC] = map->from.enc_offset; - - uidata[UI_SUBJECT_N] = db->subject->n; - uidata[UI_SUBJECT_TOK] = map->subject.tok_offset; - uidata[UI_SUBJECT_ENC] = map->subject.enc_offset; - - uidata[UI_BODY_N] = db->body->n; - uidata[UI_BODY_TOK] = map->body.tok_offset; - uidata[UI_BODY_ENC] = map->body.enc_offset; - - uidata[UI_ATTACHMENT_NAME_N] = db->attachment_name->n; - uidata[UI_ATTACHMENT_NAME_TOK] = map->attachment_name.tok_offset; - uidata[UI_ATTACHMENT_NAME_ENC] = map->attachment_name.enc_offset; - - uidata[UI_MSGID_N] = db->msg_ids->n; - uidata[UI_MSGID_TOK] = map->msg_ids.tok_offset; - uidata[UI_MSGID_ENC0] = map->msg_ids.enc0_offset; - uidata[UI_MSGID_ENC1] = map->msg_ids.enc1_offset; - - return; -} -/*}}}*/ -static char *write_type_and_flag_table(struct database *db, unsigned int *uidata, char *data, char *cdata)/*{{{*/ -{ - int i; - for (i=0; i<db->n_msgs; i++) { - struct msgpath *msgdata = db->msgs + i; - switch (db->type[i]) { - case MTY_FILE: - cdata[i] = DB_MSG_FILE; - break; - case MTY_MBOX: - cdata[i] = DB_MSG_MBOX; - break; - case MTY_DEAD: - cdata[i] = DB_MSG_DEAD; - break; - } - - if (msgdata->seen) cdata[i] |= FLAG_SEEN; - if (msgdata->replied) cdata[i] |= FLAG_REPLIED; - if (msgdata->flagged) cdata[i] |= FLAG_FLAGGED; - } - uidata[UI_MSG_TYPE_AND_FLAGS] = cdata - data; - return cdata + db->n_msgs; -} -/*}}}*/ -static char *write_messages(struct database *db, struct write_map *map, unsigned int *uidata, char *data, char *cdata)/*{{{*/ -{ - int i; - char *start_cdata = cdata; - - for (i=0; i<db->n_msgs; i++) { - int slen; - switch (db->type[i]) { - case MTY_FILE: - slen = strlen(db->msgs[i].src.mpf.path); - uidata[map->path_offset + i] = cdata - data; - uidata[map->mtime_offset + i] = db->msgs[i].src.mpf.mtime; - uidata[map->size_offset + i] = db->msgs[i].src.mpf.size; - uidata[map->date_offset + i] = db->msgs[i].date; - uidata[map->tid_offset + i] = db->msgs[i].tid; - memcpy(cdata, db->msgs[i].src.mpf.path, 1 + slen); /* include trailing null */ - cdata += (1 + slen); - break; - case MTY_MBOX: - { - int mbno = db->msgs[i].src.mbox.file_index; - int msgno = db->msgs[i].src.mbox.msg_index; - struct mbox *mb = &db->mboxen[mbno]; - uidata[map->path_offset + i] = encode_mbox_indices(mbno, msgno); - uidata[map->mtime_offset + i] = mb->start[msgno]; - uidata[map->size_offset + i] = mb->len[msgno]; - uidata[map->date_offset + i] = db->msgs[i].date; - uidata[map->tid_offset + i] = db->msgs[i].tid; - } - break; - case MTY_DEAD: - uidata[map->path_offset + i] = 0; /* Can't ever happen for real */ - uidata[map->mtime_offset + i] = 0; /* For cleanliness */ - uidata[map->size_offset + i] = 0; /* For cleanliness */ - /* The following line is necessary, otherwise 'random' tid - * information is written to the database, which can crash the search - * functions. */ - uidata[map->tid_offset + i] = db->msgs[i].tid; - break; - } - } - if (verbose) { - printf("Wrote %d messages (%d bytes of tables, %d bytes of text)\n", - db->n_msgs, 4*5*db->n_msgs, (int)(cdata - start_cdata)); - } - return cdata; /* new value */ -} -/*}}}*/ -#if 0 -static int compare_tokens(const void *a, const void *b)/*{{{*/ -{ - const struct token **aa = (const struct token **) a; - const struct token **bb = (const struct token **) b; - return strcmp((*aa)->text, (*bb)->text); -} -/*}}}*/ -#endif - -static char *write_mbox_headers(struct database *db, struct write_map *map, unsigned int *uidata, char *data, char *cdata)/*{{{*/ -{ - int i, len; - char *start_cdata = cdata; - - for (i=0; i<db->n_mboxen; i++) { - struct mbox *mb = &db->mboxen[i]; - uidata[map->mbox_entries_offset + i] = mb->n_msgs; - uidata[map->mbox_mtime_offset + i] = mb->current_mtime; - uidata[map->mbox_size_offset + i] = mb->current_size; - if (mb->path) { - uidata[map->mbox_paths_offset + i] = cdata - data; - len = strlen(mb->path); - memcpy(cdata, mb->path, 1+len); - cdata += 1+len; - } else { - uidata[map->mbox_paths_offset + i] = 0; - } - } - if (verbose) { - printf("Wrote %d mbox headers (%d bytes of tables, %d bytes of paths)\n", - db->n_mboxen, 4*4*db->n_mboxen, (int)(cdata - start_cdata)); - } - return cdata; -} -/*}}}*/ -static char * write_mbox_checksums(struct database *db, struct write_map *map, unsigned int *uidata, char *data, char *cdata)/*{{{*/ -{ - int i, j; - char *start_cdata = cdata; - - for (i=0; i<db->n_mboxen; i++) { - struct mbox *mb = &db->mboxen[i]; - uidata[map->mbox_checksum_offset + i] = cdata - data; - for (j=0; j<mb->n_msgs; j++) { - memcpy(cdata, mb->check_all[j], sizeof(checksum_t)); - cdata += sizeof(checksum_t); - } - } - if (verbose) { - printf("Wrote %d bytes of mbox message checksums\n", - (int)(cdata - start_cdata)); - } - return cdata; -} -/*}}}*/ - -static char *write_toktable(struct toktable *tab, struct write_map_toktable *map, unsigned int *uidata, char *data, char *cdata, char *header_name)/*{{{*/ -{ - int i, j, n, max; - char *start_cdata, *mid_cdata; - struct token **stok; - stok = new_array(struct token *, tab->n); - max = tab->size; - n = tab->n; - - for (i=0, j=0; i<max; i++) { - struct token *tok = tab->tokens[i]; - if (tok) { - stok[j++] = tok; - } - } - - assert(j == n); - -#if 0 - /* The search functions don't rely on the tokens being sorted. So not - * sorting here will save time. */ - qsort(stok, n, sizeof(struct token *), compare_tokens); -#endif - - start_cdata = cdata; - - /* FIXME : Eventually, the tokens have to be sorted - need to feed them from - * a different data structure (array with no holes) */ - for (i=0; i<n; i++) { - int slen; - uidata[map->tok_offset + i] = cdata - data; - slen = strlen(stok[i]->text); - memcpy(cdata, stok[i]->text, 1 + slen); - cdata += (1 + slen); - } - - mid_cdata = cdata; - - for (i=0; i<n; i++) { - int dlen; - dlen = stok[i]->match0.n; - uidata[map->enc_offset + i] = cdata - data; - memcpy(cdata, stok[i]->match0.msginfo, dlen); - cdata += dlen; - *cdata++ = 0xff; /* termination character */ - } - - if (verbose) { - printf("%s: Wrote %d tokens (%d bytes of tables, %d bytes of text, %d bytes of hit encoding)\n", - header_name, n, 2*4*n, (int)(mid_cdata - start_cdata), (int)(cdata - mid_cdata)); - } - - free(stok); - return cdata; -} -/*}}}*/ -static char *write_toktable2(struct toktable2 *tab, struct write_map_toktable2 *map, unsigned int *uidata, char *data, char *cdata, char *header_name)/*{{{*/ -{ - int i, j, n, max; - char *start_cdata, *mid_cdata; - struct token2 **stok; - stok = new_array(struct token2 *, tab->n); - max = tab->size; - n = tab->n; - - for (i=0, j=0; i<max; i++) { - struct token2 *tok = tab->tokens[i]; - if (tok) { - stok[j++] = tok; - } - } - - assert(j == n); - -#if 0 - /* The search functions don't rely on the tokens being sorted. So not - * sorting here will save time. */ - qsort(stok, n, sizeof(struct token *), compare_tokens); -#endif - - start_cdata = cdata; - - /* FIXME : Eventually, the tokens have to be sorted - need to feed them from - * a different data structure (array with no holes) */ - for (i=0; i<n; i++) { - int slen; - uidata[map->tok_offset + i] = cdata - data; - slen = strlen(stok[i]->text); - memcpy(cdata, stok[i]->text, 1 + slen); - cdata += (1 + slen); - } - - mid_cdata = cdata; - - for (i=0; i<n; i++) { - int dlen; - dlen = stok[i]->match0.n; - uidata[map->enc0_offset + i] = cdata - data; - memcpy(cdata, stok[i]->match0.msginfo, dlen); - cdata += dlen; - *cdata++ = 0xff; /* termination character */ - } - - for (i=0; i<n; i++) { - int dlen; - dlen = stok[i]->match1.n; - uidata[map->enc1_offset + i] = cdata - data; - memcpy(cdata, stok[i]->match1.msginfo, dlen); - cdata += dlen; - *cdata++ = 0xff; /* termination character */ - } - - if (verbose) { - printf("%s: Wrote %d tokens (%d bytes of tables, %d bytes of text, %d bytes of hit encoding)\n", - header_name, n, 2*4*n, (int)(mid_cdata - start_cdata), (int)(cdata - mid_cdata)); - } - - free(stok); - return cdata; -} -/*}}}*/ -void write_database(struct database *db, char *filename, int do_integrity_checks)/*{{{*/ -{ - int file_len; - int fd; - char *data, *cdata; - unsigned int *uidata; - struct write_map map; - - if (do_integrity_checks) { - check_database_integrity(db); - } - - if (!verify_mbox_size_constraints(db)) { - unlock_and_exit(1); - } - - /* Work out mappings */ - compute_mapping(db, &map); - - file_len = char_length(db) + (4 * map.beyond_last_ui_offset); - - create_rw_mapping(filename, file_len, &fd, &data); - uidata = (unsigned int *) data; /* align(int) < align(page)! */ - cdata = data + (4 * map.beyond_last_ui_offset); - - write_header(data, uidata, db, &map); - cdata = write_type_and_flag_table(db, uidata, data, cdata); - cdata = write_messages(db, &map, uidata, data, cdata); - cdata = write_mbox_headers(db, &map, uidata, data, cdata); - cdata = write_mbox_checksums(db, &map, uidata, data, cdata); - cdata = write_toktable(db->to, &map.to, uidata, data, cdata, "To"); - cdata = write_toktable(db->cc, &map.cc, uidata, data, cdata, "Cc"); - cdata = write_toktable(db->from, &map.from, uidata, data, cdata, "From"); - cdata = write_toktable(db->subject, &map.subject, uidata, data, cdata, "Subject"); - cdata = write_toktable(db->body, &map.body, uidata, data, cdata, "Body"); - cdata = write_toktable(db->attachment_name, &map.attachment_name, uidata, data, cdata, "Attachment Name"); - cdata = write_toktable2(db->msg_ids, &map.msg_ids, uidata, data, cdata, "(Threading)"); - - /* Write data */ - /* Unmap / close file */ - if (munmap(data, file_len) < 0) { - report_error("munmap", filename); - unlock_and_exit(2); - } - if (fsync(fd) < 0) { - report_error("fsync", filename); - unlock_and_exit(2); - } - if (close(fd) < 0) { - report_error("close", filename); - unlock_and_exit(2); - } -} - /*}}}*/ diff --git a/src/nvp.c b/src/nvp.c @@ -1,416 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2006,2007 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#ifdef VERBOSE_TEST -#define TEST 1 -#endif - -/* 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); -} -/*}}}*/ -static void combine_namevalue(struct nvp *nvp, char *name, char *value)/*{{{*/ -{ - struct nvp_entry *n; - for (n=nvp->first; n; n=n->next) { - if (n->type == NVP_NAMEVALUE) { - if (!strcmp(n->lhs, name)) { - char *new_rhs; - new_rhs = new_array(char, strlen(n->rhs) + strlen(value) + 1); - strcpy(new_rhs, n->rhs); - strcat(new_rhs, value); - free(n->rhs); - n->rhs = new_rhs; - return; - } - } - } - /* No match : it's the first one */ - append_namevalue(nvp, name, value); -} -/*}}}*/ -static void release_nvp(struct nvp *nvp)/*{{{*/ -{ - struct nvp_entry *e, *ne; - for (e=nvp->first; e; e=ne) { - ne = e->next; - switch (e->type) { - case NVP_NAME: - free(e->lhs); - break; - case NVP_MAJORMINOR: - case NVP_NAMEVALUE: - free(e->lhs); - free(e->rhs); - break; - } - free(e); - } - free(nvp); -} -/*}}}*/ -struct nvp *make_nvp(struct msg_src *src, char *s, const char *pfx)/*{{{*/ -{ - int current_state; - unsigned int tok; - char *q; - unsigned char qq; - char name[256]; - char minor[256]; - char value[256]; - enum nvp_action last_action, current_action; - struct nvp *result; - size_t pfxlen; - char *nn, *mm, *vv; - - pfxlen = strlen(pfx); - if (strncasecmp(pfx, s, pfxlen)) - return NULL; - s += pfxlen; - - 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 { - qq = *(unsigned char *) q; - if (qq) { - tok = nvp_char2tok[qq]; - } else { - tok = nvp_EOS; - } - current_state = nvp_next_state(current_state, tok); -#ifdef VERBOSE_TEST - fprintf(stderr, "Char %02x (%c) tok=%d new_current_state=%d\n", - qq, ((qq>=32) && (qq<=126)) ? qq : '.', - tok, current_state); -#endif - - if (current_state < 0) { -#ifdef TEST - fprintf(stderr, "'%s' could not be parsed\n", s); -#else - fprintf(stderr, "Header '%s%s' in %s could not be parsed\n", - pfx, s, format_msg_src(src)); -#endif - release_nvp(result); - return NULL; - } - - switch (nvp_copier[current_state]) { - case COPY_TO_NAME: -#ifdef VERBOSE_TEST - fprintf(stderr, " COPY_TO_NAME\n"); -#endif - *nn++ = *q; - break; - case COPY_TO_MINOR: -#ifdef VERBOSE_TEST - fprintf(stderr, " COPY_TO_MINOR\n"); -#endif - *mm++ = *q; - break; - case COPY_TO_VALUE: -#ifdef VERBOSE_TEST - fprintf(stderr, " COPY_TO_VALUE\n"); -#endif - *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: - case GOT_NAMEVALUE_CONT: -#ifdef VERBOSE_TEST - fprintf(stderr, " Setting last action to %d\n", current_action); -#endif - last_action = current_action; - break; - case GOT_TERMINATOR: -#ifdef VERBOSE_TEST - fprintf(stderr, " Hit terminator; last_action=%d\n", last_action); -#endif - 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; - case GOT_NAMEVALUE_CONT: - *nn = 0; - *vv = 0; - combine_namevalue(result, name, value); - break; - default: - break; - } - nn = name; - mm = minor; - vv = value; - break; - case GOT_NOTHING: - break; - } - - q++; - } while (tok != nvp_EOS); - - return result; -} -/*}}}*/ -void free_nvp(struct nvp *nvp)/*{{{*/ -{ - struct nvp_entry *ne, *nne; - for (ne = nvp->first; ne; ne=nne) { - nne = ne->next; - switch (ne->type) { - case NVP_NAME: - free(ne->lhs); - break; - case NVP_MAJORMINOR: - case NVP_NAMEVALUE: - free(ne->lhs); - free(ne->rhs); - break; - } - free(ne); - } - free(nvp); -} -/*}}}*/ -const char *nvp_lookup(struct nvp *nvp, const char *name)/*{{{*/ -{ - struct nvp_entry *ne; - for (ne = nvp->first; ne; ne=ne->next) { - if (ne->type == NVP_NAMEVALUE) { - if (!strcmp(ne->lhs, name)) { - return ne->rhs; - } - } - } - return NULL; -} -/*}}}*/ -const char *nvp_lookupcase(struct nvp *nvp, const char *name)/*{{{*/ -{ - struct nvp_entry *ne; - for (ne = nvp->first; ne; ne=ne->next) { - if (ne->type == NVP_NAMEVALUE) { - if (!strcasecmp(ne->lhs, name)) { - return ne->rhs; - } - } - } - return NULL; -} -/*}}}*/ - -void nvp_dump(struct nvp *nvp, FILE *out)/*{{{*/ -{ - struct nvp_entry *ne; - fprintf(out, "----\n"); - for (ne = nvp->first; ne; ne=ne->next) { - switch (ne->type) { - case NVP_NAME: - fprintf(out, "NAME: %s\n", ne->lhs); - break; - case NVP_MAJORMINOR: - fprintf(out, "MAJORMINOR: %s/%s\n", ne->lhs, ne->rhs); - break; - case NVP_NAMEVALUE: - fprintf(out, "NAMEVALUE: %s=%s\n", ne->lhs, ne->rhs); - break; - } - } -} -/*}}}*/ - -/* In these cases, we only look at the first entry */ -const char *nvp_major(struct nvp *nvp)/*{{{*/ -{ - struct nvp_entry *ne; - ne = nvp->first; - if (ne) { - if (ne->type == NVP_MAJORMINOR) { - return ne->lhs; - } else { - return NULL; - } - } else { - return NULL; - } -} -/*}}}*/ -const char *nvp_minor(struct nvp *nvp)/*{{{*/ -{ - struct nvp_entry *ne; - ne = nvp->first; - if (ne) { - if (ne->type == NVP_MAJORMINOR) { - return ne->rhs; - } else { - return NULL; - } - } else { - return NULL; - } -} -/*}}}*/ -const char *nvp_first(struct nvp *nvp)/*{{{*/ -{ - struct nvp_entry *ne; - ne = nvp->first; - if (ne) { - if (ne->type == NVP_NAME) { - return ne->lhs; - } else { - return NULL; - } - } else { - return NULL; - } -} -/*}}}*/ - -#ifdef TEST - -static void do_test(char *s) -{ - struct nvp *n; - n = make_nvp(NULL, s, ""); - if (n) { - nvp_dump(n, stderr); - free_nvp(n); - } -} - - -int main (int argc, char **argv) { - struct nvp *n; -#if 0 - do_test("attachment; filename=\"foo.c\"; prot=ro"); - do_test("attachment; filename= \"foo bar.c\" ;prot=ro"); - do_test("attachment ; filename= \"foo bar.c\" ;prot= ro"); - do_test("attachment ; filename= \"foo bar.c\" ;prot= ro"); - do_test("attachment ; filename= \"foo ; bar.c\" ;prot= ro"); - do_test("attachment ; x*0=\"hi \"; x*1=\"there\""); -#endif - - do_test("application/vnd.ms-excel; name=\"thequiz.xls\""); -#if 0 - do_test("inline; filename*0=\"aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj\t kkkkllll\""); - do_test(" text/plain ; name= \"foo bar.c\" ;prot= ro/rw; read/write; read= foo bar"); -#endif - return 0; -} -#endif - - - - diff --git a/src/nvp.h b/src/nvp.h @@ -1,38 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2006,2010 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#ifndef NVP_H -#define NVP_H - -struct nvp; -struct msg_src; -extern struct nvp *make_nvp(struct msg_src *, char *, const char *); -extern void free_nvp(struct nvp *); -extern void nvp_dump(struct nvp *nvp, FILE *out); -extern const char *nvp_major(struct nvp *n); -extern const char *nvp_minor(struct nvp *n); -extern const char *nvp_first(struct nvp *n); -extern const char *nvp_lookup(struct nvp *n, const char *name); -extern const char *nvp_lookupcase(struct nvp *n, const char *name); - -#endif - diff --git a/src/nvp.nfa b/src/nvp.nfa @@ -1,197 +0,0 @@ -######################################################################### -# -# mairix - message index builder and finder for maildir folders. -# -# Copyright (C) Richard P. Curnow 2006,2007 -# -# 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., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# ======================================================================= - -Tokens EOS -Abbrev VALUE = [\041-~]~[\\";] -Abbrev QVALUE = VALUE | [\011\040;] | <escape:in->out> -Abbrev NAME1 = [0-9a-zA-Z_\-] -Abbrev MINOR = NAME1 | [\.\-+] -Abbrev OWS = <optwhite:in->out> - -%{ -#include "nvptypes.h" -%} - -Block escape { - State in - [\\] ; [\\] -> out - [\\] ; ["] -> out -} - -Block optwhite { - State in - -> out - # I have seen headers with ^M in them... - [ \t\r] -> in -} - -Block name { - # This needs to cope with embedded spaces, e.g. for mailers that write '7 - # bit' instead of '7bit' - State in - NAME1 -> name1 - - State name1 - = COPY_TO_NAME - = GOT_NAME - NAME1 -> name1 - [ \t] -> name2 - -> out - - State name2 - = COPY_TO_NAME - = GOT_NAME_TRAILING_SPACE - [ \t] -> name2 - NAME1 -> name1 - -> out - - State out -} - -Block value { - State in - VALUE -> v1 - State v1 - = COPY_TO_VALUE - -> out - VALUE -> v1 -} - -Block qvalue { - State in - ["] -> qv0 - - State qv0 - QVALUE -> qv1 - - State qv1 - = COPY_TO_VALUE - QVALUE -> qv1 - -> qv2 - - State qv2 - ["] -> out -} - -Block digits { - State in - [0-9] -> out - [0-9] -> in -} - -Block namevalue { - State in - OWS ; <name:in->out> ; OWS ; [=] -> rhs_normal - OWS ; <name:in->out> ; [*] ; <digits:in->out> ; OWS ; [=] -> rhs_continue - - State rhs_normal - OWS ; <qvalue:in->out> ; OWS -> out_normal - OWS ; <value:in->out> ; OWS -> out_normal - OWS ; ; EOS -> out_normal - - State rhs_continue - OWS ; <qvalue:in->out> ; OWS -> out_continue - OWS ; <value:in->out> ; OWS -> out_continue - - State out_normal = GOT_NAMEVALUE - -> out - State out_continue = GOT_NAMEVALUE_CONT - -> out -} - -Block major { - State in - NAME1 -> name1 - - State name1 - NAME1 -> name1 - -> out -} - -Block minor { - State in - MINOR -> minor1 - - State minor1 - = COPY_TO_MINOR - MINOR -> minor1 - -> out -} - -Block majorminor { - State in - <major:in->out> -> foo - - State foo - [/] -> bar - - State bar - <minor:in->out> -> out - - State out = GOT_MAJORMINOR -} - -Block component { - State in - <namevalue:in->out> -> out - <name:in->out> -> out - <majorminor:in->out> -> out -} - -Block main { - State in Entry in - OWS ; <component:in->out> ; OWS ; EOS -> out2 - OWS ; <component:in->out> ; OWS ; [;] ; OWS ; EOS -> out2 - OWS ; <component:in->out> ; OWS ; [;] -> in2 - - State in2 - = GOT_TERMINATOR - -> in - - State out2 - = GOT_TERMINATOR - -> out -} - -Defattr 0 -Prefix nvp - -Group action { - Attr GOT_NAMEVALUE - Attr GOT_NAMEVALUE_CONT - Attr GOT_NAME - Attr GOT_NAME_TRAILING_SPACE - Attr GOT_MAJORMINOR - Attr GOT_TERMINATOR - Defattr GOT_NOTHING - Type "enum nvp_action" -} - -Group copier { - Attr COPY_TO_NAME - Attr COPY_TO_MINOR - Attr COPY_TO_VALUE - Defattr COPY_NOWHERE - Type "enum nvp_copier" -} - -# vim:et:sts=4:sw=4:ht=8 - diff --git a/src/nvptypes.h b/src/nvptypes.h @@ -1,43 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2006,2007 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#ifndef NVPTYPES_H -#define NVPTYPES_H - -enum nvp_action { - GOT_NAMEVALUE, - GOT_NAMEVALUE_CONT, - GOT_NAME, - GOT_NAME_TRAILING_SPACE, - GOT_MAJORMINOR, - GOT_TERMINATOR, - GOT_NOTHING -}; - -enum nvp_copier { - COPY_TO_NAME, - COPY_TO_MINOR, - COPY_TO_VALUE, - COPY_NOWHERE -}; - -#endif diff --git a/src/rfc822_mairix.c b/src/rfc822_mairix.c @@ -1,1536 +0,0 @@ -/* - mairix - message index builder and finder for maildir folders. - - ********************************************************************** - * Copyright (C) Richard P. Curnow 2002,2003,2004,2005,2006,2007,2010 - * rfc2047 decode: - * Copyright (C) Mikael Ylikoski 2002 - * gzip mbox support: - * Copyright (C) Ico Doornekamp 2005 - * Copyright (C) Felipe Gustavo de Almeida 2005 - * bzip2 mbox support: - * Copyright (C) Paramjit Oberoi 2005 - * caching uncompressed mbox data: - * Copyright (C) Chris Mason 2006 - * memory leak fixes: - * Copyright (C) Samuel Tardieu 2008 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - ********************************************************************** - */ - -#include "mairix.h" -#include "nvp.h" - -#include <assert.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/mman.h> -#ifdef USE_GZIP_MBOX -# include <zlib.h> -#endif -#ifdef USE_BZIP_MBOX -# include <bzlib.h> -#endif - -struct DLL {/*{{{*/ - struct DLL *next; - struct DLL *prev; -}; -/*}}}*/ -static void enqueue(void *head, void *x)/*{{{*/ -{ - /* Declare this way so it can be used with any kind of double linked list - * having next & prev pointers in its first two words. */ - struct DLL *h = (struct DLL *) head; - struct DLL *xx = (struct DLL *) x; - xx->next = h; - xx->prev = h->prev; - h->prev->next = xx; - h->prev = xx; - return; -} -/*}}}*/ - -enum encoding_type {/*{{{*/ - ENC_UNKNOWN, - ENC_NONE, - ENC_BINARY, - ENC_7BIT, - ENC_8BIT, - ENC_QUOTED_PRINTABLE, - ENC_BASE64, - ENC_UUENCODE -}; -/*}}}*/ -struct content_type_header {/*{{{*/ - const char *major; /* e.g. text */ - const char *minor; /* e.g. plain */ - const char *boundary; /* for multipart */ - /* charset? */ -}; -/*}}}*/ -struct line {/*{{{*/ - struct line *next; - struct line *prev; - char *text; -}; -/*}}}*/ - -static void init_headers(struct headers *hdrs)/*{{{*/ -{ - hdrs->to = NULL; - hdrs->cc = NULL; - hdrs->from = NULL; - hdrs->subject = NULL; - hdrs->message_id = NULL; - hdrs->in_reply_to = NULL; - hdrs->references = NULL; - hdrs->date = 0; - hdrs->flags.seen = 0; - hdrs->flags.replied = 0; - hdrs->flags.flagged = 0; -}; -/*}}}*/ -static void splice_header_lines(struct line *header)/*{{{*/ -{ - /* Deal with newline then tab in header */ - struct line *x, *next; - for (x=header->next; x!=header; x=next) { -#if 0 - printf("next header, x->text=%08lx\n", x->text); - printf("header=<%s>\n", x->text); -#endif - next = x->next; - if (isspace(x->text[0] & 0xff)) { - /* Glue to previous line */ - char *p, *newbuf, *oldbuf; - struct line *y; - for (p=x->text; *p; p++) { - if (!isspace(*(unsigned char *)p)) break; - } - p--; /* point to final space */ - y = x->prev; -#if 0 - printf("y=%08lx p=%08lx\n", y->text, p); -#endif - newbuf = new_array(char, strlen(y->text) + strlen(p) + 1); - strcpy(newbuf, y->text); - strcat(newbuf, p); - oldbuf = y->text; - y->text = newbuf; - free(oldbuf); - y->next = x->next; - x->next->prev = y; - free(x->text); - free(x); - } - } - return; -} -/*}}}*/ -static int audit_header(struct line *header)/*{{{*/ -{ - /* Check for obvious broken-ness - * 1st line has no leading spaces, single word then colon - * following lines have leading spaces or single word followed by colon - * */ - struct line *x; - int first=1; - int count=1; - for (x=header->next; x!=header; x=x->next) { - int has_leading_space=0; - int is_blank; - int has_word_colon=0; - - if (1 || first) { - /* Ignore any UUCP or mbox style From line at the start */ - if (!strncmp("From ", x->text, 5)) { - continue; - } - /* Ignore escaped From line at the start */ - if (!strncmp(">From ", x->text, 6)) { - continue; - } - } - - is_blank = !(x->text[0]); - if (!is_blank) { - char *p; - int saw_char = 0; - has_leading_space = isspace(x->text[0] & 0xff); - has_word_colon = 0; /* default */ - p = x->text; - while(*p) { - if(*p == ':') { - has_word_colon = saw_char; - break; - } else if (isspace(*(unsigned char *) p)) { - has_word_colon = 0; - break; - } else { - saw_char = 1; - } - p++; - } - } - - if (( first && (is_blank || has_leading_space || !has_word_colon)) || - (!first && (is_blank || !(has_leading_space || has_word_colon)))) { -#if 0 - fprintf(stderr, "Header line %d <%s> fails because:", count, x->text); - if (first && is_blank) { fprintf(stderr, " [first && is_blank]"); } - if (first && has_leading_space) { fprintf(stderr, " [first && has_leading_space]"); } - if (first && !has_word_colon) { fprintf(stderr, " [first && !has_word_colon]"); } - if (!first && is_blank) { fprintf(stderr, " [!first && is_blank]"); } - if (!first && !(has_leading_space||has_word_colon)) { fprintf(stderr, " [!first && !has_leading_space||has_word_colon]"); } - fprintf(stderr, "\n"); -#endif - /* Header fails the audit */ - return 0; - } - first = 0; - count++; - } - /* If we get here the header must have been OK */ - return 1; -}/*}}}*/ -static int match_string(const char *ref, const char *candidate)/*{{{*/ -{ - int len = strlen(ref); - return !strncasecmp(ref, candidate, len); -} -/*}}}*/ - -static char equal_table[] = {/*{{{*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00-0f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10-1f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20-2f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 30-3f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40-4f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50-5f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60-6f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70-7f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80-8f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90-9f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a0-af */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b0-bf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c0-cf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d0-df */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e0-ef */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* f0-ff */ -}; -/*}}}*/ -static int base64_table[] = {/*{{{*/ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00-0f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10-1f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 20-2f */ - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, /* 30-3f */ - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 40-4f */ - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 50-5f */ - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 60-6f */ - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 70-7f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80-8f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90-9f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a0-af */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b0-bf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c0-cf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d0-df */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0-ef */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* f0-ff */ -}; -/*}}}*/ -static int hex_to_val(char x) {/*{{{*/ - switch (x) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return (x - '0'); - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - return 10 + (x - 'a'); - break; - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - return 10 + (x - 'A'); - break; - default: - return 0; - } -} -/*}}}*/ -static void decode_header_value(char *text){/*{{{*/ - /* rfc2047 decode, written by Mikael Ylikoski */ - - char *s, *a, *b, *e, *p, *q; - - for (p = q = s = text; (s = strstr(s, "=?")); s = e + 2) { - if (p == q) - p = q = s; - else - while (q != s) - *p++ = *q++; - s += 2; - a = strchr(s, '?'); - if (!a) break; - a++; - b = strchr(a, '?'); - if (!b) break; - b++; - e = strstr(b, "?="); - if (!e) break; - /* have found an encoded-word */ - if (b - a != 2) - continue; /* unknown encoding */ - if (*a == 'q' || *a == 'Q') { - int val; - q = b; - while (q < e) { - if (*q == '_') { - *p++ = 0x20; - q++; - } else if (*q == '=') { - q++; - val = hex_to_val(*q++) << 4; - val += hex_to_val(*q++); - *p++ = val; - } else - *p++ = *q++; - } - } else if (*a == 'b' || *a == 'B') { - int reg, nc, eq; /* register, #characters in reg, #equals */ - int dc; /* decoded character */ - eq = reg = nc = 0; - for (q = b; q < e; q++) { - unsigned char cq = *(unsigned char *)q; - dc = base64_table[cq]; - eq += equal_table[cq]; - - if (dc >= 0) { - reg <<= 6; - reg += dc; - nc++; - if (nc == 4) { - *p++ = ((reg >> 16) & 0xff); - if (eq < 2) *p++ = ((reg >> 8) & 0xff); - if (eq < 1) *p++ = reg & 0xff; - nc = reg = 0; - if (eq) break; - } - } - } - } else { - continue; /* unknown encoding */ - } - q = e + 2; - } - if (p == q) return; - while (*q != '\0') - *p++ = *q++; - *p = '\0'; -} -/*}}}*/ -static char *copy_header_value(char *text){/*{{{*/ - char *p; - for (p = text; *p && (*p != ':'); p++) ; - if (!*p) return NULL; - p++; - p = new_string(p); - decode_header_value(p); - return p; -} -/*}}}*/ -static void copy_or_concat_header_value(char **previous, char *text){/*{{{*/ - char *p = copy_header_value(text); - if (*previous) - { - *previous = extend_string(*previous, ", "); - *previous = extend_string(*previous, p); - free(p); - } - else - *previous = p; -} -/*}}}*/ -static enum encoding_type decode_encoding_type(const char *e)/*{{{*/ -{ - enum encoding_type result; - const char *p; - if (!e) { - result = ENC_NONE; - } else { - for (p=e; *p && isspace(*(unsigned char *)p); p++) ; - if ( match_string("7bit", p) - || match_string("7-bit", p) - || match_string("7 bit", p)) { - result = ENC_7BIT; - } else if (match_string("8bit", p) - || match_string("8-bit", p) - || match_string("8 bit", p)) { - result = ENC_8BIT; - } else if (match_string("quoted-printable", p)) { - result = ENC_QUOTED_PRINTABLE; - } else if (match_string("base64", p)) { - result = ENC_BASE64; - } else if (match_string("binary", p)) { - result = ENC_BINARY; - } else if (match_string("x-uuencode", p)) { - result = ENC_UUENCODE; - } else { - fprintf(stderr, "Warning: unknown encoding type: '%s'\n", e); - result = ENC_UNKNOWN; - } - } - return result; -} -/*}}}*/ -static void parse_content_type(struct nvp *ct_nvp, struct content_type_header *result)/*{{{*/ -{ - result->major = NULL; - result->minor = NULL; - result->boundary = NULL; - - result->major = nvp_major(ct_nvp); - if (result->major) { - result->minor = nvp_minor(ct_nvp); - } else { - result->minor = NULL; - result->major = nvp_first(ct_nvp); - } - - result->boundary = nvp_lookupcase(ct_nvp, "boundary"); -} - -/*}}}*/ -static char *looking_at_ws_then_newline(char *start)/*{{{*/ -{ - char *result; - result = start; - do { - if (*result == '\n') return result; - else if (!isspace(*(unsigned char *) result)) return NULL; - else result++; - } while (1); - - /* Can't get here */ - assert(0); -} -/*}}}*/ - -static char *unencode_data(struct msg_src *src, char *input, int input_len, const char *enc, int *output_len)/*{{{*/ -{ - enum encoding_type encoding; - char *result, *end_result; - char *end_input; - - encoding = decode_encoding_type(enc); - end_input = input + input_len; - - /* All mime encodings result in expanded data, so this is guaranteed to - * safely oversize the output array */ - result = new_array(char, input_len + 1); - - /* Now decode */ - switch (encoding) { - case ENC_7BIT:/*{{{*/ - case ENC_8BIT: - case ENC_BINARY: - case ENC_NONE: - { - memcpy(result, input, input_len); - end_result = result + input_len; - } - break; -/*}}}*/ - case ENC_QUOTED_PRINTABLE:/*{{{*/ - { - char *p, *q; - p = result; - for (p=result, q=input; - q<end_input; ) { - - if (*q == '=') { - /* followed by optional whitespace then \n? discard them. */ - char *r; - int val; - q++; - r = looking_at_ws_then_newline(q); - if (r) { - q = r + 1; /* Point into next line */ - continue; - } - /* not that case. */ - val = hex_to_val(*q++) << 4; - val += hex_to_val(*q++); - *p++ = val; - - } else { - /* Normal character */ - *p++ = *q++; - } - } - end_result = p; - } - break; -/*}}}*/ - case ENC_BASE64:/*{{{*/ - { - char *p, *q; - int reg, nc, eq; /* register, #characters in reg, #equals */ - int dc; /* decoded character */ - eq = reg = nc = 0; - for (q=input, p=result; q<end_input; q++) { - unsigned char cq = * (unsigned char *)q; - /* Might want a 256 entry array instead of this sub-optimal mess - * eventually. */ - dc = base64_table[cq]; - eq += equal_table[cq]; - - if (dc >= 0) { - reg <<= 6; - reg += dc; - nc++; - if (nc == 4) { - *p++ = ((reg >> 16) & 0xff); - if (eq < 2) *p++ = ((reg >> 8) & 0xff); - if (eq < 1) *p++ = reg & 0xff; - nc = reg = 0; - if (eq) goto done_base_64; - } - } - } - done_base_64: - end_result = p; - } - break; - /*}}}*/ - case ENC_UUENCODE:/*{{{*/ - { - char *p, *q; - /* Find 'begin ' */ - for (q = input; q < end_input - 6 && memcmp(q, "begin ", 6); q++) - ; - q += 6; - /* skip to EOL */ - while (q < end_input && *q != '\n') - q++; - p = result; - while (q < end_input) { /* process line */ -#define DEC(c) (((c) - ' ') & 077) - int len = DEC(*q++); - if (len == 0) - break; - for (; len > 0; q += 4, len -= 3) { - if (len >= 3) { - *p++ = DEC(q[0]) << 2 | DEC(q[1]) >> 4; - *p++ = DEC(q[1]) << 4 | DEC(q[2]) >> 2; - *p++ = DEC(q[2]) << 6 | DEC(q[3]); - } else { - if (len >= 1) - *p++ = DEC(q[0]) << 2 | DEC(q[1]) >> 4; - if (len >= 2) - *p++ = DEC(q[1]) << 4 | DEC(q[2]) >> 2; - } - } - while (q < end_input && *q != '\n') - q++; - } - end_result = p; - } - break; - /*}}}*/ - case ENC_UNKNOWN:/*{{{*/ - fprintf(stderr, "Unknown encoding type in %s\n", format_msg_src(src)); - /* fall through - ignore this data */ - /*}}}*/ - default:/*{{{*/ - end_result = result; - break; - /*}}}*/ - } - *output_len = end_result - result; - result[*output_len] = '\0'; /* for convenience with text/plain etc to make it printable */ - return result; -} -/*}}}*/ -char *format_msg_src(struct msg_src *src)/*{{{*/ -{ - static char *buffer = NULL; - static int buffer_len = 0; - char *result; - int len; - switch (src->type) { - case MS_FILE: - result = src->filename; - break; - case MS_MBOX: - len = strlen(src->filename); - len += 32; - if (!buffer || (len > buffer_len)) { - free(buffer); - buffer = new_array(char, len); - buffer_len = len; - } - sprintf(buffer, "%s[%d,%d)", src->filename, - (int) src->start, (int) (src->start + src->len)); - result = buffer; - break; - default: - result = NULL; - break; - } - return result; -} -/*}}}*/ -static int split_and_splice_header(struct msg_src *src, char *data, struct line *header, char **body_start)/*{{{*/ -{ - char *sol, *eol; - int blank_line; - header->next = header->prev = header; - sol = data; - do { - if (!*sol) break; - blank_line = 1; /* until proven otherwise */ - eol = sol; - while (*eol && (*eol != '\n')) { - if (!isspace(*(unsigned char *) eol)) blank_line = 0; - eol++; - } - if (*eol == '\n') { - if (!blank_line) { - int line_length = eol - sol; - char *line_text = new_array(char, 1 + line_length); - struct line *new_header; - - strncpy(line_text, sol, line_length); - line_text[line_length] = '\0'; - new_header = new(struct line); - new_header->text = line_text; - enqueue(header, new_header); - } - sol = eol + 1; /* Start of next line */ - } else { /* must be null char */ - fprintf(stderr, "Got null character whilst processing header of %s\n", - format_msg_src(src)); - return -1; /* & leak memory */ - } - } while (!blank_line); - - *body_start = sol; - - if (audit_header(header)) { - splice_header_lines(header); - return 0; - } else { -#if 0 - /* Caller generates message */ - fprintf(stderr, "Message had bad rfc822 headers, ignoring\n"); -#endif - return -1; - } -} -/*}}}*/ - -/* Forward prototypes */ -static void do_multipart(struct msg_src *src, char *input, int input_len, - const char *boundary, struct attachment *atts, - enum data_to_rfc822_error *error); - -/*{{{ do_body() */ -static void do_body(struct msg_src *src, - char *body_start, int body_len, - struct nvp *ct_nvp, struct nvp *cte_nvp, - struct nvp *cd_nvp, - struct attachment *atts, - enum data_to_rfc822_error *error) -{ - char *decoded_body; - int decoded_body_len; - const char *content_transfer_encoding; - content_transfer_encoding = NULL; - if (cte_nvp) { - content_transfer_encoding = nvp_first(cte_nvp); - if (!content_transfer_encoding) { - fprintf(stderr, "Giving up on %s, content_transfer_encoding header not parseable\n", - format_msg_src(src)); - return; - } - } - - decoded_body = unencode_data(src, body_start, body_len, content_transfer_encoding, &decoded_body_len); - - if (ct_nvp) { - struct content_type_header ct; - parse_content_type(ct_nvp, &ct); - if (ct.major && !strcasecmp(ct.major, "multipart")) { - do_multipart(src, decoded_body, decoded_body_len, ct.boundary, atts, error); - /* Don't need decoded body any longer - copies have been taken if - * required when handling multipart attachments. */ - free(decoded_body); - if (error && (*error == DTR8_MISSING_END)) return; - } else { - /* unipart */ - struct attachment *new_att; - const char *disposition; - new_att = new(struct attachment); - disposition = cd_nvp ? nvp_first(cd_nvp) : NULL; - if (disposition && !strcasecmp(disposition, "attachment")) { - const char *lookup; - lookup = nvp_lookupcase(cd_nvp, "filename"); - if (lookup) { - new_att->filename = new_string(lookup); - } else { - /* Some messages have name=... in content-type: instead of - * filename=... in content-disposition. */ - lookup = nvp_lookup(ct_nvp, "name"); - if (lookup) { - new_att->filename = new_string(lookup); - } else { - new_att->filename = NULL; - } - } - } else { - new_att->filename = NULL; - } - if (ct.major && !strcasecmp(ct.major, "text")) { - if (ct.minor && !strcasecmp(ct.minor, "plain")) { - new_att->ct = CT_TEXT_PLAIN; - } else if (ct.minor && !strcasecmp(ct.minor, "html")) { - new_att->ct = CT_TEXT_HTML; - } else { - new_att->ct = CT_TEXT_OTHER; - } - } else if (ct.major && !strcasecmp(ct.major, "message") && - ct.minor && !strcasecmp(ct.minor, "rfc822")) { - new_att->ct = CT_MESSAGE_RFC822; - } else { - new_att->ct = CT_OTHER; - } - - if (new_att->ct == CT_MESSAGE_RFC822) { - new_att->data.rfc822 = data_to_rfc822(src, decoded_body, decoded_body_len, error); - free(decoded_body); /* data no longer needed */ - } else { - new_att->data.normal.len = decoded_body_len; - new_att->data.normal.bytes = decoded_body; - } - enqueue(atts, new_att); - } - } else { - /* Treat as text/plain {{{*/ - struct attachment *new_att; - new_att = new(struct attachment); - new_att->filename = NULL; - new_att->ct = CT_TEXT_PLAIN; - new_att->data.normal.len = decoded_body_len; - /* Add null termination on the end */ - new_att->data.normal.bytes = new_array(char, decoded_body_len + 1); - memcpy(new_att->data.normal.bytes, decoded_body, decoded_body_len + 1); - free(decoded_body); - enqueue(atts, new_att);/*}}}*/ - } -} -/*}}}*/ -/*{{{ do_attachment() */ -static void do_attachment(struct msg_src *src, - char *start, char *after_end, - struct attachment *atts) -{ - /* decode attachment and add to attachment list */ - struct line header, *x, *nx; - char *body_start; - int body_len; - - struct nvp *ct_nvp, *cte_nvp, *cd_nvp, *nvp; - - if (split_and_splice_header(src, start, &header, &body_start) < 0) { - fprintf(stderr, "Giving up on attachment with bad header in %s\n", - format_msg_src(src)); - return; - } - - /* Extract key headers */ - ct_nvp = cte_nvp = cd_nvp = NULL; - for (x=header.next; x!=&header; x=x->next) { - if ((nvp = make_nvp(src, x->text, "content-type:"))) { - ct_nvp = nvp; - } else if ((nvp = make_nvp(src, x->text, "content-transfer-encoding:"))) { - cte_nvp = nvp; - } else if ((nvp = make_nvp(src, x->text, "content-disposition:"))) { - cd_nvp = nvp; - } - } - -#if 0 - if (ct_nvp) { - fprintf(stderr, "======\n"); - fprintf(stderr, "Dump of content-type hdr\n"); - nvp_dump(ct_nvp, stderr); - free(ct_nvp); - } - - if (cte_nvp) { - fprintf(stderr, "======\n"); - fprintf(stderr, "Dump of content-transfer-encoding hdr\n"); - nvp_dump(cte_nvp, stderr); - free(cte_nvp); - } -#endif - - if (body_start > after_end) { - /* This is a (maliciously?) b0rken attachment, e.g. maybe empty */ - if (verbose) { - fprintf(stderr, "Message %s contains an invalid attachment, length=%d bytes\n", - format_msg_src(src), (int)(after_end - start)); - } - } else { - body_len = after_end - body_start; - /* Ignore errors in nested body parts. */ - do_body(src, body_start, body_len, ct_nvp, cte_nvp, cd_nvp, atts, NULL); - } - - /* Free header memory */ - for (x=header.next; x!=&header; x=nx) { - nx = x->next; - free(x->text); - free(x); - } - - if (ct_nvp) free_nvp(ct_nvp); - if (cte_nvp) free_nvp(cte_nvp); - if (cd_nvp) free_nvp(cd_nvp); -} -/*}}}*/ -/*{{{ do_multipart() */ -static void do_multipart(struct msg_src *src, - char *input, int input_len, - const char *boundary, - struct attachment *atts, - enum data_to_rfc822_error *error) -{ - char *b0, *b1, *be, *bx; - char *line_after_b0, *start_b1_search_from; - int boundary_len; - int looking_at_end_boundary; - - if (!boundary) { - fprintf(stderr, "Can't process multipart message %s with no boundary string\n", - format_msg_src(src)); - if (error) *error = DTR8_MULTIPART_SANS_BOUNDARY; - return; - } - - boundary_len = strlen(boundary); - - b0 = NULL; - line_after_b0 = input; - be = input + input_len; - - do { - int boundary_ok; - start_b1_search_from = line_after_b0; - do { - /* reject boundaries that aren't a whole line */ - b1 = NULL; - for (bx = start_b1_search_from; bx < be - (boundary_len + 4); bx++) { - if (bx[0] == '-' && bx[1] == '-' && - !strncmp(bx+2, boundary, boundary_len)) { - b1 = bx; - break; - } - } - if (!b1) { - if (error) - *error = DTR8_MISSING_END; - return; - } - - looking_at_end_boundary = (b1[boundary_len+2] == '-' && - b1[boundary_len+3] == '-'); - boundary_ok = 1; - if ((b1 > input) && (*(b1-1) != '\n')) - boundary_ok = 0; - if (!looking_at_end_boundary && (b1 + boundary_len + 2 < input + input_len) && (*(b1 + boundary_len + 2) != '\n')) - boundary_ok = 0; - if (!boundary_ok) { - char *eol = strchr(b1, '\n'); - if (!eol) { - fprintf(stderr, "Oops, didn't find another normal boundary in %s\n", - format_msg_src(src)); - return; - } - start_b1_search_from = 1 + eol; - } - } while (!boundary_ok); - - /* b1 is now looking at a good boundary, which might be the final one */ - - if (b0) { - /* don't treat preamble as an attachment */ - do_attachment(src, line_after_b0, b1, atts); - } - - b0 = b1; - line_after_b0 = strchr(b0, '\n'); - if (line_after_b0 == 0) - line_after_b0 = b0 + strlen(b0); - else - ++line_after_b0; - } while (b1 < be && !looking_at_end_boundary); -} -/*}}}*/ -static time_t parse_rfc822_date(char *date_string)/*{{{*/ -{ - struct tm tm; - char *s, *z; - /* Format [weekday ,] day-of-month month year hour:minute:second timezone. - - Some of the ideas, sanity checks etc taken from parse.c in the mutt - sources, credit to Michael R. Elkins et al - */ - - s = date_string; - z = strchr(s, ','); - if (z) s = z + 1; - while (*s && isspace(*s)) s++; - /* Should now be looking at day number */ - if (!isdigit(*s)) goto tough_cheese; - tm.tm_mday = atoi(s); - if (tm.tm_mday > 31) goto tough_cheese; - - while (isdigit(*s)) s++; - while (*s && isspace(*s)) s++; - if (!*s) goto tough_cheese; - if (!strncasecmp(s, "jan", 3)) tm.tm_mon = 0; - else if (!strncasecmp(s, "feb", 3)) tm.tm_mon = 1; - else if (!strncasecmp(s, "mar", 3)) tm.tm_mon = 2; - else if (!strncasecmp(s, "apr", 3)) tm.tm_mon = 3; - else if (!strncasecmp(s, "may", 3)) tm.tm_mon = 4; - else if (!strncasecmp(s, "jun", 3)) tm.tm_mon = 5; - else if (!strncasecmp(s, "jul", 3)) tm.tm_mon = 6; - else if (!strncasecmp(s, "aug", 3)) tm.tm_mon = 7; - else if (!strncasecmp(s, "sep", 3)) tm.tm_mon = 8; - else if (!strncasecmp(s, "oct", 3)) tm.tm_mon = 9; - else if (!strncasecmp(s, "nov", 3)) tm.tm_mon = 10; - else if (!strncasecmp(s, "dec", 3)) tm.tm_mon = 11; - else goto tough_cheese; - - while (!isspace(*s)) s++; - while (*s && isspace(*s)) s++; - if (!isdigit(*s)) goto tough_cheese; - tm.tm_year = atoi(s); - if (tm.tm_year < 70) { - tm.tm_year += 100; - } else if (tm.tm_year >= 1900) { - tm.tm_year -= 1900; - } - - while (isdigit(*s)) s++; - while (*s && isspace(*s)) s++; - if (!*s) goto tough_cheese; - - /* Now looking at hms */ - /* For now, forget this. The searching will be vague enough that nearest day is good enough. */ - - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = 0; - return mktime(&tm); - -tough_cheese: - return (time_t) -1; /* default value */ -} -/*}}}*/ - -static void scan_status_flags(const char *s, struct headers *hdrs)/*{{{*/ -{ - const char *p; - for (p=s; *p; p++) { - switch (*p) { - case 'R': hdrs->flags.seen = 1; break; - case 'A': hdrs->flags.replied = 1; break; - case 'F': hdrs->flags.flagged = 1; break; - default: break; - } - } -} -/*}}}*/ - -/*{{{ data_to_rfc822() */ -struct rfc822 *data_to_rfc822(struct msg_src *src, - char *data, int length, - enum data_to_rfc822_error *error) -{ - struct rfc822 *result; - char *body_start; - struct line header; - struct line *x, *nx; - struct nvp *ct_nvp, *cte_nvp, *cd_nvp, *nvp; - int body_len; - - if (error) *error = DTR8_OK; /* default */ - result = new(struct rfc822); - init_headers(&result->hdrs); - result->atts.next = result->atts.prev = &result->atts; - - if (split_and_splice_header(src, data, &header, &body_start) < 0) { - if (verbose) { - fprintf(stderr, "Giving up on message %s with bad header\n", - format_msg_src(src)); - } - if (error) *error = DTR8_BAD_HEADERS; - return NULL; - } - - /* Extract key headers {{{*/ - ct_nvp = cte_nvp = cd_nvp = NULL; - for (x=header.next; x!=&header; x=x->next) { - if (match_string("to", x->text)) - copy_or_concat_header_value(&result->hdrs.to, x->text); - else if (match_string("cc", x->text)) - copy_or_concat_header_value(&result->hdrs.cc, x->text); - else if (!result->hdrs.from && match_string("from", x->text)) - result->hdrs.from = copy_header_value(x->text); - else if (!result->hdrs.subject && match_string("subject", x->text)) - result->hdrs.subject = copy_header_value(x->text); - else if (!ct_nvp && (nvp = make_nvp(src, x->text, "content-type:"))) - ct_nvp = nvp; - else if (!cte_nvp && (nvp = make_nvp(src, x->text, "content-transfer-encoding:"))) - cte_nvp = nvp; - else if (!cd_nvp && (nvp = make_nvp(src, x->text, "content-disposition:"))) - cd_nvp = nvp; - else if (!result->hdrs.date && match_string("date", x->text)) { - char *date_string = copy_header_value(x->text); - result->hdrs.date = parse_rfc822_date(date_string); - free(date_string); - } else if (!result->hdrs.message_id && match_string("message-id", x->text)) - result->hdrs.message_id = copy_header_value(x->text); - else if (!result->hdrs.in_reply_to && match_string("in-reply-to", x->text)) - result->hdrs.in_reply_to = copy_header_value(x->text); - else if (!result->hdrs.references && match_string("references", x->text)) - result->hdrs.references = copy_header_value(x->text); - else if (match_string("status", x->text)) - scan_status_flags(x->text + sizeof("status:"), &result->hdrs); - else if (match_string("x-status", x->text)) - scan_status_flags(x->text + sizeof("x-status:"), &result->hdrs); - } -/*}}}*/ - - /* Process body */ - body_len = length - (body_start - data); - do_body(src, body_start, body_len, ct_nvp, cte_nvp, cd_nvp, &result->atts, error); - - /* Free header memory */ - for (x=header.next; x!=&header; x=nx) { - nx = x->next; - free(x->text); - free(x); - } - - if (ct_nvp) free_nvp(ct_nvp); - if (cte_nvp) free_nvp(cte_nvp); - if (cd_nvp) free_nvp(cd_nvp); - - return result; - -} -/*}}}*/ - -#define ALLOC_NONE 1 -#define ALLOC_MMAP 2 -#define ALLOC_MALLOC 3 - -int data_alloc_type; - -#if USE_GZIP_MBOX || USE_BZIP_MBOX - -#define SIZE_STEP (8 * 1024 * 1024) - -#define COMPRESSION_NONE 0 -#define COMPRESSION_GZIP 1 -#define COMPRESSION_BZIP 2 - -static int get_compression_type(const char *filename) {/*{{{*/ - size_t len = strlen(filename); - int ptr; - -#ifdef USE_GZIP_MBOX - ptr = len - 3; - if (len > 3 && strncasecmp(filename + ptr, ".gz", 3) == 0) { - return COMPRESSION_GZIP; - } -#endif - -#ifdef USE_BZIP_MBOX - ptr = len - 4; - if (len > 3 && strncasecmp(filename + ptr, ".bz2", 4) == 0) { - return COMPRESSION_BZIP; - } -#endif - - return COMPRESSION_NONE; -} -/*}}}*/ - -static int is_compressed(const char *filename) {/*{{{*/ - return (get_compression_type(filename) != COMPRESSION_NONE); -} -/*}}}*/ - -struct zFile {/*{{{*/ - union { - /* Both gzFile and BZFILE* are defined as void pointers - * in their respective header files. - */ -#ifdef USE_GZIP_MBOX - gzFile gzf; -#endif -#ifdef USE_BZIP_MBOX - BZFILE *bzf; -#endif - void *zptr; - } foo; - int type; -}; -/*}}}*/ - -static struct zFile * xx_zopen(const char *filename, const char *mode) {/*{{{*/ - struct zFile *zf = new(struct zFile); - - zf->type = get_compression_type(filename); - switch (zf->type) { -#ifdef USE_GZIP_MBOX - case COMPRESSION_GZIP: - zf->foo.gzf = gzopen(filename, "rb"); - break; -#endif -#ifdef USE_BZIP_MBOX - case COMPRESSION_BZIP: - zf->foo.bzf = BZ2_bzopen(filename, "rb"); - break; -#endif - default: - zf->foo.zptr = NULL; - break; - } - - if (!zf->foo.zptr) { - free(zf); - return 0; - } - - return zf; -} -/*}}}*/ -static void xx_zclose(struct zFile *zf) {/*{{{*/ - switch (zf->type) { -#ifdef USE_GZIP_MBOX - case COMPRESSION_GZIP: - gzclose(zf->foo.gzf); - break; -#endif -#ifdef USE_BZIP_MBOX - case COMPRESSION_BZIP: - BZ2_bzclose(zf->foo.bzf); - break; -#endif - default: - zf->foo.zptr = NULL; - break; - } - free(zf); -} -/*}}}*/ -static int xx_zread(struct zFile *zf, void *buf, int len) {/*{{{*/ - switch (zf->type) { -#ifdef USE_GZIP_MBOX - case COMPRESSION_GZIP: - return gzread(zf->foo.gzf, buf, len); - break; -#endif -#ifdef USE_BZIP_MBOX - case COMPRESSION_BZIP: - return BZ2_bzread(zf->foo.bzf, buf, len); - break; -#endif - default: - return 0; - break; - } -} -/*}}}*/ -#endif - -#if USE_GZIP_MBOX || USE_BZIP_MBOX -/* do we need ROCACHE_SIZE > 1? the code supports any number here */ -#define ROCACHE_SIZE 1 -struct ro_mapping { - char *filename; - unsigned char *map; - size_t len; -}; -static int ro_cache_init = 0; -static struct ro_mapping ro_mapping_cache[ROCACHE_SIZE]; - -/* find a temp file in the mapping cache. If nothing is found lasti is - * set to the next slot to use for insertion. You have to check that slot - * to see if it is currently in use - */ -static struct ro_mapping *find_ro_cache(const char *filename, int *lasti) -{ - int i = 0; - struct ro_mapping *ro = NULL; - if (lasti) - *lasti = 0; - if (!ro_cache_init) - return NULL; - for (i = 0 ; i < ROCACHE_SIZE ; i++) { - ro = ro_mapping_cache + i; - if (!ro->map) { - if (lasti) - *lasti = i; - return NULL; - } - if (strcmp(filename, ro->filename) == 0) - return ro; - } - /* if we're here, the map is full. They will reuse slot 0 */ - return NULL; -} - -/* - * put a new tempfile into the cache. It is mmaped as part of this function - * so you can safely close the file handle after calling this. - */ -static struct ro_mapping *add_ro_cache(const char *filename, int fd, size_t len) -{ - int i = 0; - struct ro_mapping *ro = NULL; - if (!ro_cache_init) { - memset(&ro_mapping_cache, 0, sizeof(ro_mapping_cache)); - ro_cache_init = 1; - } - ro = find_ro_cache(filename, &i); - if (ro) { - fprintf(stderr, "%s already in ro cache\n", filename); - return NULL; - } - ro = ro_mapping_cache + i; - if (ro->map) { - munmap(ro->map, ro->len); - ro->map = NULL; - free(ro->filename); - } - ro->map = (unsigned char *)mmap(0, len, PROT_READ, MAP_SHARED, fd, 0); - if (ro->map == MAP_FAILED) { - ro->map = NULL; - perror("rfc822:mmap"); - return NULL; - } - ro->len = len; - ro->filename = new_string(filename); - return ro; -} -#endif /* USE_GZIP_MBOX || USE_BZIP_MBOX */ - -void create_ro_mapping(const char *filename, unsigned char **data, int *len)/*{{{*/ -{ - struct stat sb; - int fd; - -#if USE_GZIP_MBOX || USE_BZIP_MBOX - struct zFile *zf; -#endif - - if (stat(filename, &sb) < 0) - { - report_error("stat", filename); - *data = NULL; - return; - } - -#if USE_GZIP_MBOX || USE_BZIP_MBOX - if(is_compressed(filename)) { - unsigned char *p; - size_t cur_read; - struct ro_mapping *ro; - FILE *tmpf; - - /* this branch never returns things that are freeable */ - data_alloc_type = ALLOC_NONE; - ro = find_ro_cache(filename, NULL); - if (ro) { - *data = ro->map; - *len = ro->len; - return; - } - - if(verbose) { - fprintf(stderr, "Decompressing %s...\n", filename); - } - - tmpf = tmpfile(); - if (!tmpf) { - perror("tmpfile"); - goto comp_error; - } - zf = xx_zopen(filename, "rb"); - if (!zf) { - fprintf(stderr, "Could not open %s\n", filename); - goto comp_error; - } - p = new_array(unsigned char, SIZE_STEP); - cur_read = xx_zread(zf, p, SIZE_STEP); - if (fwrite(p, cur_read, 1, tmpf) != 1) { - fprintf(stderr, "failed writing to temp file for %s\n", filename); - goto comp_error; - } - *len = cur_read; - if (cur_read >= SIZE_STEP) { - while(1) { - int ret; - cur_read = xx_zread(zf, p, SIZE_STEP); - if (cur_read <= 0) - break; - *len += cur_read; - ret = fwrite(p, cur_read, 1, tmpf); - if (ret != 1) { - fprintf(stderr, "failed writing to temp file for %s\n", filename); - goto comp_error; - } - } - } - free(p); - xx_zclose(zf); - - if(*len > 0) { - ro = add_ro_cache(filename, fileno(tmpf), *len); - if (!ro) - goto comp_error; - *data = ro->map; - *len = ro->len; - } else { - *data = NULL; - } - fclose(tmpf); - return; - -comp_error: - *data = NULL; - *len = 0; - if (tmpf) - fclose(tmpf); - return; - } -#endif /* USE_GZIP_MBOX || USE_BZIP_MBOX */ - - *len = sb.st_size; - if (*len == 0) { - *data = NULL; - return; - } - - if (!S_ISREG(sb.st_mode)) { - *data = NULL; - return; - } - - fd = open(filename, O_RDONLY); - if (fd < 0) - { - report_error("open", filename); - *data = NULL; - return; - } - - *data = (unsigned char *) mmap(0, *len, PROT_READ, MAP_SHARED, fd, 0); - if (close(fd) < 0) - report_error("close", filename); - if (*data == MAP_FAILED) { - report_error("rfc822:mmap", filename); - *data = NULL; - return; - } - data_alloc_type = ALLOC_MMAP; -} -/*}}}*/ -void free_ro_mapping(unsigned char *data, int len)/*{{{*/ -{ - int r; - - if(data_alloc_type == ALLOC_MALLOC) { - free(data); - } - - if(data_alloc_type == ALLOC_MMAP) { - r = munmap(data, len); - if(r < 0) { - fprintf(stderr, "munmap() errord\n"); - exit(1); - } - } -} -/*}}}*/ - -static struct msg_src *setup_msg_src(char *filename)/*{{{*/ -{ - static struct msg_src result; - result.type = MS_FILE; - result.filename = filename; - return &result; -} -/*}}}*/ -struct rfc822 *make_rfc822(char *filename)/*{{{*/ -{ - int len; - unsigned char *data; - struct rfc822 *result; - - create_ro_mapping(filename, &data, &len); - - /* Don't process empty files */ - result = NULL; - - if (data) - { - struct msg_src *src; - /* Now process the data */ - src = setup_msg_src(filename); - /* For one message per file, ignore missing end boundary condition. */ - result = data_to_rfc822(src, (char *) data, len, NULL); - - free_ro_mapping(data, len); - } - - return result; -} -/*}}}*/ -void free_rfc822(struct rfc822 *msg)/*{{{*/ -{ - struct attachment *a, *na; - - if (!msg) return; - - if (msg->hdrs.to) free(msg->hdrs.to); - if (msg->hdrs.cc) free(msg->hdrs.cc); - if (msg->hdrs.from) free(msg->hdrs.from); - if (msg->hdrs.subject) free(msg->hdrs.subject); - if (msg->hdrs.message_id) free(msg->hdrs.message_id); - if (msg->hdrs.in_reply_to) free(msg->hdrs.in_reply_to); - if (msg->hdrs.references) free(msg->hdrs.references); - - for (a = msg->atts.next; a != &msg->atts; a = na) { - na = a->next; - if (a->filename) free(a->filename); - if (a->ct == CT_MESSAGE_RFC822) { - free_rfc822(a->data.rfc822); - } else { - free(a->data.normal.bytes); - } - free(a); - } - free(msg); -} -/*}}}*/ - -#ifdef TEST - -static void do_indent(int indent)/*{{{*/ -{ - int i; - for (i=indent; i>0; i--) { - putchar(' '); - } -} -/*}}}*/ -static void show_header(char *tag, char *x, int indent)/*{{{*/ -{ - if (x) { - do_indent(indent); - printf("%s: %s\n", tag, x); - } -} -/*}}}*/ -static void show_rfc822(struct rfc822 *msg, int indent)/*{{{*/ -{ - struct attachment *a; - show_header("From", msg->hdrs.from, indent); - show_header("To", msg->hdrs.to, indent); - show_header("Cc", msg->hdrs.cc, indent); - show_header("Date", msg->hdrs.date, indent); - show_header("Subject", msg->hdrs.subject, indent); - - for (a = msg->atts.next; a != &msg->atts; a=a->next) { - printf("========================\n"); - switch (a->ct) { - case CT_TEXT_PLAIN: printf("Attachment type text/plain\n"); break; - case CT_TEXT_HTML: printf("Attachment type text/html\n"); break; - case CT_TEXT_OTHER: printf("Attachment type text/non-plain\n"); break; - case CT_MESSAGE_RFC822: printf("Attachment type message/rfc822\n"); break; - case CT_OTHER: printf("Attachment type other\n"); break; - } - if (a->ct != CT_MESSAGE_RFC822) { - printf("%d bytes\n", a->data.normal.len); - } - if ((a->ct == CT_TEXT_PLAIN) || (a->ct == CT_TEXT_HTML) || (a->ct == CT_TEXT_OTHER)) { - printf("----------\n"); - printf("%s\n", a->data.normal.bytes); - } - if (a->ct == CT_MESSAGE_RFC822) { - show_rfc822(a->data.rfc822, indent + 4); - } - } -} -/*}}}*/ - -int main (int argc, char **argv)/*{{{*/ -{ - struct rfc822 *msg; - - if (argc < 2) { - fprintf(stderr, "Need a path\n"); - unlock_and_exit(2); - } - - msg = make_rfc822(argv[1]); - show_rfc822(msg, 0); - free_rfc822(msg); - - /* Print out some stuff */ - - return 0; -} -/*}}}*/ -#endif /* TEST */