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.
#
# 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
# it under the terms of version 2 of the GNU General Public License as
......@@ -30,7 +30,7 @@ CC=gcc
#CFLAGS=-O2 -pg
CFLAGS=-Wall -g
prefix=/other/mairix/0.3-1
prefix=/usr/local
bindir=$(prefix)/bin
mandir=$(prefix)/man
man1dir=$(mandir)/man1
......@@ -41,16 +41,19 @@ docdir=$(prefix)/docs
# 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
reader.o search.o stats.o dates.o datescan.o
all : mairix
mairix : $(OBJ)
$(CC) -o mairix $(CFLAGS) $(OBJ)
%.o : %.c
%.o : %.c memmac.h mairix.h reader.h Makefile
$(CC) -c $(CFLAGS) $<
datescan.c : datescan.nfa
dfasyn -o datescan.c -v -u datescan.nfa
clean:
-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
......
NEW IN VERSION 0.11
===================
* Detect failed malloc (out of memory) conditions properly and report it.
NEW IN VERSION 0.10
===================
......@@ -6,6 +11,7 @@ NEW IN VERSION 0.10
* 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
==================
......
/*
* 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.
**********************************************************************
* 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
* 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)/*{{{*/
struct stat sb;
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);
strcpy(full_path, folder_base);
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.
**********************************************************************
* 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
* it under the terms of version 2 of the GNU General Public License as
......@@ -30,6 +30,10 @@
#include <ctype.h>
#include <locale.h>
#ifdef TEST_OOM
int total_bytes=0;
#endif
int verbose = 0;
static char *folder_base = NULL;
......@@ -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 buffer[256];
static char cvs_version[] = "$Name: V0_9_2 $";
static char cvs_version[] = "$Name: V0_11_pre1 $";
char *p, *q;
for (p=cvs_version; *p; p++) {
if (*p == ':') {
......@@ -238,7 +291,7 @@ static char *get_version(void)/*{{{*/
static void print_copyright(void)/*{{{*/
{
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"
"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",
......
/*
$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.
......@@ -179,4 +179,7 @@ void search_top(int do_threads, int do_augment, char *database_path, char *folde
/* 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);
#endif /* MAIRIX_H */
......@@ -22,7 +22,7 @@
@author Richard P. Curnow
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 2002 Richard P. Curnow
Copyright @copyright{} 2002, 2003 Richard P. Curnow
@end titlepage
@contents
......
/*
$Header: /cvs/src/mairix/memmac.h,v 1.1 2002/07/03 22:15:59 richard Exp $
$Header: /cvs/src/mairix/memmac.h,v 1.2 2003/01/18 00:38:12 richard Exp $
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
* it under the terms of version 2 of the GNU General Public License as
......@@ -26,12 +26,43 @@
#ifndef MEMMAC_H
#define MEMMAC_H
/*{{{ Safe alloc helpers (GCC extensions) */
extern volatile 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;
}
/*}}}*/
#define Malloc(s) safe_malloc(__FILE__, __LINE__, s)
#define Realloc(xx,s) safe_realloc(__FILE__, __LINE__,xx,s)
/*}}}*/
/*{{{ 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 new_string(s) strcpy((char *) Malloc(1+strlen(s)), (s))