- Added all source code.

This commit is contained in:
Paul Beckingham 2008-04-19 22:11:59 -04:00
parent 7f8fc1182d
commit b5be083d88
27 changed files with 7842 additions and 0 deletions

191
src/Config.cpp Normal file
View file

@ -0,0 +1,191 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2005 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <fstream>
#include <sstream>
#include "task.h"
#include "Config.h"
////////////////////////////////////////////////////////////////////////////////
Config::Config ()
{
}
////////////////////////////////////////////////////////////////////////////////
Config::Config (const std::string& file)
{
load (file);
}
////////////////////////////////////////////////////////////////////////////////
// Read the Configuration filee and populate the *this map. The file format
// is simply lines with name=value pairs. Whitespace between name, = and value
// is not tolerated, but blank lines and comments starting with # are allowed.
bool Config::load (const std::string& file)
{
std::ifstream in;
in.open (file.c_str (), std::ifstream::in);
if (in.good ())
{
std::string line;
while (getline (in, line))
{
// Remove comments.
unsigned int pound = line.find ("#");
if (pound != std::string::npos)
line = line.substr (0, pound);
line = trim (line, " \t");
// Skip empty lines.
if (line.length () > 0)
{
unsigned int equal = line.find ("=");
if (equal != std::string::npos)
{
std::string key = trim (line.substr (0, equal), " \t");
std::string value = trim (line.substr (equal+1, line.length () - equal), " \t");
(*this)[key] = value;
}
}
}
in.close ();
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
// Return the configuration value given the specified key.
const std::string& Config::get (const char* key)
{
return this->get (std::string (key));
}
////////////////////////////////////////////////////////////////////////////////
// Return the configuration value given the specified key. If a default_value
// is present, it will be the returned value in the event of a missing key.
const std::string& Config::get (
const char* key,
const char* default_value)
{
return this->get (std::string (key), std::string (default_value));
}
////////////////////////////////////////////////////////////////////////////////
// Return the configuration value given the specified key.
const std::string& Config::get (const std::string& key)
{
return (*this)[key];
}
////////////////////////////////////////////////////////////////////////////////
// Return the configuration value given the specified key. If a default_value
// is present, it will be the returned value in the event of a missing key.
const std::string& Config::get (
const std::string& key,
const std::string& default_value)
{
if ((*this).find (key) != (*this).end ())
return (*this)[key];
return default_value;
}
////////////////////////////////////////////////////////////////////////////////
bool Config::get (const std::string& key, bool default_value)
{
if ((*this).find (key) != (*this).end ())
{
std::string value = lowerCase ((*this)[key]);
if (value == "t" ||
value == "true" ||
value == "1" ||
value == "yes" ||
value == "on")
return true;
return false;
}
return default_value;
}
////////////////////////////////////////////////////////////////////////////////
int Config::get (const std::string& key, const int default_value)
{
if ((*this).find (key) != (*this).end ())
return ::atoi ((*this)[key].c_str ());
return default_value;
}
////////////////////////////////////////////////////////////////////////////////
double Config::get (const std::string& key, const double default_value)
{
if ((*this).find (key) != (*this).end ())
return ::atof ((*this)[key].c_str ());
return default_value;
}
////////////////////////////////////////////////////////////////////////////////
void Config::set (const std::string& key, const int value)
{
char v[24];
sprintf (v, "%d", value);
(*this)[key] = v;
}
////////////////////////////////////////////////////////////////////////////////
void Config::set (const std::string& key, const double value)
{
char v[32];
sprintf (v, "%f", value);
(*this)[key] = v;
}
////////////////////////////////////////////////////////////////////////////////
void Config::set (const std::string& key, const std::string& value)
{
(*this)[key] = value;
}
////////////////////////////////////////////////////////////////////////////////
// The vector form of Config::get assumes the single value is comma-separated,
// and splits accordingly.
void Config::get (
const std::string& key,
std::vector <std::string>& values)
{
values.clear ();
split (values, (*this)[key], ',');
}
////////////////////////////////////////////////////////////////////////////////
// The vector form of Config::set joins the values together with commas, and
// stores the single value.
void Config::set (
const std::string& key,
const std::vector <std::string>& values)
{
std::string conjoined;
join (conjoined, ",", values);
(*this)[key] = conjoined;
}
////////////////////////////////////////////////////////////////////////////////
// Provide a vector of all configuration keys.
void Config::all (std::vector<std::string>& items)
{
foreach (i, *this)
items.push_back (i->first);
}
////////////////////////////////////////////////////////////////////////////////

37
src/Config.h Normal file
View file

@ -0,0 +1,37 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2005 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_CONFIG
#define INCLUDED_CONFIG
#include <map>
#include <vector>
#include <string>
class Config : public std::map <std::string, std::string>
{
public:
Config ();
Config (const std::string&);
bool load (const std::string&);
const std::string& get (const char*);
const std::string& get (const char*, const char*);
const std::string& get (const std::string&);
const std::string& get (const std::string&, const std::string&);
bool get (const std::string&, bool);
int get (const std::string&, const int);
double get (const std::string&, const double);
void get (const std::string&, std::vector <std::string>&);
void set (const std::string&, const int);
void set (const std::string&, const double);
void set (const std::string&, const std::string&);
void set (const std::string&, const std::vector <std::string>&);
void all (std::vector <std::string>&);
};
#endif
////////////////////////////////////////////////////////////////////////////////

303
src/Date.cpp Normal file
View file

@ -0,0 +1,303 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2005 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <time.h>
#include "task.h"
#include "Date.h"
////////////////////////////////////////////////////////////////////////////////
// Defaults to "now".
Date::Date ()
{
mT = time (NULL);
}
////////////////////////////////////////////////////////////////////////////////
Date::Date (const time_t t)
{
mT = t;
}
////////////////////////////////////////////////////////////////////////////////
Date::Date (const int m, const int d, const int y)
{
// Error if not valid.
struct tm t = {0};
t.tm_mday = d;
t.tm_mon = m - 1;
t.tm_year = y - 1900;
mT = mktime (&t);
}
////////////////////////////////////////////////////////////////////////////////
Date::Date (const std::string& mdy)
{
unsigned int firstSlash = mdy.find ("/");
unsigned int secondSlash = mdy.find ("/", firstSlash + 1);
if (firstSlash != std::string::npos &&
secondSlash != std::string::npos)
{
int m = ::atoi (mdy.substr (0, firstSlash ).c_str ());
int d = ::atoi (mdy.substr (firstSlash + 1, secondSlash - firstSlash).c_str ());
int y = ::atoi (mdy.substr (secondSlash + 1, std::string::npos ).c_str ());
if (!valid (m, d, y))
throw std::string ("\"") + mdy + "\" is not a valid date.";
// Duplicate Date::Date (const int, const int, const int);
struct tm t = {0};
t.tm_mday = d;
t.tm_mon = m - 1;
t.tm_year = y - 1900;
mT = mktime (&t);
}
else
throw std::string ("\"") + mdy + "\" is not a valid date.";
}
////////////////////////////////////////////////////////////////////////////////
Date::Date (const Date& rhs)
{
mT = rhs.mT;
}
////////////////////////////////////////////////////////////////////////////////
Date::~Date ()
{
}
////////////////////////////////////////////////////////////////////////////////
time_t Date::toEpoch ()
{
return mT;
}
////////////////////////////////////////////////////////////////////////////////
void Date::toEpoch (time_t& epoch)
{
epoch = mT;
}
////////////////////////////////////////////////////////////////////////////////
void Date::toMDY (int& m, int& d, int& y)
{
struct tm* t = localtime (&mT);
m = t->tm_mon + 1;
d = t->tm_mday;
y = t->tm_year + 1900;
}
////////////////////////////////////////////////////////////////////////////////
void Date::toString (std::string& output)
{
output = toString ();
}
////////////////////////////////////////////////////////////////////////////////
std::string Date::toString (void)
{
int m, d, y;
toMDY (m, d, y);
char formatted [11];
sprintf (formatted, "%d/%d/%d", m, d, y);
return std::string (formatted);
}
////////////////////////////////////////////////////////////////////////////////
bool Date::valid (const int m, const int d, const int y)
{
// Check that the year is valid.
if (y < 0)
return false;
// Check that the month is valid.
if (m < 1 || m > 12)
return false;
// Finally check that the days fall within the acceptable range for this
// month, and whether or not this is a leap year.
if (d < 1 || d > Date::daysInMonth (m, y))
return false;
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool Date::leapYear (int year)
{
bool ly = false;
if (!(year % 4)) ly = true;
else if (!(year % 400)) ly = true;
else if (!(year % 100)) ly = false;
return ly;
}
////////////////////////////////////////////////////////////////////////////////
int Date::daysInMonth (int month, int year)
{
static int days[2][12] =
{
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
return days[Date::leapYear (year) ? 1 : 0][month - 1];
}
////////////////////////////////////////////////////////////////////////////////
std::string Date::monthName (int month)
{
static char* months[12] =
{
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
};
assert (month > 0);
assert (month <= 12);
return months[month -1];
}
////////////////////////////////////////////////////////////////////////////////
void Date::dayName (int dow, std::string& name)
{
static char* days[7] =
{
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
};
name = days[dow];
}
////////////////////////////////////////////////////////////////////////////////
std::string Date::dayName (int dow)
{
static char* days[7] =
{
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
};
return days[dow];
}
////////////////////////////////////////////////////////////////////////////////
int Date::dayOfWeek ()
{
struct tm* t = localtime (&mT);
return t->tm_wday;
}
////////////////////////////////////////////////////////////////////////////////
int Date::month ()
{
struct tm* t = localtime (&mT);
return t->tm_mon + 1;
}
////////////////////////////////////////////////////////////////////////////////
int Date::day ()
{
struct tm* t = localtime (&mT);
return t->tm_mday;
}
////////////////////////////////////////////////////////////////////////////////
int Date::year ()
{
struct tm* t = localtime (&mT);
return t->tm_year + 1900;
}
////////////////////////////////////////////////////////////////////////////////
bool Date::operator== (const Date& rhs)
{
return rhs.mT == mT;
}
////////////////////////////////////////////////////////////////////////////////
bool Date::operator!= (const Date& rhs)
{
return rhs.mT != mT;
}
////////////////////////////////////////////////////////////////////////////////
bool Date::operator< (const Date& rhs)
{
return mT < rhs.mT;
}
////////////////////////////////////////////////////////////////////////////////
bool Date::operator> (const Date& rhs)
{
return mT > rhs.mT;
}
////////////////////////////////////////////////////////////////////////////////
bool Date::operator<= (const Date& rhs)
{
return mT <= rhs.mT;
}
////////////////////////////////////////////////////////////////////////////////
bool Date::operator>= (const Date& rhs)
{
return mT >= rhs.mT;
}
////////////////////////////////////////////////////////////////////////////////
Date Date::operator+ (const int delta)
{
return Date::Date (mT + delta);
}
////////////////////////////////////////////////////////////////////////////////
Date& Date::operator+= (const int delta)
{
mT += (time_t) delta;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Date& Date::operator-= (const int delta)
{
mT -= (time_t) delta;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
time_t Date::operator- (const Date& rhs)
{
return mT - rhs.mT;
}
////////////////////////////////////////////////////////////////////////////////

60
src/Date.h Normal file
View file

@ -0,0 +1,60 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2005 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_DATE
#define INCLUDED_DATE
#include <string>
class Date;
class Date
{
public:
Date ();
Date (time_t);
Date (const int, const int, const int);
Date (const std::string&);
Date (const Date&);
virtual ~Date ();
void toEpoch (time_t&);
time_t toEpoch ();
void toMDY (int&, int&, int&);
void toString (std::string&);
std::string toString (void);
static bool valid (const int, const int, const int);
static bool leapYear (int);
static int daysInMonth (int, int);
static std::string monthName (int);
static void dayName (int, std::string&);
static std::string dayName (int);
int dayOfWeek ();
int month ();
int day ();
int year ();
bool operator== (const Date&);
bool operator!= (const Date&);
bool operator< (const Date&);
bool operator> (const Date&);
bool operator<= (const Date&);
bool operator>= (const Date&);
Date operator+ (const int);
Date& operator+= (const int);
Date& operator-= (const int);
time_t operator- (const Date&);
protected:
time_t mT;
};
#endif
////////////////////////////////////////////////////////////////////////////////

429
src/Makefile Normal file
View file

@ -0,0 +1,429 @@
# Makefile.in generated by automake 1.10 from Makefile.am.
# src/Makefile. Generated from Makefile.in by configure.
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
pkgdatadir = $(datadir)/task
pkglibdir = $(libdir)/task
pkgincludedir = $(includedir)/task
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
bin_PROGRAMS = task$(EXEEXT)
subdir = src
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/auto.h
CONFIG_CLEAN_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
am_task_OBJECTS = Config.$(OBJEXT) Date.$(OBJEXT) T.$(OBJEXT) \
TDB.$(OBJEXT) Table.$(OBJEXT) color.$(OBJEXT) parse.$(OBJEXT) \
task.$(OBJEXT) util.$(OBJEXT) text.$(OBJEXT) rules.$(OBJEXT)
task_OBJECTS = $(am_task_OBJECTS)
task_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I. -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
CXXLD = $(CXX)
CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
-o $@
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(task_SOURCES)
DIST_SOURCES = $(task_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = ${SHELL} /Users/paul/work/task_rel/missing --run aclocal-1.10
AMTAR = ${SHELL} /Users/paul/work/task_rel/missing --run tar
AUTOCONF = ${SHELL} /Users/paul/work/task_rel/missing --run autoconf
AUTOHEADER = ${SHELL} /Users/paul/work/task_rel/missing --run autoheader
AUTOMAKE = ${SHELL} /Users/paul/work/task_rel/missing --run automake-1.10
AWK = awk
CC = gcc
CCDEPMODE = depmode=gcc3
CFLAGS = -g -O2
CPPFLAGS =
CXX = g++
CXXCPP = g++ -E
CXXDEPMODE = depmode=gcc3
CXXFLAGS = -g -O2
CYGPATH_W = echo
DEFS = -DHAVE_CONFIG_H
DEPDIR = .deps
ECHO_C = \c
ECHO_N =
ECHO_T =
EGREP = /usr/bin/grep -E
EXEEXT =
GREP = /usr/bin/grep
INSTALL = /usr/bin/install -c
INSTALL_DATA = ${INSTALL} -m 644
INSTALL_PROGRAM = ${INSTALL}
INSTALL_SCRIPT = ${INSTALL}
INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
LDFLAGS =
LIBOBJS = ${LIBOBJDIR}mktime$U.o
LIBS = -lncurses
LTLIBOBJS = ${LIBOBJDIR}mktime$U.lo
MAKEINFO = ${SHELL} /Users/paul/work/task_rel/missing --run makeinfo
MKDIR_P = .././install-sh -c -d
OBJEXT = o
PACKAGE = task
PACKAGE_BUGREPORT = bugs@beckingham.net
PACKAGE_NAME = task
PACKAGE_STRING = task 0.9.0
PACKAGE_TARNAME = task
PACKAGE_VERSION = 0.9.0
PATH_SEPARATOR = :
SET_MAKE =
SHELL = /bin/sh
STRIP =
VERSION = 0.9.0
abs_builddir = /Users/paul/work/task_rel/src
abs_srcdir = /Users/paul/work/task_rel/src
abs_top_builddir = /Users/paul/work/task_rel
abs_top_srcdir = /Users/paul/work/task_rel
ac_ct_CC = gcc
ac_ct_CXX = g++
am__include = include
am__leading_dot = .
am__quote =
am__tar = ${AMTAR} chof - "$$tardir"
am__untar = ${AMTAR} xf -
bindir = ${exec_prefix}/bin
build_alias =
builddir = .
datadir = ${datarootdir}
datarootdir = ${prefix}/share
docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
dvidir = ${docdir}
exec_prefix = ${prefix}
host_alias =
htmldir = ${docdir}
includedir = ${prefix}/include
infodir = ${datarootdir}/info
install_sh = $(SHELL) /Users/paul/work/task_rel/install-sh
libdir = ${exec_prefix}/lib
libexecdir = ${exec_prefix}/libexec
localedir = ${datarootdir}/locale
localstatedir = ${prefix}/var
mandir = ${datarootdir}/man
mkdir_p = $(top_builddir)/./install-sh -c -d
oldincludedir = /usr/include
pdfdir = ${docdir}
prefix = /usr/local
program_transform_name = s,x,x,
psdir = ${docdir}
sbindir = ${exec_prefix}/sbin
sharedstatedir = ${prefix}/com
srcdir = .
subdirs = src
sysconfdir = ${prefix}/etc
target_alias =
top_builddir = ..
top_srcdir = ..
task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp color.cpp parse.cpp task.cpp util.cpp text.cpp rules.cpp Config.h Date.h T.h TDB.h Table.h color.h stlmacros.h task.h
all: all-am
.SUFFIXES:
.SUFFIXES: .cpp .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu src/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
@list='$(bin_PROGRAMS)'; for p in $$list; do \
p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
if test -f $$p \
; then \
f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
$(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
else :; fi; \
done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
rm -f "$(DESTDIR)$(bindir)/$$f"; \
done
clean-binPROGRAMS:
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
task$(EXEEXT): $(task_OBJECTS) $(task_DEPENDENCIES)
@rm -f task$(EXEEXT)
$(CXXLINK) $(task_OBJECTS) $(task_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
include ./$(DEPDIR)/Config.Po
include ./$(DEPDIR)/Date.Po
include ./$(DEPDIR)/T.Po
include ./$(DEPDIR)/TDB.Po
include ./$(DEPDIR)/Table.Po
include ./$(DEPDIR)/color.Po
include ./$(DEPDIR)/parse.Po
include ./$(DEPDIR)/rules.Po
include ./$(DEPDIR)/task.Po
include ./$(DEPDIR)/text.Po
include ./$(DEPDIR)/util.Po
.cpp.o:
$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
# source='$<' object='$@' libtool=no \
# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
# $(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
# source='$<' object='$@' libtool=no \
# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
# $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$tags $$unique; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& cd $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) $$here
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS)
installdirs:
for dir in "$(DESTDIR)$(bindir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-exec-am: install-binPROGRAMS
install-html: install-html-am
install-info: install-info-am
install-man:
install-pdf: install-pdf-am
install-ps: install-ps-am
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-binPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
clean-generic ctags distclean distclean-compile \
distclean-generic distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-binPROGRAMS \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
uninstall-am uninstall-binPROGRAMS
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

2
src/Makefile.am Normal file
View file

@ -0,0 +1,2 @@
bin_PROGRAMS = task
task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp color.cpp parse.cpp task.cpp util.cpp text.cpp rules.cpp Config.h Date.h T.h TDB.h Table.h color.h stlmacros.h task.h

429
src/Makefile.in Normal file
View file

@ -0,0 +1,429 @@
# Makefile.in generated by automake 1.10 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
bin_PROGRAMS = task$(EXEEXT)
subdir = src
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/auto.h
CONFIG_CLEAN_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
am_task_OBJECTS = Config.$(OBJEXT) Date.$(OBJEXT) T.$(OBJEXT) \
TDB.$(OBJEXT) Table.$(OBJEXT) color.$(OBJEXT) parse.$(OBJEXT) \
task.$(OBJEXT) util.$(OBJEXT) text.$(OBJEXT) rules.$(OBJEXT)
task_OBJECTS = $(am_task_OBJECTS)
task_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
CXXLD = $(CXX)
CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
-o $@
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(task_SOURCES)
DIST_SOURCES = $(task_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build_alias = @build_alias@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host_alias = @host_alias@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
subdirs = @subdirs@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp color.cpp parse.cpp task.cpp util.cpp text.cpp rules.cpp Config.h Date.h T.h TDB.h Table.h color.h stlmacros.h task.h
all: all-am
.SUFFIXES:
.SUFFIXES: .cpp .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu src/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
@list='$(bin_PROGRAMS)'; for p in $$list; do \
p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
if test -f $$p \
; then \
f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
$(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
else :; fi; \
done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
rm -f "$(DESTDIR)$(bindir)/$$f"; \
done
clean-binPROGRAMS:
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
task$(EXEEXT): $(task_OBJECTS) $(task_DEPENDENCIES)
@rm -f task$(EXEEXT)
$(CXXLINK) $(task_OBJECTS) $(task_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Config.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Date.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/T.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TDB.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Table.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/color.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rules.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/text.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$tags $$unique; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& cd $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) $$here
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS)
installdirs:
for dir in "$(DESTDIR)$(bindir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-exec-am: install-binPROGRAMS
install-html: install-html-am
install-info: install-info-am
install-man:
install-pdf: install-pdf-am
install-ps: install-ps-am
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-binPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
clean-generic ctags distclean distclean-compile \
distclean-generic distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-binPROGRAMS \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
uninstall-am uninstall-binPROGRAMS
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

510
src/T.cpp Normal file
View file

@ -0,0 +1,510 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <algorithm>
#include "task.h"
#include "T.h"
////////////////////////////////////////////////////////////////////////////////
// Default
T::T ()
{
mUUID = uuid ();
mStatus = pending;
mId = 0;
mTags.clear ();
mAttributes.clear ();
mDescription = "";
}
////////////////////////////////////////////////////////////////////////////////
// Initialize by parsing storage format
T::T (const std::string& line)
{
parse (line);
}
////////////////////////////////////////////////////////////////////////////////
T::T (const T& other)
{
mStatus = other.mStatus;
mUUID = other.mUUID;
mId = other.mId;
mDescription = other.mDescription;
mTags = other.mTags;
mRemoveTags = other.mRemoveTags;
mAttributes = other.mAttributes;
}
////////////////////////////////////////////////////////////////////////////////
T& T::operator= (const T& other)
{
if (this != &other)
{
mStatus = other.mStatus;
mUUID = other.mUUID;
mId = other.mId;
mDescription = other.mDescription;
mTags = other.mTags;
mRemoveTags = other.mRemoveTags;
mAttributes = other.mAttributes;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
T::~T ()
{
}
////////////////////////////////////////////////////////////////////////////////
bool T::hasTag (const std::string& tag) const
{
std::vector <std::string>::const_iterator it = find (mTags.begin (), mTags.end (), tag);
if (it != mTags.end ())
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
// SPECIAL METHOD - DO NOT REMOVE
void T::getRemoveTags (std::vector<std::string>& all)
{
all = mRemoveTags;
}
////////////////////////////////////////////////////////////////////////////////
// SPECIAL METHOD - DO NOT REMOVE
void T::addRemoveTag (const std::string& tag)
{
if (tag.find (' ') != std::string::npos)
throw std::string ("T::addRemoveTag - tags may not contain spaces");
mRemoveTags.push_back (tag);
}
////////////////////////////////////////////////////////////////////////////////
void T::getTags (std::vector<std::string>& all) const
{
all = mTags;
}
////////////////////////////////////////////////////////////////////////////////
void T::addTag (const std::string& tag)
{
if (tag.find (' ') != std::string::npos)
throw std::string ("T::addTag - tags may not contain spaces");
if (tag[0] == '+')
{
if (! hasTag (tag.substr (1, std::string::npos)))
mTags.push_back (tag.substr (1, std::string::npos));
}
else
{
if (! hasTag (tag))
mTags.push_back (tag);
}
}
////////////////////////////////////////////////////////////////////////////////
void T::addTags (const std::vector <std::string>& tags)
{
for (unsigned int i = 0; i < tags.size (); ++i)
{
if (tags[i].find (' ') != std::string::npos)
throw std::string ("T::addTags - tags may not contain spaces");
if (tags[i][0] == '+')
{
if (! hasTag (tags[i].substr (1, std::string::npos)))
mTags.push_back (tags[i].substr (1, std::string::npos));
}
else
{
if (! hasTag (tags[i]))
mTags.push_back (tags[i]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
void T::removeTag (const std::string& tag)
{
std::vector <std::string> copy;
for (unsigned int i = 0; i < mTags.size (); ++i)
if (mTags[i] != tag)
copy.push_back (mTags[i]);
mTags = copy;
}
////////////////////////////////////////////////////////////////////////////////
void T::removeTags ()
{
mTags.clear ();
}
////////////////////////////////////////////////////////////////////////////////
void T::getAttributes (std::map<std::string, std::string>& all)
{
all = mAttributes;
}
////////////////////////////////////////////////////////////////////////////////
const std::string T::getAttribute (const std::string& name)
{
if (mAttributes.find (name) != mAttributes.end ())
return mAttributes[name];
return "";
}
////////////////////////////////////////////////////////////////////////////////
void T::setAttribute (const std::string& name, const std::string& value)
{
if (name.find (' ') != std::string::npos)
throw std::string ("An attribute name may not contain spaces");
if (value.find (' ') != std::string::npos)
throw std::string ("An attribute value may not contain spaces");
mAttributes[name] = value;
}
////////////////////////////////////////////////////////////////////////////////
void T::setAttributes (const std::map <std::string, std::string>& attributes)
{
foreach (i, attributes)
{
if (i->first.find (' ') != std::string::npos)
throw std::string ("An attribute name may not contain spaces");
if (i->second.find (' ') != std::string::npos)
throw std::string ("An attribute value may not contain spaces");
mAttributes[i->first] = i->second;
}
}
////////////////////////////////////////////////////////////////////////////////
void T::removeAttributes ()
{
mAttributes.clear ();
}
////////////////////////////////////////////////////////////////////////////////
void T::removeAttribute (const std::string& name)
{
std::map <std::string, std::string> copy = mAttributes;
mAttributes.clear ();
foreach (i, copy)
if (i->first != name)
mAttributes[i->first] = i->second;
}
////////////////////////////////////////////////////////////////////////////////
void T::getSubstitution (std::string& from, std::string& to) const
{
from = mFrom;
to = mTo;
}
////////////////////////////////////////////////////////////////////////////////
void T::setSubstitution (const std::string& from, const std::string& to)
{
mFrom = from;
mTo = to;
}
////////////////////////////////////////////////////////////////////////////////
// uuid status [tags] [attributes] description
//
// uuid \x{8}-\x{4}-\x{4}-\x{4}-\x{12}
// status - O X
// tags \w+ \s ...
// attributes \w+:\w+ \s ...
// description .+
//
const std::string T::compose () const
{
// UUID
std::string line = mUUID + ' ';
// Status
if (mStatus == pending) line += "- [";
else if (mStatus == completed) line += "+ [";
else if (mStatus == deleted) line += "X [";
// Tags
for (unsigned int i = 0; i < mTags.size (); ++i)
{
line += (i > 0 ? " " : "");
line += mTags[i];
}
line += "] [";
// Attributes
int count = 0;
foreach (i, mAttributes)
{
std::string converted = i->second;
// Date attributes may need conversion to epoch.
if (i->first == "due" ||
i->first == "start" ||
i->first == "entry" ||
i->first == "end")
{
if (i->second.find ("/") != std::string::npos)
validDate (converted);
}
line += (count > 0 ? " " : "");
line += i->first + ":" + converted;
++count;
}
line += "] ";
// Description
line += mDescription;
line += "\n";
if (line.length () > T_LINE_MAX)
throw std::string ("Line too long");
return line;
}
////////////////////////////////////////////////////////////////////////////////
const std::string T::composeCSV ()
{
// UUID
std::string line = "'" + mUUID + "',";
// Status
if (mStatus == pending) line += "'pending',";
else if (mStatus == completed) line += "'completed',";
else if (mStatus == deleted) line += "'deleted',";
// Tags
line += "'";
for (unsigned int i = 0; i < mTags.size (); ++i)
{
line += (i > 0 ? " " : "");
line += mTags[i];
}
line += "',";
std::string value = mAttributes["entry"];
line += value + ",";
value = mAttributes["start"];
if (value != "")
line += value;
line += ",";
value = mAttributes["due"];
if (value != "")
line += value;
line += ",";
value = mAttributes["end"];
if (value != "")
line += value;
line += ",";
value = mAttributes["project"];
if (value != "")
line += "'" + value + "'";
line += ",";
value = mAttributes["priority"];
if (value != "")
line += "'" + value + "'";
line += ",";
value = mAttributes["fg"];
if (value != "")
line += "'" + value + "'";
line += ",";
value = mAttributes["bg"];
if (value != "")
line += "'" + value + "'";
line += ",";
line += "'" + mDescription + "'\n";
return line;
}
////////////////////////////////////////////////////////////////////////////////
// Read all file formats, write only the latest.
void T::parse (const std::string& line)
{
switch (determineVersion (line))
{
// File format version 1, from 2006.11.27 - 2007.12.31
case 1:
{
// Generate a UUID for forward support.
mUUID = uuid ();
if (line.length () > 6) // ^\[\]\s\[\]\n
{
if (line[0] == 'X')
setStatus (deleted);
unsigned int openTagBracket = line.find ("[");
unsigned int closeTagBracket = line.find ("]", openTagBracket);
if (openTagBracket != std::string::npos &&
closeTagBracket != std::string::npos)
{
unsigned int openAttrBracket = line.find ("[", closeTagBracket);
unsigned int closeAttrBracket = line.find ("]", openAttrBracket);
if (openAttrBracket != std::string::npos &&
closeAttrBracket != std::string::npos)
{
std::string tags = line.substr (
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
std::vector <std::string> rawTags;
split (mTags, tags, ' ');
std::string attributes = line.substr (
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
std::vector <std::string> pairs;
split (pairs, attributes, ' ');
for (unsigned int i = 0; i < pairs.size (); ++i)
{
std::vector <std::string> pair;
split (pair, pairs[i], ':');
if (pair[1] != "")
mAttributes[pair[0]] = pair[1];
}
mDescription = line.substr (closeAttrBracket + 2, std::string::npos);
}
else
throw std::string ("Missing attribute brackets");
}
else
throw std::string ("Missing tag brackets");
}
else
throw std::string ("Line too short");
}
break;
// File format version 2, from 2008.1.1
case 2:
{
if (line.length () > 46) // ^.{36} . \[\] \[\] \n
{
mUUID = line.substr (0, 36);
mStatus = line[37] == '+' ? completed
: line[37] == 'X' ? deleted
: pending;
unsigned int openTagBracket = line.find ("[");
unsigned int closeTagBracket = line.find ("]", openTagBracket);
if (openTagBracket != std::string::npos &&
closeTagBracket != std::string::npos)
{
unsigned int openAttrBracket = line.find ("[", closeTagBracket);
unsigned int closeAttrBracket = line.find ("]", openAttrBracket);
if (openAttrBracket != std::string::npos &&
closeAttrBracket != std::string::npos)
{
std::string tags = line.substr (
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
std::vector <std::string> rawTags;
split (mTags, tags, ' ');
std::string attributes = line.substr (
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
std::vector <std::string> pairs;
split (pairs, attributes, ' ');
for (unsigned int i = 0; i < pairs.size (); ++i)
{
std::vector <std::string> pair;
split (pair, pairs[i], ':');
if (pair[1] != "")
mAttributes[pair[0]] = pair[1];
}
mDescription = line.substr (closeAttrBracket + 2, std::string::npos);
}
else
throw std::string ("Missing attribute brackets");
}
else
throw std::string ("Missing tag brackets");
}
else
throw std::string ("Line too short");
}
break;
default:
throw std::string ();
break;
}
}
////////////////////////////////////////////////////////////////////////////////
// If this code is inaccurate, data corruption ensues.
int T::determineVersion (const std::string& line)
{
// Version 1 looks like:
//
// [tags] [attributes] description\n
// X [tags] [attributes] description\n
//
// Scan for the first character being either the bracket or X.
if (line[0] == '[' ||
line[0] == 'X')
return 1;
// Version 2 looks like:
//
// uuid status [tags] [attributes] description\n
//
// Where uuid looks like:
//
// 27755d92-c5e9-4c21-bd8e-c3dd9e6d3cf7
//
// Scan for the hyphens in the uuid, the following space, and a valid status
// character.
if (line[8] == '-' &&
line[13] == '-' &&
line[18] == '-' &&
line[23] == '-' &&
line[36] == ' ' &&
(line[37] == '-' || line[37] == '+' || line[37] == 'X'))
return 2;
// Version 3?
//
// Fortunately, with the hindsight that will come with version 3, the
// identifying characteristics of 1 and 2 may be modified such that if 3 has
// a UUID followed by a status, then there is still a way to differentiate
// between 2 and 3.
//
// The danger is that a version 2 binary reads and misinterprets a version 2
// file. This is why it is a good idea to rely on an explicit version
// declaration rather than chance positioning.
// Zero means 'no idea'.
return 0;
}

80
src/T.h Normal file
View file

@ -0,0 +1,80 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 - 2007, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_T
#define INCLUDED_T
#include <string>
#include <vector>
#include <map>
// Length of longest line.
#define T_LINE_MAX 8192
class T
{
public:
enum status {pending, completed, deleted};
T (); // Default constructor
T (const std::string&); // Initialize by parsing storage format
T (const T&); // Copy constructor
T& operator= (const T&); // Assignment operator
~T (); // Destructor
std::string getUUID () const { return mUUID; }
void setUUID (const std::string& uuid) { mUUID = uuid; }
int getId () const { return mId; }
void setId (int id) { mId = id; }
status getStatus () const { return mStatus; }
void setStatus (status s) { mStatus = s; }
const std::string getDescription () const { return mDescription; }
void setDescription (const std::string& description) { mDescription = description; }
void getSubstitution (std::string&, std::string&) const;
void setSubstitution (const std::string&, const std::string&);
bool hasTag (const std::string&) const;
void getRemoveTags (std::vector<std::string>&); // SPECIAL
void addRemoveTag (const std::string&); // SPECIAL
void getTags (std::vector<std::string>&) const;
void addTag (const std::string&);
void addTags (const std::vector <std::string>&);
void removeTag (const std::string&);
void removeTags ();
void getAttributes (std::map<std::string, std::string>&);
const std::string getAttribute (const std::string&);
void setAttribute (const std::string&, const std::string&);
void setAttributes (const std::map <std::string, std::string>&);
void removeAttribute (const std::string&);
void removeAttributes ();
const std::string compose () const;
const std::string composeCSV ();
void parse (const std::string&);
private:
int determineVersion (const std::string&);
private:
status mStatus;
std::string mUUID;
int mId;
std::string mDescription;
std::vector<std::string> mTags;
std::vector<std::string> mRemoveTags;
std::map<std::string, std::string> mAttributes;
std::string mFrom;
std::string mTo;
};
#endif
////////////////////////////////////////////////////////////////////////////////

467
src/TDB.cpp Normal file
View file

@ -0,0 +1,467 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2007, 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <fstream>
#include <sys/file.h>
#include <unistd.h>
#include "task.h"
#include "TDB.h"
////////////////////////////////////////////////////////////////////////////////
TDB::TDB ()
: mPendingFile ("")
, mCompletedFile ("")
, mLogFile ("")
{
}
////////////////////////////////////////////////////////////////////////////////
TDB::~TDB ()
{
}
////////////////////////////////////////////////////////////////////////////////
void TDB::dataDirectory (const std::string& directory)
{
if (! access (directory.c_str (), F_OK))
{
mPendingFile = directory + "/pending.data";
mCompletedFile = directory + "/completed.data";
mLogFile = directory + "/command.log";
}
else
{
std::string error = "Directory '";
error += directory;
error += "' does not exist, or is not readable and writable.";
throw error;
}
}
////////////////////////////////////////////////////////////////////////////////
// Combine allPendingT with allCompletedT.
// Note: this method is O(N1) + O(N2), where N2 is not bounded.
bool TDB::allT (std::vector <T>& all) const
{
all.clear ();
// Retrieve all the pending records.
std::vector <T> allp;
if (allPendingT (allp))
{
std::vector <T>::iterator i;
for (i = allp.begin (); i != allp.end (); ++i)
all.push_back (*i);
// Retrieve all the completed records.
std::vector <T> allc;
if (allCompletedT (allc))
{
for (i = allc.begin (); i != allc.end (); ++i)
all.push_back (*i);
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
// Only accesses to the pending file result in Tasks that have assigned ids.
bool TDB::pendingT (std::vector <T>& all) const
{
all.clear ();
std::vector <std::string> lines;
if (readLockedFile (mPendingFile, lines))
{
int id = 1;
std::vector <std::string>::iterator it;
for (it = lines.begin (); it != lines.end (); ++it)
{
T t (*it);
t.setId (id++);
if (t.getStatus () == T::pending)
all.push_back (t);
}
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
// Only accesses to the pending file result in Tasks that have assigned ids.
bool TDB::allPendingT (std::vector <T>& all) const
{
all.clear ();
std::vector <std::string> lines;
if (readLockedFile (mPendingFile, lines))
{
int id = 1;
std::vector <std::string>::iterator it;
for (it = lines.begin (); it != lines.end (); ++it)
{
T t (*it);
t.setId (id++);
all.push_back (t);
}
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::completedT (std::vector <T>& all) const
{
all.clear ();
std::vector <std::string> lines;
if (readLockedFile (mCompletedFile, lines))
{
std::vector <std::string>::iterator it;
for (it = lines.begin (); it != lines.end (); ++it)
{
T t (*it);
if (t.getStatus () != T::deleted)
all.push_back (t);
}
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::allCompletedT (std::vector <T>& all) const
{
all.clear ();
std::vector <std::string> lines;
if (readLockedFile (mCompletedFile, lines))
{
std::vector <std::string>::iterator it;
for (it = lines.begin (); it != lines.end (); ++it)
{
T t (*it);
all.push_back (t);
}
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::deleteT (const T& t) const
{
T task (t);
std::vector <T> all;
allPendingT (all);
std::vector <T>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
if (task.getId () == it->getId ())
{
it->setStatus (T::deleted);
char endTime[16];
sprintf (endTime, "%u", (unsigned int) time (NULL));
it->setAttribute ("end", endTime);
return overwritePending (all);
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::completeT (const T& t) const
{
T task (t);
std::vector <T> all;
allPendingT (all);
std::vector <T>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
if (task.getId () == it->getId ())
{
it->setStatus (T::completed);
char endTime[16];
sprintf (endTime, "%u", (unsigned int) time (NULL));
it->setAttribute ("end", endTime);
return overwritePending (all);
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::addT (const T& t) const
{
T task (t);
std::vector <std::string> tags;
task.getTags (tags);
// TODO This logic smells funny.
// +tag or -tag are both considered valid tags to add to a new pending task.
// Generating an error here would not be friendly.
for (unsigned int i = 0; i < tags.size (); ++i)
{
if (tags[i][0] == '-' || tags[i][0] == '+')
{
task.removeTag (tags[i]);
task.addTag (tags[i].substr (1, std::string::npos));
}
}
if (task.getStatus () == T::pending)
return writePending (task);
return writeCompleted (task);
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::modifyT (const T& t) const
{
T modified (t);
std::vector <T> all;
allPendingT (all);
std::vector <T> pending;
std::vector <T>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
{
if (it->getId () == t.getId ())
{
modified.setUUID (it->getUUID ());
pending.push_back (modified);
}
else
pending.push_back (*it);
}
return overwritePending (pending);
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::logRead (std::vector <std::string>& entries) const
{
entries.clear ();
return readLockedFile (mLogFile, entries);
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::logCommand (int argc, char** argv) const
{
// Get time info.
time_t now;
time (&now);
struct tm* t = localtime (&now);
// Generate timestamp.
char timestamp[20];
sprintf (timestamp, "%04d-%02d-%02d %02d:%02d:%02d",
t->tm_year + 1900,
t->tm_mon + 1,
t->tm_mday,
t->tm_hour,
t->tm_min,
t->tm_sec);
std::string command = timestamp;
command += " \"";
for (int i = 0; i < argc; ++i)
command += std::string (i ? " " : "") + argv[i];
command += "\"\n";
if (! access (mLogFile.c_str (), F_OK | W_OK))
{
FILE* out;
if ((out = fopen (mLogFile.c_str (), "a")))
{
#ifdef HAVE_FLOCK
int retry = 0;
while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
delay (0.25);
#endif
fprintf (out, command.c_str ());
fclose (out);
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::lock (FILE* file) const
{
#ifdef HAVE_FLOCK
return flock (fileno (file), LOCK_EX) ? false : true;
#else
return true;
#endif
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::overwritePending (std::vector <T>& all) const
{
// Write a single task to the pending file
FILE* out;
if ((out = fopen (mPendingFile.c_str (), "w")))
{
#ifdef HAVE_FLOCK
int retry = 0;
while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
delay (0.25);
#endif
std::vector <T>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
fprintf (out, it->compose ().c_str ());
fclose (out);
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::writePending (const T& t) const
{
// Write a single task to the pending file
FILE* out;
if ((out = fopen (mPendingFile.c_str (), "a")))
{
#ifdef HAVE_FLOCK
int retry = 0;
while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
delay (0.25);
#endif
fprintf (out, t.compose ().c_str ());
fclose (out);
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::writeCompleted (const T& t) const
{
// Write a single task to the pending file
FILE* out;
if ((out = fopen (mCompletedFile.c_str (), "a")))
{
#ifdef HAVE_FLOCK
int retry = 0;
while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
delay (0.25);
#endif
fprintf (out, t.compose ().c_str ());
fclose (out);
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool TDB::readLockedFile (
const std::string& file,
std::vector <std::string>& contents) const
{
contents.clear ();
if (! access (file.c_str (), F_OK | R_OK))
{
FILE* in;
if ((in = fopen (file.c_str (), "r")))
{
#ifdef HAVE_FLOCK
int retry = 0;
while (flock (fileno (in), LOCK_EX) && ++retry <= 3)
delay (0.25);
#endif
char line[T_LINE_MAX];
while (fgets (line, T_LINE_MAX, in))
{
int length = ::strlen (line);
if (length > 1)
{
line[length - 1] = '\0'; // Kill \n
contents.push_back (line);
}
}
fclose (in);
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
int TDB::gc () const
{
int count = 0;
// Read everything from the pending file.
std::vector <T> all;
allPendingT (all);
// A list of the truly pending tasks.
std::vector <T> pending;
std::vector<T>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
{
// Some tasks stay in the pending file.
if (it->getStatus () == T::pending)
pending.push_back (*it);
// Others are transferred to the completed file.
else
{
writeCompleted (*it);
++count;
}
}
// Dump all clean tasks into pending.
overwritePending (pending);
return count;
}
////////////////////////////////////////////////////////////////////////////////

47
src/TDB.h Normal file
View file

@ -0,0 +1,47 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2007, 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_TDB
#define INCLUDED_TDB
#include <vector>
#include <string>
#include "T.h"
class TDB
{
public:
TDB ();
~TDB ();
void dataDirectory (const std::string&);
bool allT (std::vector <T>&) const;
bool pendingT (std::vector <T>&) const;
bool allPendingT (std::vector <T>&) const;
bool completedT (std::vector <T>&) const;
bool allCompletedT (std::vector <T>&) const;
bool deleteT (const T&) const;
bool completeT (const T&) const;
bool addT (const T&) const;
bool modifyT (const T&) const;
bool logRead (std::vector <std::string>&) const;
bool logCommand (int, char**) const;
int gc () const;
private:
bool lock (FILE*) const;
bool overwritePending (std::vector <T>&) const;
bool writePending (const T&) const;
bool writeCompleted (const T&) const;
bool readLockedFile (const std::string&, std::vector <std::string>&) const;
private:
std::string mPendingFile;
std::string mCompletedFile;
std::string mLogFile;
};
#endif
////////////////////////////////////////////////////////////////////////////////

1064
src/Table.cpp Normal file

File diff suppressed because it is too large Load diff

115
src/Table.h Normal file
View file

@ -0,0 +1,115 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 - 2008, Paul Beckingham.
// All rights reserved.
//
// TODO Implement height
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_TABLE
#define INCLUDED_TABLE
#include <map>
#include <vector>
#include <string>
#include "color.h"
class Table
{
public:
enum just {left, center, right};
enum order {ascendingNumeric, ascendingCharacter, ascendingPriority,
ascendingDate, descendingNumeric, descendingCharacter,
descendingPriority, descendingDate};
enum sizing {minimum = -1, flexible = 0};
Table ();
virtual ~Table ();
void setTableColor (Text::color, Text::color);
void setTableFg (Text::color);
void setTableBg (Text::color);
void setTablePadding (int);
void setTableIntraPadding (int);
void setTableWidth (int);
int addColumn (const std::string&);
void setColumnColor (int, Text::color, Text::color);
void setColumnFg (int, Text::color);
void setColumnBg (int, Text::color);
void setColumnUnderline (int);
void setColumnPadding (int, int);
void setColumnWidth (int, int);
void setColumnWidth (int, sizing);
void setColumnJustification (int, just);
void setColumnCommify (int);
void sortOn (int, order);
int addRow ();
void setRowColor (int, Text::color, Text::color);
void setRowFg (int, Text::color);
void setRowBg (int, Text::color);
void addCell (int, int, const std::string&);
void addCell (int, int, char);
void addCell (int, int, int);
void addCell (int, int, float);
void addCell (int, int, double);
void setCellColor (int, int, Text::color, Text::color);
void setCellFg (int, int, Text::color);
void setCellBg (int, int, Text::color);
void suppressWS ();
int rowCount ();
int columnCount ();
const std::string render ();
private:
std::string getCell (int, int);
Text::color getFg (int, int);
Text::color getHeaderFg (int);
Text::color getBg (int, int);
Text::color getHeaderBg (int);
Text::attr getHeaderUnderline (int);
int getPadding (int);
int getIntraPadding ();
void calculateColumnWidths ();
just getJustification (int, int);
just getHeaderJustification (int);
const std::string formatHeader (int, int, int);
const std::string formatCell (int, int, int, int);
void formatCell (int, int, int, int, std::vector <std::string>&, std::string&);
void optimize (std::string&);
void sort (std::vector <int>&);
void clean (std::string&);
private:
std::vector <std::string> mColumns;
int mRows;
int mIntraPadding;
std::map <std::string, Text::color> mFg;
std::map <std::string, Text::color> mBg;
std::map <std::string, Text::attr> mUnderline;
// Padding...
int mTablePadding;
std::vector <int> mColumnPadding;
// Width...
int mTableWidth;
std::vector <int> mSpecifiedWidth;
std::vector <int> mMaxDataWidth;
std::vector <int> mCalculatedWidth;
std::map <std::string, just> mJustification;
std::map <int, bool> mCommify;
std::map <std::string, std::string> mData;
std::vector <int> mSortColumns;
std::map <int, order> mSortOrder;
// Misc...
bool mSuppressWS;
};
#endif
////////////////////////////////////////////////////////////////////////////////

64
src/color.cpp Normal file
View file

@ -0,0 +1,64 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#include <string>
#include "color.h"
////////////////////////////////////////////////////////////////////////////////
std::string Text::colorName (Text::color c)
{
switch (c)
{
case black: return "black";
case red: return "red";
case green: return "green";
case yellow: return "yellow";
case blue: return "blue";
case magenta: return "magenta";
case cyan: return "cyan";
case white: return "white";
case nocolor: return "";
}
return "";
}
////////////////////////////////////////////////////////////////////////////////
Text::color Text::colorCode (const std::string& c)
{
if (c == "black") return black;
if (c == "red") return red;
if (c == "green") return green;
if (c == "yellow") return yellow;
if (c == "blue") return blue;
if (c == "magenta") return magenta;
if (c == "cyan") return cyan;
if (c == "white") return white;
return nocolor;
}
////////////////////////////////////////////////////////////////////////////////
std::string Text::attrName (Text::attr a)
{
switch (a)
{
case underline: return "underline";
case normal: return "";
}
return "";
}
////////////////////////////////////////////////////////////////////////////////
Text::attr Text::attrCode (const std::string& a)
{
if (a == "underline") return underline;
return normal;
}
////////////////////////////////////////////////////////////////////////////////

23
src/color.h Normal file
View file

@ -0,0 +1,23 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2008, Paul Beckingham.
// All rights reserved.
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_COLOR
#define INCLUDED_COLOR
namespace Text
{
enum color {nocolor = 0, black, red, green, yellow, blue, magenta, cyan, white};
enum attr {normal = 0, underline};
std::string colorName (Text::color);
Text::color colorCode (const std::string&);
std::string attrName (Text::attr);
Text::attr attrCode (const std::string&);
}
#endif
////////////////////////////////////////////////////////////////////////////////

49
src/library.h Normal file
View file

@ -0,0 +1,49 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2004 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_LIBRARY
#define INCLUDED_LIBRARY
#include <string>
#include <vector>
#include <sys/types.h>
#include "stlmacros.h"
#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif
// text.cpp
void wrapText (std::vector <std::string>&, const std::string&, const int);
std::string trimLeft (const std::string& in, const std::string& t = " ");
std::string trimRight (const std::string& in, const std::string& t = " ");
std::string trim (const std::string& in, const std::string& t = " ");
std::wstring trimLeft (const std::wstring& in, const std::wstring& t = L" "); // UNICODE safe
std::wstring trimRight (const std::wstring& in, const std::wstring& t = L" "); // UNICODE safe
std::wstring trim (const std::wstring& in, const std::wstring& t = L" "); // UNICODE safe
void extractParagraphs (const std::string&, std::vector<std::string>&);
void extractLine (std::string&, std::string&, int);
void split (std::vector<std::string>&, const std::string&, const char);
void split (std::vector<std::string>&, const std::string&, const std::string&);
void join (std::string&, const std::string&, const std::vector<std::string>&);
std::string commify (const std::string&);
std::string lowerCase (const std::string&);
// misc.cpp
void delay (float);
// list.cpp
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
// units.cpp
void formatTimeDeltaDays (std::string&, time_t);
std::string formatSeconds (time_t);
// uuid.cpp
const std::string uuid ();
#endif
////////////////////////////////////////////////////////////////////////////////

329
src/parse.cpp Normal file
View file

@ -0,0 +1,329 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include "Date.h"
#include "task.h"
#include "T.h"
////////////////////////////////////////////////////////////////////////////////
static char* colors[] =
{
"black",
"blue",
"red",
"green",
"magenta",
"cyan",
"yellow",
"white",
"",
};
static char* attributes[] =
{
"project",
"priority",
"fg",
"bg",
"due",
"entry",
"start",
"end",
"",
};
static char* commands[] =
{
"active",
"add",
"calendar",
"completed",
"delete",
"done",
"export",
"history",
"info",
"list",
"long",
"ls",
"next",
"overdue",
"projects",
"start",
"stats",
"summary",
"tags",
"usage",
"version",
"",
};
void guess (const std::string& type, char** list, std::string& candidate)
{
std::vector <std::string> options;
for (int i = 0; list[i][0]; ++i)
options.push_back (list[i]);
std::vector <std::string> matches;
autoComplete (candidate, options, matches);
if (1 == matches.size ())
candidate = matches[0];
else if (0 == matches.size ())
throw std::string ("Unrecognized ") + type + " '" + candidate + "'";
else
{
std::string error = "Ambiguous ";
error += type;
error += " '";
error += candidate;
error += "' - could be either of ";
for (unsigned int i = 0; i < matches.size (); ++i)
{
if (i)
error += ", ";
error += matches[i];
}
throw error;
}
}
////////////////////////////////////////////////////////////////////////////////
static bool isCommand (const std::string& candidate)
{
std::vector <std::string> options;
for (int i = 0; commands[i][0]; ++i)
options.push_back (commands[i]);
std::vector <std::string> matches;
autoComplete (candidate, options, matches);
if (0 == matches.size ())
return false;
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool validDate (std::string& date)
{
unsigned int firstSlash = date.find ("/");
unsigned int secondSlash = date.find ("/", firstSlash + 1);
if (firstSlash != std::string::npos &&
secondSlash != std::string::npos)
{
int m = ::atoi (date.substr (0, firstSlash ).c_str ());
int d = ::atoi (date.substr (firstSlash + 1, secondSlash - firstSlash).c_str ());
int y = ::atoi (date.substr (secondSlash + 1, std::string::npos ).c_str ());
if (!Date::valid (m, d, y))
throw std::string ("\"") + date + "\" is not a valid date.";
// Convert to epoch form.
Date dt (m, d, y);
time_t t;
dt.toEpoch (t);
char converted[12];
sprintf (converted, "%u", (unsigned int) t);
date = converted;
}
else
throw std::string ("Badly formed date - use the MM/DD/YYYY format");
return true;
}
////////////////////////////////////////////////////////////////////////////////
static bool validPriority (std::string& input)
{
if (input != "H" &&
input != "M" &&
input != "L" &&
input != "")
throw std::string ("\"") +
input +
"\" is not a valid priority. Use H, M, L or leave blank.";
return true;
}
////////////////////////////////////////////////////////////////////////////////
static bool validAttribute (std::string& name, std::string& value)
{
guess ("attribute", attributes, name);
if ((name == "fg" || name == "bg") && value != "")
guess ("color", colors, value);
else if (name == "due" && value != "")
validDate (value);
else if (name == "priority")
{
for (std::string::iterator i = value.begin (); i != value.end (); ++i)
*i = ::toupper (*i);
return validPriority (value);
}
else if (name == "entry" ||
name == "start" ||
name == "end")
throw std::string ("\"") +
name +
"\" is not an attribute you may modify directly.";
return true;
}
////////////////////////////////////////////////////////////////////////////////
static bool validId (const std::string& input)
{
for (unsigned int i = 0; i < input.length (); ++i)
if (!::isdigit (input[i]))
return false;
return true;
}
////////////////////////////////////////////////////////////////////////////////
static bool validTag (std::string& input)
{
if ((input[0] == '-' || input[0] == '+') &&
input.length () > 1)
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
static bool validDescription (const std::string& input)
{
if (input.length () > 0)
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
static bool validCommand (std::string& input)
{
guess ("command", commands, input);
return true;
}
////////////////////////////////////////////////////////////////////////////////
static bool validSubstitution (
std::string& input,
std::string& from,
std::string& to)
{
unsigned int first = input.find ('/');
if (first != std::string::npos)
{
unsigned int second = input.find ('/', first + 1);
if (second != std::string::npos)
{
unsigned int third = input.find ('/', second + 1);
if (third != std::string::npos)
{
if (first == 0 &&
first < second &&
second < third &&
third == input.length () - 1)
{
from = input.substr (first + 1, second - first - 1);
to = input.substr (second + 1, third - second - 1);
return true;
}
}
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
// Token Distinguishing characteristic
// ------- -----------------------------
// command first positional
// id \d+
// description default, accumulate
// substitution /\w+/\w*/
// tags [-+]\w+
// attributes \w+:.+
//
void parse (
std::vector <std::string>& args,
std::string& command,
T& task)
{
command = "";
std::string descCandidate = "";
for (unsigned int i = 0; i < args.size (); ++i)
{
std::string arg (args[i]);
unsigned int colon; // Pointer to colon in argument.
std::string from;
std::string to;
// An id is the first argument found that contains all digits.
if (command != "add" && // "add" doesn't require an ID
task.getId () == 0 &&
validId (arg))
task.setId (::atoi (arg.c_str ()));
// Tags begin with + or - and contain arbitrary text.
else if (validTag (arg))
{
if (arg[0] == '+')
task.addTag (arg.substr (1, std::string::npos));
else if (arg[0] == '-')
task.addRemoveTag (arg.substr (1, std::string::npos));
}
// Attributes contain a constant string followed by a colon, followed by a
// value.
else if ((colon = arg.find (":")) != std::string::npos)
{
std::string name = arg.substr (0, colon);
std::string value = arg.substr (colon + 1, std::string::npos);
if (validAttribute (name, value))
task.setAttribute (name, value);
}
// Substitution of description text.
else if (validSubstitution (arg, from, to))
{
task.setSubstitution (from, to);
}
// Command.
else if (command == "")
{
if (!isCommand (arg))
descCandidate += std::string (arg) + " ";
else if (validCommand (arg))
command = arg;
}
// Anything else is just considered description.
else
descCandidate += std::string (arg) + " ";
}
if (validDescription (descCandidate))
task.setDescription (descCandidate);
}
////////////////////////////////////////////////////////////////////////////////

182
src/rules.cpp Normal file
View file

@ -0,0 +1,182 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include "Config.h"
#include "Table.h"
#include "Date.h"
#include "T.h"
#include "task.h"
static std::map <std::string, Text::color> gsFg;
static std::map <std::string, Text::color> gsBg;
////////////////////////////////////////////////////////////////////////////////
// There are three supported variants:
// 1) "fg"
// 2) "on bg"
// 3) "fg on bg"
static void parseColorRule (
const std::string& rule,
Text::color& fg,
Text::color& bg)
{
fg = Text::nocolor;
bg = Text::nocolor;
bool error = false;
std::vector <std::string> words;
split (words, rule, ' ');
switch (words.size ())
{
case 1: // "fg" - no spaces.
fg = Text::colorCode (words[0]);
break;
case 2: // "on bg" - one space, "on" before.
if (words[0] == "on")
bg = Text::colorCode (words[1]);
else
error = true;
break;
case 3: // "fg on bg" - two spaces, "on" between them.
if (words[1] == "on")
{
fg = Text::colorCode (words[0]);
bg = Text::colorCode (words[2]);
}
else
error = true;
break;
case 0:
default:
error = true;
break;
}
if (error)
std::cout << "Malformed color rule '" << rule << "'" << std::endl;
}
////////////////////////////////////////////////////////////////////////////////
void initializeColorRules (Config& conf)
{
std::vector <std::string> ruleNames;
conf.all (ruleNames);
foreach (it, ruleNames)
{
if (it->substr (0, 6) == "color.")
{
Text::color fg;
Text::color bg;
parseColorRule (conf.get (*it), fg, bg);
gsFg[*it] = fg;
gsBg[*it] = bg;
}
}
}
////////////////////////////////////////////////////////////////////////////////
void autoColorize (T& task, Text::color& fg, Text::color& bg)
{
fg = Text::nocolor;
bg = Text::nocolor;
// Colorization of the tagged.
if (gsFg["color.tagged"] != Text::nocolor ||
gsBg["color.tagged"] != Text::nocolor)
{
std::vector <std::string> tags;
task.getTags (tags);
if (tags.size ())
{
fg = gsFg["color.tagged"];
bg = gsBg["color.tagged"];
}
}
// Colorization of the low priority.
if (gsFg["color.pri.L"] != Text::nocolor ||
gsBg["color.pri.L"] != Text::nocolor)
{
if (task.getAttribute ("priority") == "L")
{
fg = gsFg["color.pri.L"];
bg = gsBg["color.pri.L"];
}
}
// Colorization of the medium priority.
if (gsFg["color.pri.M"] != Text::nocolor ||
gsBg["color.pri.M"] != Text::nocolor)
{
if (task.getAttribute ("priority") == "M")
{
fg = gsFg["color.pri.M"];
bg = gsBg["color.pri.M"];
}
}
// Colorization of the high priority.
if (gsFg["color.pri.H"] != Text::nocolor ||
gsBg["color.pri.H"] != Text::nocolor)
{
if (task.getAttribute ("priority") == "H")
{
fg = gsFg["color.pri.H"];
bg = gsBg["color.pri.H"];
}
}
// Colorization of the priority-less.
if (gsFg["color.pri.none"] != Text::nocolor ||
gsBg["color.pri.none"] != Text::nocolor)
{
if (task.getAttribute ("priority") == "")
{
fg = gsFg["color.pri.none"];
bg = gsBg["color.pri.none"];
}
}
// Colorization of the active.
if (gsFg["color.active"] != Text::nocolor ||
gsBg["color.active"] != Text::nocolor)
{
if (task.getAttribute ("start") != "")
{
fg = gsFg["color.active"];
bg = gsBg["color.active"];
}
}
// Colorization of the due and overdue.
std::string due = task.getAttribute ("due");
if (due != "")
{
Date dueDate (::atoi (due.c_str ()));
Date now;
Date then (now + 7 * 86400);
// Overdue
if (dueDate < now)
{
fg = gsFg["color.overdue"];
bg = gsBg["color.overdue"];
}
// Imminent
else if (dueDate < then)
{
fg = gsFg["color.due"];
bg = gsBg["color.due"];
}
}
}
////////////////////////////////////////////////////////////////////////////////

18
src/stlmacros.h Normal file
View file

@ -0,0 +1,18 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_STLMACROS
#define INCLUDED_STLMACROS
#define foreach(i, c) \
for (typeof (c) *foreach_p = & (c); \
foreach_p; \
foreach_p = 0) \
for (typeof (foreach_p->begin()) i = foreach_p->begin(); \
i != foreach_p->end(); \
++i)
#endif
////////////////////////////////////////////////////////////////////////////////

2682
src/task.cpp Normal file

File diff suppressed because it is too large Load diff

79
src/task.h Normal file
View file

@ -0,0 +1,79 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#include <string>
#include <vector>
#include <map>
#include <sys/types.h>
#include "Config.h"
#include "Table.h"
#include "color.h"
#include "TDB.h"
#include "T.h"
#include "stlmacros.h"
#include "../auto.h"
#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif
// parse.cpp
void parse (std::vector <std::string>&, std::string&, T&);
bool validDate (std::string&);
// task.cpp
void handleAdd (const TDB&, T&, Config&);
void handleProjects (const TDB&, T&, Config&);
void handleTags (const TDB&, T&, Config&);
void handleList (const TDB&, T&, Config&);
void handleInfo (const TDB&, T&, Config&);
void handleLongList (const TDB&, T&, Config&);
void handleSmallList (const TDB&, T&, Config&);
void handleCompleted (const TDB&, T&, Config&);
void handleReportSummary (const TDB&, T&, Config&);
void handleReportNext (const TDB&, T&, Config&);
void handleReportHistory (const TDB&, T&, Config&);
void handleReportUsage (const TDB&, T&, Config&);
void handleReportCalendar (const TDB&, T&, Config&);
void handleReportActive (const TDB&, T&, Config&);
void handleReportOverdue (const TDB&, T&, Config&);
void handleReportStats (const TDB&, T&, Config&);
void handleVersion (Config&);
void handleExport (const TDB&, T&, Config&);
void handleDelete (const TDB&, T&, Config&);
void handleStart (const TDB&, T&, Config&);
void handleDone (const TDB&, T&, Config&);
void handleModify (const TDB&, T&, Config&);
void gatherNextTasks (const TDB&, T&, Config&, std::vector <T>&, std::vector <int>&);
void nag (const TDB&, T&, Config&);
// util.cpp
bool confirm (const std::string&);
void wrapText (std::vector <std::string>&, const std::string&, const int);
std::string trimLeft (const std::string& in, const std::string& t = " ");
std::string trimRight (const std::string& in, const std::string& t = " ");
std::string trim (const std::string& in, const std::string& t = " ");
std::wstring trimLeft (const std::wstring& in, const std::wstring& t = L" "); // UNICODE safe
std::wstring trimRight (const std::wstring& in, const std::wstring& t = L" "); // UNICODE safe
std::wstring trim (const std::wstring& in, const std::wstring& t = L" "); // UNICODE safe
void extractParagraphs (const std::string&, std::vector<std::string>&);
void extractLine (std::string&, std::string&, int);
void split (std::vector<std::string>&, const std::string&, const char);
void split (std::vector<std::string>&, const std::string&, const std::string&);
void join (std::string&, const std::string&, const std::vector<std::string>&);
std::string commify (const std::string&);
std::string lowerCase (const std::string&);
void delay (float);
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
void formatTimeDeltaDays (std::string&, time_t);
std::string formatSeconds (time_t);
const std::string uuid ();
// rules.cpp
void initializeColorRules (Config&);
void autoColorize (T&, Text::color&, Text::color&);
////////////////////////////////////////////////////////////////////////////////

5
src/tests/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
t.t
tdb.t
pending.data
completed.data

24
src/tests/Makefile Normal file
View file

@ -0,0 +1,24 @@
PROJECT = t.t tdb.t
CFLAGS = -I.. -I../../../library/include -Wall -pedantic -ggdb3 -fno-rtti
LFLAGS = -L/usr/local/lib -L../../../library/lib -lcompany -lpcre -lncurses -lcurl
all: $(PROJECT)
install: $(PROJECT)
@echo unimplemented
test: $(PROJECT)
@echo unimplemented
clean:
-rm *.o $(PROJECT)
.cpp.o:
g++ -c $(CFLAGS) $<
t.t: t.t.o ../T.o ../parse.o ../../../library/lib/libcompany.a
g++ t.t.o ../T.o ../parse.o $(LFLAGS) -o t.t
tdb.t: tdb.t.o ../TDB.o ../T.o ../parse.o ../../../library/lib/libcompany.a
g++ tdb.t.o ../TDB.o ../T.o ../parse.o $(LFLAGS) -o tdb.t

37
src/tests/t.t.cpp Normal file
View file

@ -0,0 +1,37 @@
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
#include <T.h>
#include <library.h>
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
plan (4);
T t;
std::string s = t.compose ();
is ((int)s.length (), 46, "T::T (); T::compose ()");
diag (s);
t.setStatus (T::completed);
s = t.compose ();
is (s[37], '+', "T::setStatus (completed)");
diag (s);
t.setStatus (T::deleted);
s = t.compose ();
is (s[37], 'X', "T::setStatus (deleted)");
diag (s);
// Round trip test.
std::string sample = "00000000-0000-0000-0000-000000000000 - [] [] Sample";
T t2;
t2.parse (sample);
sample += "\n";
is (t2.compose (), sample, "T::parse -> T::compose round trip");
return 0;
}
////////////////////////////////////////////////////////////////////////////////

127
src/tests/tdb.t.cpp Normal file
View file

@ -0,0 +1,127 @@
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <unistd.h>
#include <TDB.h>
#include <library.h>
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
plan (43);
try
{
// Remove any residual test file.
unlink ("./pending.data");
unlink ("./completed.data");
// Try reading an empty database.
TDB tdb;
tdb.dataDirectory (".");
std::vector <T> all;
ok (!tdb.pendingT (all), "TDB::pendingT read empty db");
is ((int) all.size (), 0, "empty db");
ok (!tdb.allPendingT (all), "TDB::allPendingT read empty db");
is ((int) all.size (), 0, "empty db");
ok (!tdb.completedT (all), "TDB::completedT read empty db");
is ((int) all.size (), 0, "empty db");
ok (!tdb.allCompletedT (all), "TDB::allCompletedT read empty db");
is ((int) all.size (), 0, "empty db");
// Add a new task.
T t1;
t1.setId (1);
t1.setStatus (T::pending);
t1.setAttribute ("project", "p1");
t1.setDescription ("task 1");
diag (t1.compose ());
ok (tdb.addT (t1), "TDB::addT t1");
// Verify as above.
ok (tdb.pendingT (all), "TDB::pendingT read db");
is ((int) all.size (), 1, "empty db");
ok (tdb.allPendingT (all), "TDB::allPendingT read db");
is ((int) all.size (), 1, "empty db");
ok (!tdb.completedT (all), "TDB::completedT read empty db");
is ((int) all.size (), 0, "empty db");
ok (!tdb.allCompletedT (all), "TDB::allCompletedT read empty db");
is ((int) all.size (), 0, "empty db");
// TODO Modify task.
fail ("modify");
fail ("verify");
// Complete task.
ok (tdb.completeT (t1), "TDB::completeT t1");;
ok (!tdb.pendingT (all), "TDB::pendingT read db");
is ((int) all.size (), 0, "empty db");
ok (tdb.allPendingT (all), "TDB::allPendingT read db");
is ((int) all.size (), 1, "empty db");
ok (!tdb.completedT (all), "TDB::completedT read empty db");
is ((int) all.size (), 0, "empty db");
ok (!tdb.allCompletedT (all), "TDB::allCompletedT read empty db");
is ((int) all.size (), 0, "empty db");
is (tdb.gc (), 1, "TDB::gc");
ok (!tdb.pendingT (all), "TDB::pendingT read empty db");
is ((int) all.size (), 0, "empty db");
ok (!tdb.allPendingT (all), "TDB::allPendingT read empty db");
is ((int) all.size (), 0, "empty db");
ok (tdb.completedT (all), "TDB::completedT read db");
is ((int) all.size (), 1, "empty db");
ok (tdb.allCompletedT (all), "TDB::allCompletedT read db");
is ((int) all.size (), 1, "empty db");
// Add a new task.
T t2;
t2.setId (2);
t2.setAttribute ("project", "p2");
t2.setDescription ("task 2");
diag (t2.compose ());
ok (tdb.addT (t2), "TDB::addT t2");
fail ("verify");
// Delete task.
ok (tdb.deleteT (t2), "TDB::deleteT t2");
fail ("verify");
// GC the files.
is (tdb.gc (), 1, "1 <- TDB::gc");
// Read log file.
std::vector <std::string> entries;
tdb.logRead (entries);
std::vector <std::string>::iterator it;
for (it = entries.begin (); it != entries.end (); ++it)
diag (*it);
// TODO Verify contents of above transactions.
fail ("verify");
}
catch (std::string& error)
{
diag (error);
return -1;
}
catch (...)
{
diag ("Unknown error.");
return -2;
}
/*
unlink ("./pending.data");
unlink ("./completed.data");
*/
return 0;
}
////////////////////////////////////////////////////////////////////////////////

277
src/text.cpp Normal file
View file

@ -0,0 +1,277 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2004 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <vector>
#include <string>
#include "task.h"
///////////////////////////////////////////////////////////////////////////////
void wrapText (
std::vector <std::string>& lines,
const std::string& text,
const int width)
{
std::string copy = text;
std::string line;
while (copy.length ())
{
extractLine (copy, line, width);
lines.push_back (line);
}
}
////////////////////////////////////////////////////////////////////////////////
void split (std::vector<std::string>& results, const std::string& input, const char delimiter)
{
std::string temp = input;
std::string::size_type i;
while ((i = temp.find (delimiter)) != std::string::npos)
{
std::string token = temp.substr (0, i);
results.push_back (token);
temp.erase (0, i + 1);
}
if (temp.length ()) results.push_back (temp);
}
////////////////////////////////////////////////////////////////////////////////
void split (std::vector<std::string>& results, const std::string& input, const std::string& delimiter)
{
std::string temp = input;
std::string::size_type i;
while ((i = temp.find (delimiter)) != std::string::npos)
{
std::string token = temp.substr (0, i);
results.push_back (token);
temp.erase (0, i + delimiter.length ());
}
if (temp.length ()) results.push_back (temp);
}
////////////////////////////////////////////////////////////////////////////////
void join (
std::string& result,
const std::string& separator,
const std::vector<std::string>& items)
{
result = "";
unsigned int size = items.size ();
for (unsigned int i = 0; i < size; ++i)
{
result += items[i];
if (i < size - 1)
result += separator;
}
}
////////////////////////////////////////////////////////////////////////////////
void extractParagraphs (const std::string& input, std::vector<std::string>& output)
{
std::string copy = input;
while (1)
{
unsigned int so = copy.find ("<p>");
unsigned int eo = copy.find ("</p>");
if (so == std::string::npos && eo == std::string::npos)
break;
std::string extract = trim (copy.substr (so + 3, eo - so - 3));
copy = copy.substr (eo + 4, std::string::npos);
output.push_back (extract);
}
// There were no paragraphs.
if (!output.size ())
output.push_back (input);
}
////////////////////////////////////////////////////////////////////////////////
std::string trimLeft (const std::string& in, const std::string& t /*= " "*/)
{
std::string out = in;
return out.erase (0, in.find_first_not_of (t));
}
// UNICODE safe
std::wstring trimLeft (const std::wstring& in, const std::wstring& t /*= L" "*/)
{
std::wstring out = in;
return out.erase (0, in.find_first_not_of (t));
}
////////////////////////////////////////////////////////////////////////////////
std::string trimRight (const std::string& in, const std::string& t /*= " "*/)
{
std::string out = in;
return out.erase (out.find_last_not_of (t) + 1);
}
// UNICODE safe
std::wstring trimRight (const std::wstring& in, const std::wstring& t /*= L" "*/)
{
std::wstring out = in;
return out.erase (out.find_last_not_of (t) + 1);
}
////////////////////////////////////////////////////////////////////////////////
std::string trim (const std::string& in, const std::string& t /*= " "*/)
{
std::string out = in;
return trimLeft (trimRight (out, t), t);
}
// UNICODE safe
std::wstring trim (const std::wstring& in, const std::wstring& t /*= L" "*/)
{
std::wstring out = in;
return trimLeft (trimRight (out, t), t);
}
////////////////////////////////////////////////////////////////////////////////
// Remove enclosing balanced quotes. Assumes trimmed text.
void unquoteText (std::string& text)
{
char quote = text[0];
if (quote == '\'' || quote == '"')
if (text[text.length () - 1] == quote)
text = text.substr (1, text.length () - 3);
}
////////////////////////////////////////////////////////////////////////////////
void extractLine (std::string& text, std::string& line, int length)
{
unsigned int eol = text.find ("\n");
// Special case: found \n in first length characters.
if (eol != std::string::npos && eol < (unsigned) length)
{
line = text.substr (0, eol); // strip \n
text = text.substr (eol + 1, std::string::npos);
return;
}
// Special case: no \n, and less than length characters total.
// special case: text.find ("\n") == std::string::npos && text.length () < length
if (eol == std::string::npos && text.length () <= (unsigned) length)
{
line = text;
text = "";
return;
}
// Safe to ASSERT text.length () > length
// Look for the last space prior to length
eol = length;
while (eol && text[eol] != ' ' && text[eol] != '\n')
--eol;
// If a space was found, break there.
if (eol)
{
line = text.substr (0, eol);
text = text.substr (eol + 1, std::string::npos);
}
// If no space was found, hyphenate.
else
{
line = text.substr (0, length - 1) + "-";
text = text.substr (length - 1, std::string::npos);
}
}
////////////////////////////////////////////////////////////////////////////////
std::string commify (const std::string& data)
{
// First scan for decimal point and end of digits.
int decimalPoint = -1;
int end = -1;
int i;
for (int i = 0; i < (int) data.length (); ++i)
{
if (::isdigit (data[i]))
end = i;
if (data[i] == '.')
decimalPoint = i;
}
std::string result;
if (decimalPoint != -1)
{
// In reverse order, transfer all digits up to, and including the decimal
// point.
for (i = (int) data.length () - 1; i >= decimalPoint; --i)
result += data[i];
int consecutiveDigits = 0;
for (; i >= 0; --i)
{
if (::isdigit (data[i]))
{
result += data[i];
if (++consecutiveDigits == 3 && i && ::isdigit (data[i - 1]))
{
result += ',';
consecutiveDigits = 0;
}
}
else
result += data[i];
}
}
else
{
// In reverse order, transfer all digits up to, but not including the last
// digit.
for (i = (int) data.length () - 1; i > end; --i)
result += data[i];
int consecutiveDigits = 0;
for (; i >= 0; --i)
{
if (::isdigit (data[i]))
{
result += data[i];
if (++consecutiveDigits == 3 && i && ::isdigit (data[i - 1]))
{
result += ',';
consecutiveDigits = 0;
}
}
else
result += data[i];
}
}
// reverse result into data.
std::string done;
for (int i = (int) result.length () - 1; i >= 0; --i)
done += result[i];
return done;
}
////////////////////////////////////////////////////////////////////////////////
std::string lowerCase (const std::string& input)
{
std::string output = input;
for (int i = 0; i < (int) input.length (); ++i)
if (::isupper (input[i]))
output[i] = ::tolower (input[i]);
return output;
}
////////////////////////////////////////////////////////////////////////////////

212
src/util.cpp Normal file
View file

@ -0,0 +1,212 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 - 2008, Paul Beckingham. All rights reserved.
//
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include "Table.h"
#include "task.h"
#include "../auto.h"
////////////////////////////////////////////////////////////////////////////////
bool confirm (const std::string& question)
{
std::cout << question << " (y/n) ";
std::string answer;
std::cin >> answer;
answer = trim (answer);
if (answer == "y" || answer == "Y")
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
void delay (float f)
{
struct timeval t;
t.tv_sec = (int) f;
t.tv_usec = int ((f - (int)f) * 1000000);
select (0, NULL, NULL, NULL, &t);
}
////////////////////////////////////////////////////////////////////////////////
// Convert a quantity in seconds to a more readable format.
// Long version:
// 0-59 S seconds
// 60-3599 M minutes, S seconds
// 3600-86399 H hours, M minutes, S seconds
// 86400- D days, H hours, M minutes, S seconds
// Short version:
// 0-59 S seconds
// 60-3599 M minutes, S seconds
// 3600-86399 H hours, M minutes, S seconds
//
void formatTimeDeltaDays (std::string& output, time_t delta)
{
char formatted[24];
float days = (float) delta / 86400.0;
if (days > 365)
sprintf (formatted, "%.1f yrs", (days / 365.2422));
else if (days > 84)
sprintf (formatted, "%1d mths", (int) (days / 30.6));
else if (days > 13)
sprintf (formatted, "%d wks", (int) (days / 7.0));
else if (days > 5.0)
sprintf (formatted, "%d days", (int) days);
else if (days > 1.0)
sprintf (formatted, "%.1f days", days);
else if (days * 24 > 1.0)
sprintf (formatted, "%d hrs", (int) (days * 24.0));
else if (days * 24 * 60 > 1)
sprintf (formatted, "%d mins", (int) (days * 24 * 60));
else if (days * 24 * 60 * 60 > 1)
sprintf (formatted, "%d secs", (int) (days * 24 * 60 * 60));
else
strcpy (formatted, "-");
output = formatted;
}
////////////////////////////////////////////////////////////////////////////////
std::string formatSeconds (time_t delta)
{
char formatted[24];
float days = (float) delta / 86400.0;
if (days > 365)
sprintf (formatted, "%.1f yrs", (days / 365.2422));
else if (days > 84)
sprintf (formatted, "%1d mths", (int) (days / 30.6));
else if (days > 13)
sprintf (formatted, "%d wks", (int) (days / 7.0));
else if (days > 5.0)
sprintf (formatted, "%d days", (int) days);
else if (days > 1.0)
sprintf (formatted, "%.1f days", days);
else if (days * 24 > 1.0)
sprintf (formatted, "%d hrs", (int) (days * 24.0));
else if (days * 24 * 60 > 1)
sprintf (formatted, "%d mins", (int) (days * 24 * 60));
else if (days * 24 * 60 * 60 > 1)
sprintf (formatted, "%d secs", (int) (days * 24 * 60 * 60));
else
strcpy (formatted, "-");
return std::string (formatted);
}
////////////////////////////////////////////////////////////////////////////////
int autoComplete (
const std::string& partial,
const std::vector<std::string>& list,
std::vector<std::string>& matches)
{
matches.erase (matches.begin (), matches.end ());
// Handle trivial case.
unsigned int length = partial.length ();
if (length)
{
for (unsigned int i = 0; i < list.size (); ++i)
{
// Special case where there is an exact match.
if (partial == list[i])
{
matches.erase (matches.begin (), matches.end ());
matches.push_back (list[i]);
return 1;
}
// Maintain a list of partial matches.
if (length <= list[i].length () &&
! strncmp (partial.c_str (), list[i].c_str (), length))
matches.push_back (list[i]);
}
}
return matches.size ();
}
////////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_UUID
#include <uuid/uuid.h>
const std::string uuid ()
{
uuid_t id;
uuid_generate (id);
char buffer[100];
uuid_unparse_lower (id, buffer);
return std::string (buffer);
}
////////////////////////////////////////////////////////////////////////////////
#else
#warning "Using custom UUID generator"
#include <stdlib.h>
static char randomHexDigit ()
{
static char digits[] = "0123456789abcdef";
return digits[random () % 16];
}
////////////////////////////////////////////////////////////////////////////////
const std::string uuid ()
{
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
char id [37];
id[0] = randomHexDigit ();
id[1] = randomHexDigit ();
id[2] = randomHexDigit ();
id[3] = randomHexDigit ();
id[4] = randomHexDigit ();
id[5] = randomHexDigit ();
id[6] = randomHexDigit ();
id[7] = randomHexDigit ();
id[8] = '-';
id[9] = randomHexDigit ();
id[10] = randomHexDigit ();
id[11] = randomHexDigit ();
id[12] = randomHexDigit ();
id[13] = '-';
id[14] = randomHexDigit ();
id[15] = randomHexDigit ();
id[16] = randomHexDigit ();
id[17] = randomHexDigit ();
id[18] = '-';
id[19] = randomHexDigit ();
id[20] = randomHexDigit ();
id[21] = randomHexDigit ();
id[22] = randomHexDigit ();
id[23] = '-';
id[24] = randomHexDigit ();
id[25] = randomHexDigit ();
id[26] = randomHexDigit ();
id[27] = randomHexDigit ();
id[28] = randomHexDigit ();
id[29] = randomHexDigit ();
id[30] = randomHexDigit ();
id[31] = randomHexDigit ();
id[32] = randomHexDigit ();
id[33] = randomHexDigit ();
id[34] = randomHexDigit ();
id[35] = randomHexDigit ();
return id;
}
#endif
////////////////////////////////////////////////////////////////////////////////