Commit 02c8b87e authored by Richard Curnow's avatar Richard Curnow

Corresponds to CVS V0.11pre1

Original rev  : rc@rc0.org.uk--historical/mairix--history--0--patch-16
parent 59055650
######################################################################### #########################################################################
# #
# $Header: /cvs/src/mairix/Attic/Makefile,v 1.2 2002/07/29 23:03:03 richard Exp $ # $Header: /cvs/src/mairix/Attic/Makefile,v 1.5 2003/02/24 23:56:40 richard Exp $
# #
# ======================================================================= # =======================================================================
# #
# mairix - message index builder and finder for maildir folders. # mairix - message index builder and finder for maildir folders.
# #
# Copyright (C) Richard P. Curnow 2002 # Copyright (C) Richard P. Curnow 2002, 2003
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of version 2 of the GNU General Public License as
...@@ -30,7 +30,7 @@ CC=gcc ...@@ -30,7 +30,7 @@ CC=gcc
#CFLAGS=-O2 -pg #CFLAGS=-O2 -pg
CFLAGS=-Wall -g CFLAGS=-Wall -g
prefix=/other/mairix/0.3-1 prefix=/usr/local
bindir=$(prefix)/bin bindir=$(prefix)/bin
mandir=$(prefix)/man mandir=$(prefix)/man
man1dir=$(mandir)/man1 man1dir=$(mandir)/man1
...@@ -41,16 +41,19 @@ docdir=$(prefix)/docs ...@@ -41,16 +41,19 @@ docdir=$(prefix)/docs
# Things below this point shouldn't need to be edited. # 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 \ OBJ = mairix.o db.o rfc822.o tok.o hash.o dirscan.o writer.o \
reader.o search.o stats.o reader.o search.o stats.o dates.o datescan.o
all : mairix all : mairix
mairix : $(OBJ) mairix : $(OBJ)
$(CC) -o mairix $(CFLAGS) $(OBJ) $(CC) -o mairix $(CFLAGS) $(OBJ)
%.o : %.c %.o : %.c memmac.h mairix.h reader.h Makefile
$(CC) -c $(CFLAGS) $< $(CC) -c $(CFLAGS) $<
datescan.c : datescan.nfa
dfasyn -o datescan.c -v -u datescan.nfa
clean: clean:
-rm -f *~ *.o mairix *.s core mairix.txt mairix.html mairix.dvi mairix.ps mairix.pdf mairix.info -rm -f *~ *.o mairix *.s core mairix.txt mairix.html mairix.dvi mairix.ps mairix.pdf mairix.info
-rm -f mairix.cp mairix.fn mairix.aux mairix.log mairix.ky mairix.pg mairix.toc mairix.tp mairix.vr -rm -f mairix.cp mairix.fn mairix.aux mairix.log mairix.ky mairix.pg mairix.toc mairix.tp mairix.vr
......
NEW IN VERSION 0.11
===================
* Detect failed malloc (out of memory) conditions properly and report it.
NEW IN VERSION 0.10 NEW IN VERSION 0.10
=================== ===================
...@@ -6,6 +11,7 @@ NEW IN VERSION 0.10 ...@@ -6,6 +11,7 @@ NEW IN VERSION 0.10
* Add an ACKNOWLEDGEMENTS file. * Add an ACKNOWLEDGEMENTS file.
* Hack to handle missing NAME_MAX on various non-Linux systems * Hack to handle missing NAME_MAX on various non-Linux systems
* Improve mairix.spec file for RPM building * Improve mairix.spec file for RPM building
* Change default value for prefix in Makefile to make it more standard.
NEW IN VERSION 0.9 NEW IN VERSION 0.9
================== ==================
......
/*
* Scan a date string to return stuff.
* */
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <assert.h>
#include "mairix.h"
#include "dates.h"
static enum DATESCAN_TYPE discover_type(char *first, char *last)
{
int current_state = 0;
int token;
char *p;
p = first;
while (p < last) {
switch (*p) {
case '0': token = 0; break;
case '1': token = 1; break;
case '2': token = 2; break;
case '3': token = 3; break;
case '4' ... '9':
token = 4; break;
case 'a' ... 'z':
case 'A' ... 'Z':
token = 5; break;
default:
token = -1; break;
}
current_state = datescan_next_state(current_state, token);
if (current_state < 0) break;
p++;
}
if (current_state < 0) {
return DS_FAILURE;
} else {
return datescan_exitval[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 {
/* 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);
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);
}
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
#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 */
# NFA description for parsing dates
# Stuff to pass through verbatim
%{
#include "dates.h"
%}
Tokens D0 D1 D2 D3 D49 A
Abbrev D01 = D0 | D1
Abbrev D12 = D1 | D2
Abbrev D29 = D2 | D3 | D49
Abbrev D19 = D1 | D29
Abbrev D09 = D0 | D19
Abbrev D = D09
BLOCK day
State in
D0 ; D19 -> out
D12 ; D09 -> out
D3 ; D01 -> out
ENDBLOCK
# Match 2 digit year
BLOCK year
State in
D3 ; D29 -> out
D49 ; D09 -> out
ENDBLOCK
BLOCK month
State in
A ; A ; A -> out
ENDBLOCK
BLOCK scaled
State in
D -> in, after_value
State after_value
A -> out
ENDBLOCK
BLOCK ccyy
State in
D19 ; D ; D ; D -> out
ENDBLOCK
BLOCK main
State in
D19 = DS_D
<day:in->out> = DS_D
<year:in->out> = DS_Y
<ccyy:in->out> = DS_Y
D ; D ; D ; D ; D ; D = DS_YYMMDD
D ; D ; D ; D ; D ; D ; D ; D = DS_YYMMDD
<scaled:in->out> = DS_SCALED
<month:in->out> = DS_M
D19 ; <month:in->out> = DS_DM
<day:in->out> ; <month:in->out> = DS_DM
<month:in->out> ; D19 = 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> ; D19 = DS_YMD
<year:in->out> ; <month:in->out> ; <day:in->out> = DS_YMD
D19 ; <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> ; D19 = DS_YMD
<ccyy:in->out> ; <month:in->out> ; <day:in->out> = DS_YMD
D19 ; <month:in->out> ; <ccyy:in->out> = DS_DMY
<day:in->out> ; <month:in->out> ; <ccyy:in->out> = DS_DMY
ENDBLOCK
RESULT DS_D
RESULT DS_Y
RESULT DS_YYMMDD
RESULT DS_SCALED
RESULT DS_M
RESULT DS_DM
RESULT DS_MD
RESULT DS_YM
RESULT DS_MY
RESULT DS_YMD
RESULT DS_DMY
DEFRESULT DS_FAILURE
TYPE "enum DATESCAN_TYPE"
PREFIX datescan
# vim:ft=txt:et:sw=4:sts=4:ht=4
/* /*
$Header: /cvs/src/mairix/dirscan.c,v 1.6 2003/01/02 23:27:42 richard Exp $ $Header: /cvs/src/mairix/dirscan.c,v 1.8 2003/01/18 00:38:12 richard Exp $
mairix - message index builder and finder for maildir folders. mairix - message index builder and finder for maildir folders.
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 2002 * Copyright (C) Richard P. Curnow 2002, 2003
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
...@@ -195,7 +195,7 @@ static int looks_like_maildir(char *folder_base, char *name)/*{{{*/ ...@@ -195,7 +195,7 @@ static int looks_like_maildir(char *folder_base, char *name)/*{{{*/
struct stat sb; struct stat sb;
int result = 0; int result = 0;
child_name = (char *) malloc(strlen(folder_base) + strlen(name) + 6); child_name = new_array(char, strlen(folder_base) + strlen(name) + 6);
full_path = new_array(char, strlen(folder_base) + strlen(name) + 2); full_path = new_array(char, strlen(folder_base) + strlen(name) + 2);
strcpy(full_path, folder_base); strcpy(full_path, folder_base);
strcat(full_path, "/"); strcat(full_path, "/");
......
/* /*
$Header: /cvs/src/mairix/mairix.c,v 1.10 2002/12/29 23:44:46 richard Exp $ $Header: /cvs/src/mairix/mairix.c,v 1.12 2003/01/18 00:38:12 richard Exp $
mairix - message index builder and finder for maildir folders. mairix - message index builder and finder for maildir folders.
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 2002 * Copyright (C) Richard P. Curnow 2002, 2003
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
...@@ -30,6 +30,10 @@ ...@@ -30,6 +30,10 @@
#include <ctype.h> #include <ctype.h>
#include <locale.h> #include <locale.h>
#ifdef TEST_OOM
int total_bytes=0;
#endif
int verbose = 0; int verbose = 0;
static char *folder_base = NULL; static char *folder_base = NULL;
...@@ -208,10 +212,59 @@ static int check_message_list_for_duplicates(struct msgpath_array *msgs)/*{{{*/ ...@@ -208,10 +212,59 @@ static int check_message_list_for_duplicates(struct msgpath_array *msgs)/*{{{*/
} }
/*}}}*/ /*}}}*/
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;
}
/*}}}*/
volatile 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(1);
}
/*}}}*/
static char *get_version(void)/*{{{*/ static char *get_version(void)/*{{{*/
{ {
static char buffer[256]; static char buffer[256];
static char cvs_version[] = "$Name: V0_9_2 $"; static char cvs_version[] = "$Name: V0_11_pre1 $";
char *p, *q; char *p, *q;
for (p=cvs_version; *p; p++) { for (p=cvs_version; *p; p++) {
if (*p == ':') { if (*p == ':') {
...@@ -238,7 +291,7 @@ static char *get_version(void)/*{{{*/ ...@@ -238,7 +291,7 @@ static char *get_version(void)/*{{{*/
static void print_copyright(void)/*{{{*/ static void print_copyright(void)/*{{{*/
{ {
fprintf(stderr, fprintf(stderr,
"mairix %s, Copyright (C) 2002 Richard P. Curnow\n" "mairix %s, Copyright (C) 2002, 2003 Richard P. Curnow\n"
"mairix comes with ABSOLUTELY NO WARRANTY.\n" "mairix comes with ABSOLUTELY NO WARRANTY.\n"
"This is free software, and you are welcome to redistribute it\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", "under certain conditions; see the GNU General Public License for details.\n\n",
......
/* /*
$Header: /cvs/src/mairix/mairix.h,v 1.4 2002/12/29 23:44:46 richard Exp $ $Header: /cvs/src/mairix/mairix.h,v 1.5 2003/02/24 23:56:40 richard Exp $
mairix - message index builder and finder for maildir folders. mairix - message index builder and finder for maildir folders.
...@@ -179,4 +179,7 @@ void search_top(int do_threads, int do_augment, char *database_path, char *folde ...@@ -179,4 +179,7 @@ void search_top(int do_threads, int do_augment, char *database_path, char *folde
/* In stats.c */ /* In stats.c */
void get_db_stats(struct database *db); 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);
#endif /* MAIRIX_H */ #endif /* MAIRIX_H */
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
@author Richard P. Curnow @author Richard P. Curnow
@page @page