home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 6
/
AACD06.ISO
/
AACD
/
Utilities
/
amiCheck
/
Source
/
dataBase.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-04-09
|
86KB
|
3,644 lines
/************************************************
* dataBase.c
*
* This library keeps track of the register
* items. It also calls regGadget to
* update the display accordingly.
*
************************************************/
#include <exec/types.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <clib/intuition_protos.h>
#include <clib/dos_protos.h>
#include <clib/icon_protos.h>
#include <intuition/sghooks.h>
#include <intuition/gadgetclass.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include "regGadget.h"
#include "amiCheck.h"
#include "dataBase.h"
#include "qdatePanel.h"
#include "memoPanel.h"
#include "namePanel.h"
#include "amntPanel.h"
#include "dataBaseFile.h"
extern STRPTR demoptr;
/* globals and special structures */
struct MinList entries, filtered;
struct List templates,testtemps, memolist, datelist, namelist, amntlist;
struct List categories, sortfields, grouplist;
accntState usrAccount;
sortState sortStates;
UWORD decimalModulos[] = {
1,
10,
100,
1000,
10000,
};
char *decimalFormat[] = {
"%u",
"%u.%01u",
"%u.%02u",
"%u.%03u",
"%u.%04u",
};
arexxNode arexxMacros[MAXMACROS] =
{
{"UUUUUUUUUUUUUUUUUUUU",""},
{"UUUUUUUUUUUUUUUUUUUU",""},
{"UUUUUUUUUUUUUUUUUUUU",""},
{"UUUUUUUUUUUUUUUUUUUU",""},
{"UUUUUUUUUUUUUUUUUUUU",""},
{"UUUUUUUUUUUUUUUUUUUU",""},
{"UUUUUUUUUUUUUUUUUUUU",""},
{"UUUUUUUUUUUUUUUUUUUU",""},
{"UUUUUUUUUUUUUUUUUUUU",""},
{"UUUUUUUUUUUUUUUUUUUU",""},
#if 0
{"MMMMMMMMMMMMMMMMMMMM",""},
{"MMMMMMMMMMMMMMMMMMMM",""},
{"MMMMMMMMMMMMMMMMMMMM",""},
{"MMMMMMMMMMMMMMMMMMMM",""},
{"MMMMMMMMMMMMMMMMMMMM",""},
{"MMMMMMMMMMMMMMMMMMMM",""},
{"MMMMMMMMMMMMMMMMMMMM",""},
{"MMMMMMMMMMMMMMMMMMMM",""},
{"MMMMMMMMMMMMMMMMMMMM",""},
#endif
};
BOOL amiChangedItems;
UWORD entryCount;
UWORD currCheckNumber;
dateType currDate;
UWORD currCentury;
UWORD dateFormat = DATE_MMDDYY;
struct stateVars amntState;
balanceType filtAmnt;
sortNode sortEntries[SORTENTRIES];
struct TagItem strAmntTags[] =
{
/*{STRINGA_ExitHelp,TRUE},*/
/*{STRINGA_Justification, STRINGRIGHT},*/
{GTST_MaxChars,AMNTSIZE},
{TAG_DONE},
};
struct TagItem strDateTags[] =
{
/*{STRINGA_ExitHelp,TRUE},*/
{GTST_MaxChars,DATESIZE},
{TAG_DONE},
};
struct TagItem strNameTags[] =
{
/*{STRINGA_ExitHelp,TRUE},*/
{GTST_MaxChars,STRINGSIZE},
{TAG_DONE},
};
struct TagItem strMemoTags[] =
{
/*{STRINGA_ExitHelp,TRUE},*/
{GTST_MaxChars,STRINGSIZE},
{TAG_DONE},
};
struct TagItem strTempTags[] =
{
/*{STRINGA_ExitHelp,TRUE},*/
{GTST_MaxChars,TEMPNAMESIZE},
{TAG_DONE},
};
struct TagItem strCatTags[] =
{
/*{STRINGA_ExitHelp,TRUE},*/
{GTST_MaxChars,CATNAMESIZE},
{TAG_DONE},
};
struct TagItem strCheckTags[] =
{
/*{STRINGA_ExitHelp,TRUE},*/
{GTIN_Number, 1},
{GTIN_MaxChars,6},
{TAG_DONE},
};
struct TagItem TxtBorder[] =
{
{GTTX_Border, TRUE},
{GTTX_Text, ""},
{TAG_DONE},
};
struct TagItem TxtNoBorder[] =
{
{GTTX_Border, FALSE},
{GTTX_Text, ""},
{TAG_DONE},
};
struct TagItem TxtZero[] =
{
{GTTX_Border, TRUE},
{GTTX_Text," "},
{STRINGA_Justification, STRINGRIGHT},
{TAG_DONE},
};
struct TagItem TxtInt[] =
{
{GTIN_Number, 0},
{GTIN_MaxChars,6},
{TAG_DONE},
};
struct TagItem NumBorder[] =
{
{GTNM_Border, TRUE},
{TAG_DONE},
};
struct TagItem ListView[] =
{
{GTLV_ShowSelected, NULL},
{TAG_DONE},
};
struct TagItem MiscButton[] =
{
{ALT_Image, ALTI_GetMisc},
{TAG_DONE},
};
printControl checkPrint =
{
5000,TRUE,TRUE,1,0,
};
STRPTR fptlabels[] =
{
"080935cour12",
"081004cour10",
"081013cour10",
"081064cour10",
"081065cour10",
"081098cour10",
"081123cour10",
"091098cour10",
"091064cour10",
"090935cour12",
"Last Used",
NULL,
};
formControl checkForms =
{
"PRT:",
/* 080935 cour p12*/
{ TRUE, /* sheet feed */
17,3, /* lines/check, checks/page */
36, 35, 4, /* pay field m/w/l */
82,11,4, /* Date field m/w/l */
82,10,5, /* Amount field m/w/l */
30,38,13, /* Memo field m/w/l */
1,3,27, /* Voucher type, m/w */
30,60,6, /* String field m/w/l */
3, /* lines to skip */
120 /* cols/page */
},
{
/* 080935 cour p12*/
{ TRUE, /* sheet feed */
17,3, /* lines/check, checks/page */
36, 35, 4, /* pay field m/w/l */
82,11,4, /* Date field m/w/l */
82,10,5, /* Amount field m/w/l */
30,38,13, /* Memo field m/w/l */
1,3,27, /* Voucher type, m/w */
30,60,6, /* String field m/w/l */
3, /* lines to skip */
120 /* cols/page */
},
/* 081004 cour p10*/
{ TRUE, /* sheet feed */
21,1, /* lines/check, checks/page */
5, 55, 12, /* pay field m/w/l */
49,11,10, /* Date field m/w/l */
66,9,10, /* Amount field m/w/l */
2,40,17, /* Memo field m/w/l */
3,0,0, /* Voucher type, m/w */
7,65,7, /* String field m/w/l */
3, /* lines to skip */
80 /* cols/page */
},
/* 081013 cour p10*/
{ TRUE, /* sheet feed */
21,1, /* lines/check, checks/page */
5, 45, 13, /* pay field m/w/l */
50,11,7, /* Date field m/w/l */
67,9,7, /* Amount field m/w/l */
1,40,17, /* Memo field m/w/l */
2,0,0, /* Voucher type, m/w */
5,70,10, /* String field m/w/l */
3, /* lines to skip */
80 /* cols/page */
},
/* 081064 cour p10*/
{ TRUE, /* sheet feed */
21,1, /* lines/check, checks/page */
8, 55, 8, /* pay field m/w/l */
66,11,6, /* Date field m/w/l */
66,9,8, /* Amount field m/w/l */
6,35,16, /* Memo field m/w/l */
3,0,0, /* Voucher type, m/w */
1,70,10, /* String field m/w/l */
3, /* lines to skip */
80 /* cols/page */
},
/* 081065 cour p10*/
{ TRUE, /* sheet feed */
21,1, /* lines/check, checks/page */
5, 55, 12, /* pay field m/w/l */
49,11,6, /* Date field m/w/l */
66,9,6, /* Amount field m/w/l */
2,40,17, /* Memo field m/w/l */
3,0,0, /* Voucher type, m/w */
5,65,8, /* String field m/w/l */
3, /* lines to skip */
80 /* cols/page */
},
/* 081098 cour p10*/
{ TRUE, /* sheet feed */
21,1, /* lines/check, checks/page */
5, 45, 14, /* pay field m/w/l */
55,11,6, /* Date field m/w/l */
67,9,6, /* Amount field m/w/l */
1,40,17, /* Memo field m/w/l */
2,0,0, /* Voucher type, m/w */
5,70,10, /* String field m/w/l */
3, /* lines to skip */
80 /* cols/page */
},
/* 081123 cour p10*/
{ TRUE, /* sheet feed */
21,1, /* lines/check, checks/page */
5, 50, 14, /* pay field m/w/l */
66,11,5, /* Date field m/w/l */
66,9,8, /* Amount field m/w/l */
1,40,17, /* Memo field m/w/l */
3,0,0, /* Voucher type, m/w */
5,65,9, /* String field m/w/l */
3, /* lines to skip */
80 /* cols/page */
},
/* * * line printers * * */
/* 091098 cour p10*/
{ FALSE, /* sheet feed */
21,1, /* lines/check, checks/page */
5, 50, 14, /* pay field m/w/l */
53,11,6, /* Date field m/w/l */
66,9,6, /* Amount field m/w/l */
2,40,17, /* Memo field m/w/l */
4,0,0, /* Voucher type, m/w */
5,65,10, /* String field m/w/l */
2, /* lines to skip */
80 /* cols/page */
},
/* 091064 cour p10*/
{ FALSE, /* sheet feed */
21,1, /* lines/check, checks/page */
7, 55, 8, /* pay field m/w/l */
66,11,5, /* Date field m/w/l */
66,12,8, /* Amount field m/w/l */
4,35,17, /* Memo field m/w/l */
0,0,0, /* Voucher type, m/w */
1,65,10, /* String field m/w/l */
2, /* lines to skip */
80 /* cols/page */
},
/* 090935 cour p12*/
{ FALSE, /* sheet feed */
17,1, /* lines/check, checks/page */
36, 35, 4, /* pay field m/w/l */
83,11,4, /* Date field m/w/l */
83,10,5, /* Amount field m/w/l */
28,30,13, /* Memo field m/w/l */
1,3,27, /* Voucher type, m/w */
30,60,6, /* String field m/w/l */
3, /* lines to skip */
95 /* cols/page */
},
}
};
char daysinmonth[12] = {31,29,31,30,31,30,31,31,30,31,30,31};
char easymonths[12][4] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
};
reportSetting reportControl;
searchState searchControl;
filterSetting filterControl;
/*
* prototypes
*/
BOOL DataLeapYear(LONG);
BOOL DataStrSet(char *, char *);
void DataSortInit(void);
BOOL DataSortLevel(filterNode *, filterNode **, filterNode **, sortNode *);
void DataReplaceEntryCats(struct List *);
void DataReplaceTempCats(struct List *);
editCatNode *DataLocateCat(struct List *, char *);
BOOL DataSearchMatch(filterNode *, searchState *);
void DataInitBalances(void);
BOOL DataDateRange(entryNode *, filterSetting *);
int DataWriteEntry(int,entryNode *);
void DataExtractDate(dateType *, char *out);
void DataCreateDate(dateType *, char *out, BOOL year);
BOOL DataVerifyDateDec12(char *instr, char *newstr);
BOOL DataVerifyDate12Dec(char *instr, char *newstr);
BOOL DataVerifyDateMMDDYY(char *instr, char *newstr);
BOOL DataVerifyDateDDMMYY(char *instr, char *newstr);
int DataWriteTemplate(int fd, templateNode *temp);
/****************************************************
* DataListInit()
*
* Initialize lists
****************************************************/
void DataListInit(void)
{
NewList(&grouplist);
NewList((struct List *)&entries);
NewList((struct List *)&filtered);
NewList(&templates);
NewList(&categories);
NewList(&testtemps);
NewList(&sortfields);
NewList(&memolist);
NewList(&datelist);
NewList(&namelist);
NewList(&amntlist);
}
/****************************************************
* DataInit()
*
* Initialize the lists, create default templates
*****************************************************/
BOOL DataInit(void)
{
time_t t;
struct tm *pt;
templateNode temp;
categoryNode cat;
amountType defamount = 0;
int x;
/*
* install default templates
*/
memset(&temp, 0, sizeof(templateNode));
strcpy(temp.tempname,"Check");
strcpy(temp.template.category,"None");
temp.template.type=CHECKTYPE;
DataAddTemp(&templates, &temp);
strcpy(temp.tempname,"Withdrawal");
strcpy(temp.template.category,"None");
temp.template.type=WITHDRAWALTYPE;
DataAddTemp(&templates, &temp);
strcpy(temp.tempname,"Deposit");
strcpy(temp.template.category,"None");
temp.template.type=DEPOSITTYPE;
DataAddTemp(&templates,&temp);
strcpy(temp.tempname,"Script");
strcpy(temp.template.category,"None");
temp.template.type=SCRIPTTYPE;
DataAddTemp(&templates, &temp);
/*
* install default categories
*/
memset(&cat, 0, sizeof(categoryNode));
strcpy(cat.catname,"None");
DataAddCat(&categories,&cat);
/*
* other globals
*/
amntState.currTemplate = 0;
amntState.currCheckNumber = 1;
/* get century */
time (&t);
pt=localtime(&t);
currDate.day = pt->tm_mday;
currDate.month = pt->tm_mon + 1;
currDate.year = pt->tm_year + 1900;
currCentury = 1900 + (pt->tm_year/100);
QDateAdd(&currDate);
entryCount = 0;
/* initialize filter to all */
memset(&filterControl,0,sizeof(filterSetting));
filterControl.checks=TRUE;
filterControl.withdrawals=TRUE;
filterControl.deposits=TRUE;
filterControl.checkfrom = filterControl.checkto = 1;
memcpy(&filterControl.dateFrom,&currDate,sizeof(dateType));
memcpy(&filterControl.dateTo,&currDate,sizeof(dateType));
strcpy(filterControl.category,"None");
/* initialize sort array */
DataSortInit();
memset(&sortStates,0,sizeof(sortState));
/* initialize account */
memset(&usrAccount,0,sizeof(accntState));
usrAccount.checknumber = amntState.currCheckNumber;
memcpy(&usrAccount.openDate,&currDate,sizeof(dateType));
memcpy(&usrAccount.closeDate,&currDate,sizeof(dateType));
usrAccount.decimal = 2;
/* initalize balance */
DataInitBal(DEPOSITTYPE,&defamount,&amntState.currAmnt);
DataInitBal(DEPOSITTYPE,&defamount,&amntState.stateAmnt);
DataInitBal(DEPOSITTYPE,&defamount,&filtAmnt);
/* initialize search control */
memset(&searchControl,0,sizeof(searchState));
memcpy(&searchControl.searchdate,&currDate,sizeof(dateType));
searchControl.lastrow = -1;
searchControl.checknum = 1;
memset(&reportControl,0,sizeof(reportSetting));
reportControl.rows = 66;
reportControl.cols = 80;
for (x=0;x<MAXMACROS;x++) {
memset(arexxMacros[x].macroname,0,20+1);
sprintf(arexxMacros[x].macroname,"<unassigned %d>",x+1);
arexxMacros[x].macrofile[0]=0;
}
amiChangedItems = FALSE;
return (TRUE);
}
/***************************************************
* DataNode2Ord
*
* Returns ordinal entry in list by name
*
****************************************************/
LONG DataNode2Ord (struct List *list, char *name)
{
struct Node *result;
struct Node *temp;
LONG ord = 0;
result = DataFindName(list,name);
if (result == NULL)
return (0);
temp = list->lh_Head;
while (temp != result) {
ord++;
temp = temp->ln_Succ;
}
return (ord);
}
/***************************************************
* DataOrd2Node
*
* Returns Node ptr from ordinal entry
****************************************************/
struct Node *DataOrd2Node(struct List *list,LONG ord)
{
struct Node *temp = list->lh_Head;
LONG myord = 0;
while (temp && myord != ord) {
myord++;
temp = temp->ln_Succ;
}
return (temp);
}
/***************************************************
* DataAddCat()
*
* Adds a category
****************************************************/
BOOL DataAddCat(struct List *categories, categoryNode *info )
{
categoryNode *temp;
if ((temp = AllocVec(sizeof(categoryNode),MEMF_CLEAR))){
memcpy((void *)temp,(void *)info,sizeof(categoryNode));
temp->node.ln_Type = NT_USER;
temp->node.ln_Pri = 0;
temp->node.ln_Name = temp->catname;
AddTail(categories,(struct Node *)temp);
}
else return (FALSE);
return (TRUE);
}
/***************************************************
* DataTestFilter()
*
* Determine if node belongs to filter set
****************************************************/
BOOL DataTestFilter(entryNode *en, filterSetting *set)
{
BOOL retval = TRUE;
/* type check - returns quickly if it can */
switch (en->type) {
case CHECKTYPE:
if (set->checks != TRUE) return (FALSE);
break;
case WITHDRAWALTYPE:
if (set->withdrawals != TRUE) return(FALSE);
break;
case DEPOSITTYPE:
if (set->deposits != TRUE) return(FALSE);
break;
}
/* check range check */
if (en->type == CHECKTYPE) {
if (set->checkrange == FILTERIN) {
if (en->check < set->checkfrom || en->check > set->checkto)
return (FALSE);
}
else if (set->checkrange == FILTEROUT) {
if (en->check >= set->checkfrom && en->check <= set->checkto)
return (FALSE);
}
}
/* amount range check */
if (set->amntrange == FILTERIN) {
if (en->amount < set->amountFrom || en->amount > set->amountTo)
return (FALSE);
}
else if (set->amntrange == FILTEROUT) {
if (en->amount >= set->amountFrom && en->amount <= set->amountTo)
return (FALSE);
}
/* date range check */
if (set->daterange == FILTERIN && DataDateRange(en,set) == FALSE)
return (FALSE);
else if (set->daterange == FILTEROUT && DataDateRange(en,set) == TRUE)
return (FALSE);
/* category check */
if (set->usecategory == FILTERIN) {
if (strcmpi(set->category, en->category) != 0)
return (FALSE);
}
else if (set->usecategory == FILTEROUT) {
if (strcmpi(set->category, en->category) == 0)
return (FALSE);
}
/* set operations */
if ( (en->flags & set->andflag) != set->andflag)
return (FALSE);
if ( (en->flags & set->notflag) != 0)
return (FALSE);
/* payee check */
if (set->usepayee == FILTERIN ) {
if ( !MatchPatternNoCase(set->payeetoken, en->name) )
return (FALSE);
}
else if (set->usepayee == FILTEROUT) {
if (MatchPatternNoCase(set->payeetoken,en->name) )
return (FALSE);
}
/* memo check */
if (set->usememo == FILTERIN) {
if (!MatchPatternNoCase(set->memotoken, en->memo) )
return (FALSE);
}
else if (set->usememo == FILTEROUT) {
if (MatchPatternNoCase(set->memotoken,en->memo) )
return (FALSE);
}
return (retval);
}
/*************************************************
* DataDateRange()
*
* Range for dates
**************************************************/
BOOL DataDateRange(entryNode *en, filterSetting *set)
{
/* check years */
if( en->date.year < set->dateFrom.year || en->date.year > set->dateTo.year)
return (FALSE);
/* check months */
if (en->date.year == set->dateFrom.year && en->date.month < set->dateFrom.month)
return (FALSE);
if (en->date.year == set->dateTo.year && en->date.month > set->dateTo.month)
return (FALSE);
/* check days */
if (en->date.year == set->dateFrom.year && en->date.month == set->dateFrom.month &&
en->date.day < set->dateFrom.day)
return (FALSE);
if (en->date.year == set->dateTo.year && en->date.month == set->dateTo.month &&
en->date.day > set->dateTo.day)
return (FALSE);
return (TRUE);
}
/***************************************************
* DataRemoveEntry()
*
* removes an entry from the list
****************************************************/
void DataRemoveEntry(entryNode *info, filterNode *filt)
{
DataRemoveFilter(filt);
Remove((struct Node *)info);
FreeVec(info);
}
/***************************************************
* DataRemoveFilter()
*
* Removes supplied filter
***************************************************/
void DataRemoveFilter(filterNode *filt)
{
if (filt == NULL)
return;
entryCount--;
Remove((struct Node *)filt);
FreeVec(filt);
}
/***************************************************
* DataRemoveEntryFilter()
*
* Removes a filter based on the node
****************************************************/
void DataRemoveEntryFilter(entryNode *node)
{
filterNode *filt = (filterNode *)filtered.mlh_Head;
/* is this an empty list? */
if (filtered.mlh_TailPred == &filtered)
return;
/* locate filter */
while (filt->node.mln_Succ != NULL) {
if (filt->entry == node) {
DataRemoveFilter(filt);
break;
}
filt = (filterNode *)filt->node.mln_Succ;
}
}
/***************************************************
* DataInsertFilter()
*
* Add a filter node
****************************************************/
BOOL DataInsertFilter(filterNode *fparent,filterNode **ret,
entryNode *join, struct MinList *filtered)
{
int x;
filterNode *temp;
*ret = NULL;
if ((temp = AllocVec(sizeof(filterNode),MEMF_CLEAR))){
temp->entry = join;
for (x=0;x<4;x++)
temp->printChars[x]= -1;
Insert((struct List *)filtered,(struct Node *)temp, (struct Node *)fparent);
}
else return (FALSE);
*ret = temp;
return (TRUE);
}
/***************************************************
* DataInsertEntry()
*
* Add a transaction to proper place
****************************************************/
BOOL DataInsertEntry(filterNode *fparent, entryNode *eparent,
entryNode *info, struct MinList *entrylist, filterNode **filt,
entryNode **entry)
{
entryNode *temp;
*filt = NULL;
*entry = NULL;
if ((temp = AllocVec(sizeof(entryNode),MEMF_CLEAR))){
memcpy((void *)temp,(void *)info,sizeof(entryNode));
Insert((struct List *)entrylist,(struct Node *)temp,
(struct Node *)eparent);
*entry = temp;
}
else return (FALSE);
/* filter it */
if (DataTestFilter(temp, &filterControl) == TRUE)
DataInsertFilter(fparent,filt,temp,&filtered);
return (TRUE);
}
/***************************************************
* DataAddEntry()
*
* Add a transaction
****************************************************/
BOOL DataAddEntry(entryNode *info, struct MinList *entrylist, filterNode **filt)
{
entryNode *temp;
*filt = NULL;
if ((temp = AllocVec(sizeof(entryNode),MEMF_CLEAR))){
memcpy((void *)temp,(void *)info,sizeof(entryNode));
AddTail((struct List *)entrylist,(struct Node *)temp);
}
else return (FALSE);
/* filter it */
if (DataTestFilter(temp, &filterControl) == TRUE)
DataAddFilter(filt,temp,&filtered);
return (TRUE);
}
/***************************************************
* DataAddTemp()
*
* Adds a template
****************************************************/
BOOL DataAddTemp(struct List *templist, templateNode *info)
{
templateNode *temp;
if ((temp = AllocVec(sizeof(templateNode),MEMF_CLEAR))){
memcpy((void *)temp,(void *)info,sizeof(templateNode));
temp->node.ln_Type = NT_USER;
temp->node.ln_Pri = 0;
temp->node.ln_Name = temp->tempname;
AddTail(templist,(struct Node *)temp);
}
else return (FALSE);
return (TRUE);
}
/***************************************************
* DataAddFilter()
*
* Add a filter node
****************************************************/
BOOL DataAddFilter(filterNode **ret, entryNode *join, struct MinList *filtered)
{
int x;
filterNode *temp;
*ret = NULL;
if ((temp = AllocVec(sizeof(filterNode),MEMF_CLEAR))){
temp->entry = join;
for (x=0;x<4;x++)
temp->printChars[x]= -1;
AddTail((struct List *)filtered,(struct Node *)temp);
}
else return (FALSE);
*ret = temp;
return (TRUE);
}
/*****************************************************
* DataFreeAll()
*
* Free all database allocations
*****************************************************/
void DataFreeAll(void)
{
DataFreeList((struct List *)&entries);
DataFreeList((struct List *)&templates);
DataFreeList((struct List *)&filtered);
DataFreeList((struct List *)&categories);
DataFreeGroupCats((struct List *)&grouplist);
DataFreeList((struct List *)&grouplist);
DataFreeList((struct List *)&datelist);
DataFreeList((struct List *)&memolist);
DataFreeList((struct List *)&namelist);
DataFreeList((struct List *)&amntlist);
}
/****************************************************
* DataStoreAmnt()
*
* Takes the user string and stores it in a template
*****************************************************/
void DataStoreAmnt(amountType *amount, char *str)
{
ULONG d=0,c=0;
if (*str == NULL)
*amount = 0;
else {
/* later we will add "DataExtractAmount" */
if (usrAccount.decimal)
sscanf(str,"%u.%u",&d,&c);
else sscanf(str,"%u",&d);
*amount = (d*decimalModulos[usrAccount.decimal]) + c;
}
}
/***************************************************
* DataStoreDate()
*
* Stores date into string
****************************************************/
void DataStoreDate (dateType *date, char *str)
{
DataExtractDate(date,str);
}
/****************************************************
* DataBuildRegDate()
*
* Builds the reduced date for the register
*****************************************************/
void DataBuildRegDate(dateType *date, char *str)
{
DataCreateDate(date,str,TRUE);
}
/****************************************************
* DataBuildDate()
*
* Builds string from node of date
*****************************************************/
void DataBuildDate (dateType *date, char *str)
{
DataCreateDate(date,str,FALSE);
}
/****************************************************
* DataBuildAmnt()
*
* Routine to build a string from amnt
*****************************************************/
void DataBuildAmnt(BOOL zero, amountType *amount, char *str)
{
if (zero != TRUE && *amount == 0)
str[0]=0;
else {
sprintf(str,
decimalFormat[usrAccount.decimal],
(*amount/decimalModulos[usrAccount.decimal]),
(*amount%decimalModulos[usrAccount.decimal])
);
}
}
/****************************************************
* DataBuildBal()
*
* Routine to build a string from balance
*****************************************************/
void DataBuildBal(UBYTE decimal, balanceType *bal, char *str)
{
char negval = ' ';
if (bal->neg)
negval = '-';
sprintf(str,"%c",negval);
str++;
/* again, eventually we will do a createamount */
sprintf(str,decimalFormat[decimal],bal->dollar,bal->cent);
}
/*******************************************************
* DataMoveList()
*
* Accept new list as new original list.
********************************************************/
void DataMoveList(struct List *src, struct List *dest)
{
DataFreeList(dest);
memcpy(dest,src,sizeof(struct List));
dest->lh_Head->ln_Pred = (struct Node *)&(dest->lh_Head);
dest->lh_TailPred->ln_Succ = (struct Node *)&(dest->lh_Tail);
/* zap out original */
NewList(src);
}
/*******************************************************
* DataIsUnique()
*
* Takes any list and replies if an entry is
* unique by name. Boolean option opens
* requestor notifying user with custon strings.
********************************************************/
BOOL DataIsUnique(GUIFront *gui, struct List *lst, char *name, BOOL req,
char *reqstr)
{
struct Window *win = NULL;
struct EasyStruct es;
if (strlen(name) > 0 && DataFindName(lst,name) == NULL)
return (TRUE);
/* oh no, notify user */
if (req == TRUE) {
GF_GetGUIAttr(gui,
GUI_Window,&win,
TAG_DONE);
DisplayBeep(win->WScreen);
if (win != NULL) {
es.es_StructSize = sizeof(struct EasyStruct);
es.es_Flags = 0;
es.es_Title = "amiCheck NOTICE:";
es.es_TextFormat = reqstr;
es.es_GadgetFormat = "OK";
GF_LockGUI(gui);
GF_EasyRequest(gui,win,&es,NULL);
GF_UnlockGUI(gui);
}
}
return (FALSE);
}
/*****************************************************************
* DataVerifyAmnt()
*
* Force valid entry of amount strings
******************************************************************/
BOOL DataVerifyAmnt(char *instr,char *newstr)
{
amountType amnt = 0;
char *dot1, *dot2, *str, *skip;
ULONG x=0,y=0,temp;
char amnthold[AMNTSIZE+1];
*newstr = NULL;
amnthold[AMNTSIZE]=NULL;
strcpy(amnthold,instr);
str = amnthold;
/* something odd in there? */
if (str == NULL)
return (FALSE);
/* clip spaces off front and end */
while (*str == ' ') str++;
skip = &amnthold[strlen(amnthold) - 1];
while (*skip == ' ' && skip != str) {
*skip = NULL;
skip--;
}
if (DataStrSet(str,"0123456789. ") == FALSE) {
return (FALSE);
}
/* grab decimal point if one */
dot1 = strchr(str,'.');
if (dot1 != NULL) {
/* more than two decimal places? */
dot2 = dot1+1;
temp = strlen(dot2);
if (temp > usrAccount.decimal)
return (FALSE);
/* pull out data into integers */
if (dot1 == str)
sscanf(str,".%u",&y);
else sscanf(str,"%u.%u",&x,&y);
/* adjust for ".5 -> .50" */
if (temp < usrAccount.decimal)
y *= decimalModulos[usrAccount.decimal-temp];
/* another period? */
dot2 = strchr(dot2,'.');
if (dot2 != NULL) {
return (FALSE);
}
}
else sscanf(str,"%u",&x);
/* build new string */
amnt = (x*decimalModulos[usrAccount.decimal]) + y;
DataBuildAmnt(FALSE,&amnt,newstr);
return (TRUE);
}
/****************************************************************
* DataVerifyDate()
*
* Verifies and builds date string
****************************************************************/
BOOL DataVerifyDate(char *instr, char *newstr)
{
BOOL retval;
switch (dateFormat) {
case DATE_MMDDYY:
retval = DataVerifyDateMMDDYY(instr,newstr);
break;
case DATE_DDMMYY:
retval = DataVerifyDateDDMMYY(instr,newstr);
break;
case DATE_DEC_12:
retval = DataVerifyDateDec12(instr,newstr);
break;
case DATE_12_DEC:
retval = DataVerifyDate12Dec(instr,newstr);
break;
}
return (retval);
}
/********************************************************************
* DataLeapYear()
*
* TRUE if year is leap year
*********************************************************************/
BOOL DataLeapYear(LONG year)
{
/* quick /4 check for now */
if ( year%4 || !(year%100) )
return (FALSE);
return (TRUE);
}
/*******************************************************************
* DataAnnounce()
*
* Announce message to user
*******************************************************************/
void DataAnnounce(GUIFront *gui, char *str)
{
struct Window *win = NULL;
struct EasyStruct es;
if (str == NULL)
return;
/* oh no, notify user */
GF_GetGUIAttr(gui,
GUI_Window,&win,
TAG_DONE);
if (win != NULL) {
es.es_StructSize = sizeof(struct EasyStruct);
es.es_Flags = 0;
es.es_Title = "amiCheck NOTICE:";
es.es_TextFormat = str;
es.es_GadgetFormat = "OK";
GF_LockGUI(gui);
GF_EasyRequest(gui,win,&es,NULL);
GF_UnlockGUI(gui);
}
}
/*******************************************************************
* DataQuery()
*
* Query from user
*******************************************************************/
int DataQuery(GUIFront *gui, char *str, char *query)
{
struct Window *win = NULL;
struct EasyStruct es;
int val = 0;
if (str == NULL)
return (val);
/* oh no, notify user */
GF_GetGUIAttr(gui,
GUI_Window,&win,
TAG_DONE);
if (win != NULL) {
es.es_StructSize = sizeof(struct EasyStruct);
es.es_Flags = 0;
es.es_Title = "amiCheck NOTICE:";
es.es_TextFormat = str;
es.es_GadgetFormat = query;
GF_LockGUI(gui);
val = GF_EasyRequest(gui,win,&es,NULL);
GF_UnlockGUI(gui);
}
return (val);
}
/**************************************************************
* DataStrSet ()
*
* SAS/C strcspn replacement
**************************************************************/
BOOL DataStrSet(char *src, char *input)
{
WORD a,b;
BOOL found;
for (a=0;a<strlen(src);a++) {
found = FALSE;
for (b=0;b<strlen(input);b++) {
if (src[a] == input[b]) {
found = TRUE;
break;
}
}
if (found == FALSE)
return (FALSE);
}
return (TRUE);
}
/********************************************************
* DataUpdateFilters()
*
* Updates the filtered items to the filter criteria
* (not all transactions, for SPEED :)
********************************************************/
void DataUpdateFilters(struct MinList *filtered)
{
filterNode *work, *next;
if ((struct Node *)(filtered->mlh_TailPred) == (struct Node *)filtered)
return;
work = (filterNode *)(filtered->mlh_Head);
while (next = (filterNode *)(work->node.mln_Succ)) {
if (!DataTestFilter(work->entry,&filterControl))
DataRemoveFilter(work);
work = next;
}
}
/********************************************************
* DataBalConvert()
*
* Converts a balance from one decimal format to
* another (some data loss possible)
*********************************************************/
void DataBalConvert(balanceType *bal, UBYTE from, UBYTE to)
{
UWORD diff;
if (from == to)
return;
if (from > to) {
diff = decimalModulos[from - to];
bal->cent /= diff;
}
else {
diff = decimalModulos[to-from];
bal->cent *= diff;
}
}
/********************************************************
* DataBalToAmnt()
*
* Converts a balance to standard amount type
*********************************************************/
void DataBalToAmnt(balanceType *bal, UBYTE *type, amountType *amount)
{
if (bal->neg)
*type = WITHDRAWALTYPE;
else *type = DEPOSITTYPE;
*amount = (bal->dollar * decimalModulos[usrAccount.decimal]) +
bal->cent;
}
/********************************************************
* DataUpdateBal()
*
* Updates a balance, supply string. Decimal assumed
* from account setting
*********************************************************/
void DataUpdateBal(UBYTE type, amountType *amount, balanceType *bal, char *str)
{
DataAddBal(type, amount, bal);
DataBuildBal(usrAccount.decimal,bal,str);
}
/********************************************************
* DataAddBal()
*
* Updates a balance. Decimal assumed
* from account setting
*********************************************************/
void DataAddBal(UBYTE type, amountType *amount, balanceType *bal)
{
balanceType amntBal;
DataInitBal(type, amount, &amntBal);
DataBalAddBal(usrAccount.decimal,bal,&amntBal,bal);
}
/********************************************************
* DataBalAddBal()
*
* Adds two balances.
*********************************************************/
void DataBalAddBal(UBYTE decimal,balanceType *dest,
balanceType *bal1, balanceType *bal2)
{
balanceType b1, b2;
memcpy(&b1,bal1,sizeof(balanceType));
memcpy(&b2,bal2, sizeof(balanceType));
/* now we need to look at the two balances efficiently */
/* - + + */
if (b2.neg && !b1.neg) {
/* bal is greater or equal to */
if ( (b1.dollar > b2.dollar) ||
(b1.dollar == b2.dollar && b1.cent >= b2.cent)) {
/* borrow if needed */
if (b1.cent < b2.cent) {
b1.dollar--;
b1.cent += decimalModulos[decimal];
}
b1.cent -= b2.cent;
b1.dollar -= b2.dollar;
}
/* bal just shrunk! */
else {
b1.neg = TRUE;
/* borrow if needed */
if (b2.cent < b1.cent) {
b2.dollar--;
b2.cent += decimalModulos[decimal];
}
b1.cent = b2.cent - b1.cent;
b1.dollar = b2.dollar - b1.dollar;
}
}
/* + + - */
else if (b1.neg && !b2.neg) {
/* bal is breater or equal to */
if ( (b1.dollar > b2.dollar) ||
(b1.dollar == b2.dollar && b1.cent >= b2.cent)) {
/* borrow if needed */
if (b1.cent < b2.cent) {
b1.dollar--;
b1.cent += decimalModulos[decimal];
}
b1.cent -= b2.cent;
b1.dollar -= b2.dollar;
}
/* bal just shrunk! */
else {
b1.neg = FALSE;
/* borrow if needed */
if (b2.cent < b1.cent) {
b2.dollar--;
b2.cent += decimalModulos[decimal];
}
b1.cent = b2.cent - b1.cent;
b1.dollar = b2.dollar - b1.dollar;
}
}
/* + + + or - + - */
else {
b1.dollar += b2.dollar;
b1.cent += b2.cent;
if (b1.cent >= decimalModulos[decimal]) {
b1.dollar++;
b1.cent -= decimalModulos[decimal];
}
}
memcpy(dest,&b1,sizeof(balanceType));
if (dest->dollar == 0 && dest->cent == 0)
dest->neg = FALSE;
}
/********************************************************
* DataCmpAmntBal()
*
* Compares an amount and a balance. -1 if amnt is
* smaller, 0 if equal and 1 if larger. The negative
* aspect is currently ignored.
*********************************************************/
int DataCmpAmntBal(amountType *amnt, balanceType *bal)
{
balanceType store;
DataInitBal(DEPOSITTYPE,amnt,&store);
return (DataCmpBal(FALSE,&store,bal));
}
/********************************************************
* DataCmpBal()
*
* Compares two balances. -1 if b1 is smaller, 0
* if equal and 1 if larger.
*********************************************************/
int DataCmpBal(BOOL neg, balanceType *b1, balanceType *b2)
{
/* do we consider the negative aspect? */
if (neg) {
if (b1->neg && !b2->neg)
return -1;
else if (!b1->neg && b2->neg)
return 1;
else if (b1->dollar == b2->dollar && b1->cent == b2->cent)
return 0;
else if ( (b1->dollar > b2->dollar) ||
(b1->dollar == b2->dollar && b1->cent > b2->cent))
return -1;
else return 1;
}
else {
if (b1->dollar == b2->dollar && b1->cent == b2->cent)
return 0;
else if ( (b1->dollar > b2->dollar) ||
(b1->dollar == b2->dollar && b1->cent > b2->cent))
return 1;
else return -1;
}
}
/********************************************************
* DataInitBal()
*
* Inits a balance with an amount. The decimal
* is assumed to be the current account's
*********************************************************/
void DataInitBal(UBYTE type, amountType *amount, balanceType *bal)
{
bal->dollar = *amount / decimalModulos[usrAccount.decimal];
bal->cent = *amount % decimalModulos[usrAccount.decimal];
/* now make negative if necessary */
if (type != DEPOSITTYPE)
bal->neg = TRUE;
else bal->neg = FALSE;
}
/************************************************************
* DataRebuildFilters()
*
* We have changed something and need to free up and
* test _ALL_ transactions again.
*************************************************************/
void DataRebuildFilters(void)
{
entryNode *work, *next;
filterNode *filt;
DataFreeList((struct List *)&filtered);
entryCount = 0;
if (entries.mlh_TailPred == (struct Node *)&entries)
return;
work = (entryNode *)(entries.mlh_Head);
while (next = (entryNode *)(work->node.mln_Succ)) {
if (DataTestFilter(work,&filterControl) == TRUE) {
entryCount++;
DataAddFilter(&filt, work, &filtered);
}
work = next;
}
}
/**************************************************************
* DataSitNSpin()
*
* Wait for window activation
***************************************************************/
void DataSitNSpin(struct Gadget *ga, struct Window *win)
{
BOOL done = FALSE;
struct IntuiMessage *imsg = NULL;
if (simpleRefresh == TRUE)
return;
do {
while (imsg == NULL)
imsg = GF_GetIMsg(guiapp);
if (imsg->Class == IDCMP_ACTIVEWINDOW)
done = TRUE;
GF_ReplyIMsg(imsg);
} while (!done);
if (ga != NULL && win != NULL)
ActivateGadget(ga,win,NULL);
}
/***************************************************************
* DataSortInit()
*
* Initializes the sort field array
****************************************************************/
void DataSortInit(void)
{
strcpy(sortEntries[SORTCHECK].field,"Check Number");
sortEntries[SORTCHECK].node.ln_Name = sortEntries[SORTCHECK].field;
sortEntries[SORTCHECK].order = 0;
sortEntries[SORTCHECK].index = SORTCHECK;
strcpy(sortEntries[SORTDATE].field,"Transaction Date");
sortEntries[SORTDATE].node.ln_Name = sortEntries[SORTDATE].field;
sortEntries[SORTDATE].order = 0;
sortEntries[SORTDATE].index = SORTDATE;
strcpy(sortEntries[SORTAMNT].field,"Amount");
sortEntries[SORTAMNT].node.ln_Name = sortEntries[SORTAMNT].field;
sortEntries[SORTAMNT].order = 0;
sortEntries[SORTAMNT].index = SORTAMNT;
strcpy(sortEntries[SORTNAME].field,"Name Field");
sortEntries[SORTNAME].node.ln_Name = sortEntries[SORTNAME].field;
sortEntries[SORTNAME].order = 0;
sortEntries[SORTNAME].index = SORTNAME;
strcpy(sortEntries[SORTMEMO].field,"Memo Field");
sortEntries[SORTMEMO].node.ln_Name = sortEntries[SORTMEMO].field;
sortEntries[SORTMEMO].order = 0;
sortEntries[SORTMEMO].index = SORTMEMO;
strcpy(sortEntries[SORTCATEGORY].field,"Category");
sortEntries[SORTCATEGORY].node.ln_Name = sortEntries[SORTCATEGORY].field;
sortEntries[SORTCATEGORY].order = 0;
sortEntries[SORTCATEGORY].index = SORTCATEGORY;
}
/*******************************************************
* DataMoveSort()
*
* move a sort list from one to another
********************************************************/
void DataMoveSort(struct List *to, sortNode *to_nodes,
struct List *from, sortNode *from_nodes)
{
sortNode *node = (sortNode *)from->lh_Head;
NewList(to);
if (IsListEmpty(from))
return;
while (node->node.ln_Succ != NULL) {
AddTail(to, &to_nodes[node->index]);
node = (sortNode *)node->node.ln_Succ;
}
}
/**********************************************************
* DataReconcile()
*
* Reconciles the current account
***********************************************************/
balanceType DataReconcile(BOOL mark)
{
entryNode *next, *node = (entryNode *)entries.mlh_Head;
balanceType curr;
DataInitBal(DEPOSITTYPE,&usrAccount.beginAmount,&curr);
if (entries.mlh_TailPred == &entries)
return (curr);
while ( (next = (entryNode *)node->node.mln_Succ)) {
if ( (node->flags & CLEARED) && !(node->flags & VOIDED)) {
DataAddBal(node->type, &node->amount, &curr);
if (mark == TRUE) node->flags |= RECONCILED;
}
node = next;
}
if (mark) amntState.stateAmnt = curr;
return (curr);
}
/**************************************************************
* DataSortFilter()
*
* Sorts filter entries (recursive). Refilter before?
****************************************************************/
void DataSortFilter(filterNode *top, filterNode *bottom, sortNode *node)
{
BOOL swap = TRUE,done = FALSE;
filterNode *newtop, *newbottom;
filterNode *temptop, *temp, *tempswap;
sortNode *next = (sortNode *)node->node.ln_Succ;
/* move through each item and sort... not fast but _rhobust_ and easy */
temptop = top;
temp = (filterNode *)temptop->node.mln_Succ;
while (!done) {
/* place temptop node: */
swap = FALSE;
while (!swap && temp != NULL && temp->node.mln_Succ != NULL) {
switch (node->index) {
case SORTCHECK:
if (node->order == SORTASCEND) {
if (temptop->entry->check > temp->entry->check)
swap = TRUE;
}
else {
if (temptop->entry->check < temp->entry->check)
swap = TRUE;
}
break;
case SORTDATE:
if (node->order == SORTASCEND) {
if (temptop->entry->date.year > temp->entry->date.year)
swap = TRUE;
else if (temptop->entry->date.year == temp->entry->date.year &&
temptop->entry->date.month > temp->entry->date.month)
swap = TRUE;
else if (temptop->entry->date.year == temp->entry->date.year &&
temptop->entry->date.month == temp->entry->date.month &&
temptop->entry->date.day > temp->entry->date.day)
swap = TRUE;
}
else {
if (temptop->entry->date.year < temp->entry->date.year)
swap = TRUE;
else if (temptop->entry->date.year == temp->entry->date.year &&
temptop->entry->date.month < temp->entry->date.month)
swap = TRUE;
else if (temptop->entry->date.year == temp->entry->date.year &&
temptop->entry->date.month == temp->entry->date.month &&
temptop->entry->date.day < temp->entry->date.day)
swap = TRUE;
}
break;
case SORTAMNT:
if (node->order == SORTASCEND) {
if (temptop->entry->amount > temp->entry->amount)
swap = TRUE;
}
else {
if (temptop->entry->amount < temp->entry->amount)
swap = TRUE;
}
break;
case SORTNAME:
if (node->order == SORTASCEND) {
if (strcmpi(temptop->entry->name,temp->entry->name) > 0)
swap = TRUE;
}
else {
if (strcmpi(temptop->entry->name,temp->entry->name) < 0)
swap = TRUE;
}
break;
case SORTMEMO:
if (node->order == SORTASCEND) {
if (strcmpi(temptop->entry->memo,temp->entry->memo) > 0)
swap = TRUE;
}
else {
if (strcmpi(temptop->entry->memo,temp->entry->memo) < 0)
swap = TRUE;
}
break;
case SORTCATEGORY:
if (node->order == SORTASCEND) {
if (strcmpi(temptop->entry->category,temp->entry->category) > 0)
swap = TRUE;
}
else {
if (strcmpi(temptop->entry->category,temp->entry->category) < 0)
swap = TRUE;
}
break;
}
/* have we scanned the sector? */
if (temp == bottom || swap == TRUE)
break;
/* nope! move on to the next */
temp = (filterNode *)temp->node.mln_Succ;
}
if (swap) {
/* we will swap temptop with temp */
/* locate new parent for temptop */
tempswap = (filterNode *)temp->node.mln_Pred;
if (tempswap == temptop)
tempswap = temp;
/* is this the top? */
if (temptop == top)
top = temp;
/* is this the bottom? */
if (temp == bottom)
bottom = temptop;
Remove((struct Node *)temp);
Insert((struct List *)&filtered,(struct Node *)temp,(struct Node *)temptop);
Remove((struct Node *)temptop);
Insert((struct List *)&filtered,(struct Node *)temptop,(struct Node *)tempswap);
/* point to temp for next search */
temptop = temp;
temp = (filterNode *)temptop->node.mln_Succ;
}
else {
/* the current item needs no movement, next! */
if (temptop == bottom)
done = TRUE;
else {
temptop = (filterNode *)temptop->node.mln_Succ;
/* prepare for next round of sorting */
if (temptop == NULL || temptop == bottom || temptop->node.mln_Succ == NULL)
done = TRUE;
else temp = (filterNode *)temptop->node.mln_Succ;
}
}
}
/* finished, now jump to next level */
newtop = newbottom = top;
if (next != NULL && next->node.ln_Succ != NULL) {
/* find ALL tops and bottoms of this level and sort them */
while ( DataSortLevel(bottom,&newtop,&newbottom, node))
DataSortFilter(newtop,newbottom,next);
}
}
/****************************************************************
* DataSortLevel()
*
* Finds next block of sublevel entries that need sorting
*****************************************************************/
BOOL DataSortLevel(filterNode *bottom, filterNode **stop, filterNode **sbottom, sortNode *sort)
{
BOOL retval = FALSE;
BOOL skip = FALSE;
UWORD skipcount = 0;
filterNode *temptop = NULL;
filterNode *temp;
/* are we at the top or subsequent search? */
if (*sbottom == *stop)
temptop = *stop;
else
temptop = (filterNode *)(*sbottom)->node.mln_Succ;
/* don't go any farther if this is the bottom */
if (*sbottom == bottom || temptop == NULL || temptop == bottom || temptop->node.mln_Succ == NULL)
return(retval);
/* scan through while level is equal */
temp = (filterNode *)temptop->node.mln_Succ;
while (temp != NULL && temp->node.mln_Succ != NULL) {
skip = FALSE;
/* is this node == to temptop? */
switch (sort->index) {
case SORTCHECK:
if (temptop->entry->check == temp->entry->check)
skip = TRUE;
break;
case SORTDATE:
if (temptop->entry->date.year == temp->entry->date.year &&
temptop->entry->date.month == temp->entry->date.month &&
temptop->entry->date.day == temp->entry->date.day)
skip = TRUE;
break;
case SORTAMNT:
if (temptop->entry->amount == temp->entry->amount)
skip = TRUE;
break;
case SORTNAME:
if (strcmpi(temptop->entry->name,temp->entry->name) == 0)
skip = TRUE;
break;
case SORTMEMO:
if (strcmpi(temptop->entry->memo,temp->entry->memo) == 0)
skip = TRUE;
break;
case SORTCATEGORY:
if (strcmpi(temptop->entry->category,temp->entry->category) == 0)
skip = TRUE;
break;
}
if (skip == TRUE) {
/* yes, check next one (find whole block) */
skipcount++;
if (temp == bottom) {
temp = (filterNode *)temp->node.mln_Succ;
break;
}
else temp = (filterNode *)temp->node.mln_Succ;
}
else {
/* have we captured a region? */
if (skipcount > 0)
break;
/* move temptop down.. */
temptop = temp;
if (temptop == bottom || temptop == NULL) break;
temp = (filterNode *)temptop->node.mln_Succ;
}
}
/* ok what did we grab? */
if (skipcount > 0) {
temp = (filterNode *)temp->node.mln_Pred;
retval = TRUE;
*stop = temptop;
*sbottom = temp;
}
return (retval);
}
/*************************************************************
* DataNewEditCat()
*
* Creates a new editcat node and places it at tail
**************************************************************/
editCatNode *DataNewEditCat(struct List *el, categoryNode *cat)
{
editCatNode *work;
work = (editCatNode *)AllocVec(sizeof(editCatNode), MEMF_CLEAR);
memcpy(&work->new,cat,sizeof(categoryNode));
work->oldnode = FALSE;
work->new.node.ln_Name = work->new.catname;
AddTail((struct List *)el,(struct Node *)work);
return (work);
}
/*************************************************************
* DataFreeGroupCats()
*
* Special routine to free up group nodes
**************************************************************/
void DataFreeGroupCats(struct List *gl)
{
groupNode *work = NULL;
while ( (work = (groupNode *)DataGetNext(gl,(struct Node *)work)) != NULL)
DataFreeList(&work->catlist);
}
/*************************************************************
* DataNewGroup()
*
* Creates a new group node and places it at tail
**************************************************************/
groupNode *DataNewGroup(struct List *gl, groupNode *grp)
{
groupNode *work;
work = (groupNode *)AllocVec(sizeof(groupNode), MEMF_CLEAR);
memcpy(work,grp,sizeof(groupNode));
NewList(&work->catlist);
work->node.ln_Name = work->groupname;
AddTail((struct List *)gl,(struct Node *)work);
return (work);
}
/*************************************************************
* DataFreeList()
*
* Special free routine for a generic list
**************************************************************/
void DataFreeList(struct List *list)
{
struct Node *work = list->lh_Head;
struct Node *next;
if (IsListEmpty(list))
return;
while ( (next= work->ln_Succ)) {
FreeVec(work);
work = next;
}
NewList(list);
}
/**************************************************************
* DataCopyCatList()
*
* A special copy routine for the edit cat list
**************************************************************/
void DataCopyCatList(struct List *editlist, struct List *catlist)
{
categoryNode *cat = (categoryNode *)catlist->lh_Head;
editCatNode *work;
NewList((struct List *)editlist);
if (IsListEmpty(catlist))
return;
while (cat->node.ln_Succ) {
work = (editCatNode *)AllocVec(sizeof(editCatNode), MEMF_CLEAR);
memcpy(&work->original,cat,sizeof(categoryNode));
memcpy(&work->new,cat,sizeof(categoryNode));
work->oldnode = TRUE;
work->new.node.ln_Name = work->new.catname;
AddTail((struct List *)editlist,(struct Node *)work);
cat = (categoryNode*)cat->node.ln_Succ;
}
}
/********************************************************
* DataCopyList()
*
* Copy a simple list from one to another
*********************************************************/
void DataCopyList(struct List *src, struct List *dest, funcptr func)
{
struct MinNode *work = NULL;
/* free up dest */
DataFreeList(dest);
while ( (work = (struct MinNode *)DataGetNext(src,(struct Node *)work)) != NULL)
func(dest,work);
}
/****************************************************
* DataCopyGroupList()
*
* Copies a group list from one list to the other
******************************************************/
void DataCopyGroupList(struct List *src, struct List *dest)
{
groupNode *new, *work = NULL;
/* clean up dest */
DataFreeGroupCats(dest);
DataFreeList(dest);
/* copy each node over */
while ( (work = (groupNode *)DataGetNext(src,(struct Node *)work)) != NULL) {
new = DataNewGroup(dest,work);
DataCopyList(&work->catlist, &new->catlist, (funcptr)DataAddCat);
}
}
/****************************************************
* DataMoveCatList()
*
* Moves the special edit list into the original.
* replaces ALL system wide categories with
* their modified version or NONE if deleted.
******************************************************/
void DataMoveCatList(struct List *edit)
{
editCatNode *en, *next;
/* replace the database entries */
DataReplaceEntryCats(edit);
DataReplaceTempCats(edit);
/*DataReplaceGroupCats(&grouplist, edit);*/
/* replace all control structures */
en = DataLocateCat(edit,filterControl.category);
strcpy(filterControl.category,en->new.catname);
en = DataLocateCat(edit,searchControl.catstr);
/* only replace search if _exact_ match */
if (strcmpi(en->original.catname,searchControl.catstr) == 0)
strcpy(searchControl.catstr,en->new.catname);
/* what the hell was I thinking...
en = DataLocateCat(edit,sortEntries[SORTCATEGORY].field);
strcpy(sortEntries[SORTCATEGORY].field,en->new.catname);
*/
/* free up original list */
DataFreeList(&categories);
/* create new cat list */
en = (editCatNode *)edit->lh_Head;
while ( (next = (editCatNode *)en->new.node.ln_Succ)) {
DataAddCat(&categories,(categoryNode *)(&en->new));
en = next;
}
/* free up edit list */
DataFreeList(edit);
}
/********************************************************
* DataReplaceGroupCats()
*
* replaces all categories with their new names
*********************************************************/
void DataReplaceGroupCats(struct List *grps, struct List *new)
{
editCatNode *en;
groupNode *node = NULL;
categoryNode *cat;
struct Node *find;
while ( (node = (groupNode *)DataGetNext(grps, node)) != NULL) {
cat = NULL;
while ( (cat = (categoryNode *)DataGetNext(&node->catlist,cat)) != NULL) {
/* replace all control structures */
en = DataLocateCat(new, cat->catname);
if (strcmpi(en->new.catname,"none") == 0) {
find = DataFindName(new,cat->catname);
if (find == NULL) {
Remove(cat);
FreeVec(cat);
cat = NULL;
}
else strcpy(cat->catname,en->new.catname);
}
else strcpy(cat->catname,en->new.catname);
}
}
}
/********************************************************
* DataReplaceTempCats()
*
* replaces all categories with their new names
*********************************************************/
void DataReplaceTempCats(struct List *new)
{
editCatNode *found;
templateNode *node, *next;
if (templates.lh_TailPred == (struct Node *)&templates)
return;
node = (templateNode *)templates.lh_Head;
while ( (next = (templateNode *)node->node.ln_Succ) ){
found = DataLocateCat(new,node->template.category);
strcpy(node->template.category,found->new.catname);
node = next;
}
}
/********************************************************
* DataReplaceEntryCats()
*
* replaces all categories with their new names
*********************************************************/
void DataReplaceEntryCats(struct List *new)
{
editCatNode *found;
entryNode *node, *next;
if (entries.mlh_TailPred == &entries)
return;
node = (entryNode *)entries.mlh_Head;
while ( (next = (entryNode *)node->node.mln_Succ) ){
found = DataLocateCat(new,node->category);
strcpy(node->category,found->new.catname);
node = next;
}
}
/********************************************************
* DataLocateCat()
*
* Locate an original cat name.. return NONE if deleted
**********************************************************/
editCatNode *DataLocateCat(struct List *new, char *cat)
{
editCatNode *temp, *next;
temp = (editCatNode *)new->lh_Head;
while ( (next = (editCatNode *)temp->new.node.ln_Succ) ){
if (temp->oldnode == TRUE && strcmpi(cat,temp->original.catname) == 0)
return (temp);
temp = next;
}
return ( (editCatNode*)(new->lh_Head));
}
/**********************************************************
* DataSearchFilter()
*
* Searches through a fliter list for search match
***********************************************************/
WORD DataSearchFilter(struct MinList *fl, searchState *search)
{
WORD entry = 0, firstrow = -1;
BOOL findfirst;
filterNode *work = (filterNode *)fl->mlh_Head, *next;
if (fl->mlh_TailPred == fl)
return ( -1 );
/* is there any criteria to begin with? */
if (!search->check && !search->amnt && !search->date && !search->category &&
!search->name && !search->memo)
return (-1);
/* can we return on the first match? */
if (search->lastrow == -1 || search->lastrow >= entryCount)
findfirst = TRUE;
else findfirst = FALSE;
while ( (next = (filterNode *)work->node.mln_Succ) ) {
if (DataSearchMatch(work,search)) {
if (firstrow == -1) {
firstrow = entry;
if (findfirst || entry > search->lastrow)
return (entry);
}
else if (entry > search->lastrow)
return (entry);
}
/* next! */
entry++;
work = next;
}
/* did we match before entry? */
return (firstrow);
}
/********************************************************************
* DataSearchMatch()
*
* Match a filter to a search criteria
*********************************************************************/
BOOL DataSearchMatch(filterNode *fn, searchState *search)
{
if (search->check && fn->entry->type != CHECKTYPE)
return (FALSE);
if (search->check && (fn->entry->check != search->checknum))
return (FALSE);
if (search->memo && !MatchPatternNoCase(search->memostrtoken, fn->entry->memo))
return (FALSE);
if (search->name && !MatchPatternNoCase(search->namestrtoken, fn->entry->name))
return (FALSE);
if (search->category && !MatchPatternNoCase(search->catstrtoken, fn->entry->category))
return (FALSE);
if (search->amnt && (fn->entry->amount != search->amount))
return (FALSE);
if (search->date && (fn->entry->date.year != search->searchdate.year ||
fn->entry->date.month != search->searchdate.month ||
fn->entry->date.day != search->searchdate.day) )
return (FALSE);
return (TRUE);
}
/**********************************************************
* DataFindName()
*
* Case insensitive "FindName"
***********************************************************/
struct Node *DataFindName(struct List *l, char *name)
{
struct Node *work = (struct Node *)l->lh_Head, *next;
if (IsListEmpty(l))
return (NULL);
while ( (next = (struct Node *)work->ln_Succ)) {
if (strcmpi(work->ln_Name,name) == 0)
return (work);
work = next;
}
return (NULL);
}
/**********************************************************
* DataFindNode()
*
* search for node
***********************************************************/
WORD DataFindNode(struct List *l, struct Node *node)
{
WORD index = 0;
struct Node *work = (struct Node *)l->lh_Head, *next;
if (IsListEmpty(l))
return (-1);
while ( (next = (struct Node *)work->ln_Succ)) {
if (work == node)
return (index);
work = next;
index++;
}
return (-1);
}
/************************************************************
* DataBalance()
*
* calculate a balance based on flags. ignores
* account default balance
************************************************************/
balanceType DataBalance(UBYTE flags, struct MinList *list)
{
amountType amnt=0;
balanceType bal;
entryNode *entry = (entryNode *)list->mlh_Head, *next;
DataInitBal(DEPOSITTYPE,&amnt,&bal);
if (IsListEmpty((struct List *)list))
return (bal);
while ( (next = (entryNode *)entry->node.mln_Succ)) {
if ( !(entry->flags & VOIDED) && (entry->flags & flags) == flags) {
/*if (entry->type == DEPOSITTYPE)*/
DataAddBal(DEPOSITTYPE,&entry->amount,&bal);
/*
bal += entry->amount;
else
bal -= entry->amount;
*/
}
entry = next;
}
return (bal);
}
/************************************************************
* DataSaveFile()
*
* Save an account
*************************************************************/
BOOL DataSaveFile(char *fname, BOOL create)
{
int fd;
UWORD magicnum = MAGICNUM;
UWORD temp;
struct netInfoVars netInfo;
categoryNode *cat=NULL;
templateNode *tmpl=NULL;
entryNode *entry=NULL;
sortNode *tempsort = NULL;
memoNode *memo = NULL;
nameNode *nm = NULL;
amntNode *am = NULL;
groupNode *group = NULL;
if ( (fd = open(fname,O_WRONLY | ((create)?O_CREAT:0) ,0)) == -1)
return(FALSE);
/* write magic number */
if (write (fd,&magicnum,sizeof(UWORD)) == -1) {
close (fd);
return (FALSE);
}
/* calculate and write tax info */
netInfo.taxdeductcurr = DataBalance( (UBYTE)TAXDEDUCT,&entries);
netInfo.taxdeductstate = DataBalance( (UBYTE)(TAXDEDUCT | RECONCILED),&entries);
netInfo.currAmnt = amntState.currAmnt;
netInfo.stateAmnt = amntState.stateAmnt;
netInfo.decimal = usrAccount.decimal;
if (write (fd, &netInfo, sizeof(struct netInfoVars)) == -1) {
close(fd);
return (FALSE);
}
/* write user macros*/
if (write (fd, arexxMacros, sizeof(arexxNode)*MAXMACROS) == -1) {
close (fd);
return (FALSE);
}
/* write user check form */
if (write (fd,&checkForms.userForm,sizeof(checkForm)) == -1) {
close(fd);
return (FALSE);
}
/* write print prefs */
if (write (fd,&checkPrint,sizeof(printControl)) == -1) {
close(fd);
return (FALSE);
}
/* write report structure */
if (write (fd,&reportControl,sizeof(reportSetting)) == -1) {
close (fd);
return (FALSE);
}
/* write filter structure */
if (write (fd,&filterControl,sizeof(filterSetting)) == -1) {
close (fd);
return (FALSE);
}
/* write search structure */
if (write (fd,&searchControl, sizeof(searchState)) == -1) {
close (fd);
return (FALSE);
}
/* write num of sorts */
temp = DataCountNodes(&sortfields);
if (write (fd, &temp, sizeof(UWORD)) == -1) {
close (fd);
return (FALSE);
}
/* write sort structure */
while ( (tempsort = (sortNode *)DataGetNext(&sortfields,tempsort)))
if (write (fd,tempsort,sizeof(sortNode)) == -1) {
close(fd);
return (FALSE);
}
/* write sort state */
if (write (fd, &sortStates, sizeof(sortState)) == -1){
close(fd);
return (FALSE);
}
/* write account structure */
if (write (fd, &usrAccount,sizeof(accntState)) == -1) {
close(fd);
return (FALSE);
}
/* write num of categories */
temp = DataCountNodes(&categories);
if (write (fd, &temp, sizeof(UWORD)) == -1) {
close(fd);
return (FALSE);
}
/* write categories */
while ( (cat = (categoryNode*)DataGetNext(&categories,cat)))
if (write(fd,cat,sizeof(categoryNode)) == -1) {
close(fd);
return (FALSE);
}
/* write num groups */
temp = DataCountNodes(&grouplist);
if (write(fd,&temp,sizeof(UWORD)) == -1) {
close(fd);
return (FALSE);
}
/* write groups, one at a time */
while ( (group = (groupNode *)DataGetNext(&grouplist,group))) {
if (write(fd,group,sizeof(groupNode)) == -1) {
close(fd);
return(FALSE);
}
temp = DataCountNodes(&group->catlist);
if (write (fd, &temp, sizeof(UWORD)) == -1) {
close(fd);
return (FALSE);
}
cat = NULL;
while ( (cat = (categoryNode*)DataGetNext(&group->catlist,cat)))
if (write(fd,cat,sizeof(categoryNode)) == -1) {
close(fd);
return (FALSE);
}
}
/* write num of templates */
temp = DataCountNodes(&templates);
if (write (fd, &temp, sizeof(UWORD)) == -1) {
close(fd);
return (FALSE);
}
/* write templates */
while ( (tmpl = (templateNode*)DataGetNext(&templates,tmpl)))
if (DataWriteTemplate(fd, tmpl) != 0) {
close(fd);
return(FALSE);
}
/* write num of entries */
temp = DataCountNodes((struct List *)&entries);
if (write (fd, &temp, sizeof(UWORD)) == -1) {
close(fd);
return (FALSE);
}
/* write entries */
while ( (entry = (entryNode*)DataGetNext((struct List *)&entries, (struct Node *)entry)))
if (DataWriteEntry(fd,entry) != 0) {
close(fd);
return(FALSE);
}
/* checkbook state information */
if (write (fd,&amntState,sizeof(struct stateVars)) == -1) {
close(fd);
return (FALSE);
}
/* save the memo list */
temp = DataCountNodes((struct List *)&memolist);
if (write (fd, &temp, sizeof(UWORD)) == -1) {
close(fd);
return (FALSE);
}
/* write memos */
while ( (memo = (memoNode*)DataGetNext((struct List *)&memolist, (struct Node *)memo)))
if (write(fd,memo,sizeof(memoNode)) == -1) {
close(fd);
return (FALSE);
}
/* do the same for the names list and amnts list */
temp = DataCountNodes((struct List *)&namelist);
if (write (fd, &temp, sizeof(UWORD)) == -1) {
close(fd);
return (FALSE);
}
/* write names */
while ( (nm = (nameNode*)DataGetNext((struct List *)&namelist, (struct Node *)nm)))
if (write(fd,nm,sizeof(nameNode)) == -1) {
close(fd);
return (FALSE);
}
temp = DataCountNodes((struct List *)&amntlist);
if (write (fd, &temp, sizeof(UWORD)) == -1) {
close(fd);
return (FALSE);
}
/* write names */
while ( (am = (amntNode*)DataGetNext((struct List *)&amntlist, (struct Node *)am)))
if (write(fd,am,sizeof(amntNode)) == -1) {
close(fd);
return (FALSE);
}
close(fd);
return (TRUE);
}
/************************************************************
* DataLoadFile()
*
* Load an account
*************************************************************/
BOOL DataLoadFile(char *fname)
{
int fd;
int x,y;
UWORD magicnum;
UWORD temp,temp3;
categoryNode cat;
entryNode entry;
memoNode memo;
nameNode nm;
amntNode am;
templateNode tmpl;
sortNode tempsort;
filterNode *filt;
groupNode *group, tempgroup;
struct netInfoVars netInfo;
if ( (fd = open(fname,O_RDONLY,0)) == -1)
return (FALSE);
/* read magic number */
read (fd,&magicnum,sizeof(UWORD));
if (magicnum > MAGICNUM || magicnum < MAGICNUMOLD1 ) {
close(fd);
return (FALSE);
}
/* read tax vars */
DataReadTaxVars(magicnum,fd, &netInfo);
usrAccount.decimal = netInfo.decimal;
/* read in user macros*/
if (magicnum > MAGICNUMOLD8) {
read (fd, arexxMacros, sizeof(arexxNode)*MAXMACROS);
}
if (magicnum >= MAGICNUMOLD6) {
/* user check form */
if (magicnum == MAGICNUMOLD6)
read (fd,&checkForms.userForm,sizeof(checkForm)-(sizeof(ULONG)*3));
else read (fd,&checkForms.userForm,sizeof(checkForm));
/* print prefs */
read (fd,&checkPrint,sizeof(printControl));
}
/* read report structure */
read (fd,&reportControl,sizeof(reportSetting));
/* read filter structure */
DataReadFilterSetting(magicnum,fd,&filterControl);
/* read search structure */
DataReadSearchControl(magicnum,fd,&searchControl);
/* read num of sorts */
read (fd, &temp, sizeof(UWORD));
/* read sort structure */
NewList(&sortfields);
for (x=0;x<temp;x++) {
read (fd,&tempsort,sizeof(sortNode));
memcpy(&sortEntries[tempsort.index],&tempsort,sizeof(sortNode));
sortEntries[tempsort.index].node.ln_Succ = sortEntries[tempsort.index].node.ln_Pred = 0;
sortEntries[tempsort.index].node.ln_Name = sortEntries[tempsort.index].field;
AddTail(&sortfields,&sortEntries[tempsort.index]);
}
/* read sort state */
read (fd, &sortStates, sizeof(sortState));
/* read account structure */
DataReadAccountInfo(magicnum,fd,&usrAccount);
/* read num of categories */
read (fd, &temp, sizeof(UWORD));
/* read categories */
DataFreeList(&categories);
for (x=0;x<temp;x++) {
read (fd,&cat,sizeof(categoryNode));
DataAddCat(&categories,&cat);
}
/* read in groups */
if (magicnum > MAGICNUMOLD7) {
/* read num of groups */
read (fd, &temp, sizeof(UWORD));
DataFreeGroupCats(&grouplist);
DataFreeList(&grouplist);
/* read in each group */
for (x=0;x<temp;x++) {
read(fd,&tempgroup,sizeof(groupNode));
group = DataNewGroup(&grouplist,&tempgroup);
/* read each group category in */
read(fd,&temp3,sizeof(UWORD));
for (y=0;y<temp3;y++) {
read(fd,&cat,sizeof(categoryNode));
DataAddCat(&group->catlist,&cat);
}
}
}
/* read num of templates */
read (fd, &temp, sizeof(UWORD));
/* read templates */
DataFreeList(&templates);
for (x=0;x<temp;x++) {
DataReadTemplate(magicnum,fd,&tmpl);
DataAddTemp(&templates, &tmpl);
}
/* read num of entries */
read (fd, &temp, sizeof(UWORD));
/* read entries */
DataFreeList((struct List *)&filtered);
entryCount = 0;
DataFreeList((struct List *)&entries);
for (x=0;x<temp;x++) {
DataReadEntry(magicnum,fd,&entry);
DataAddEntry(&entry,&entries,&filt);
if (filt) entryCount++;
}
/* basic state variables */
DataReadStateVars(magicnum,fd, &amntState);
/* read in memos */
if (magicnum >= MAGICNUMOLD4) {
DataFreeList(&memolist);
read (fd, &temp, sizeof(UWORD));
for (x=0;x<temp;x++) {
read (fd,&memo,sizeof(memoNode));
MemoNewEdit(&memolist,&memo);
}
}
if (magicnum > MAGICNUMOLD4) {
DataFreeList(&namelist);
read(fd,&temp,sizeof(UWORD));
for (x=0;x<temp;x++) {
read (fd,&nm,sizeof(nameNode));
NameNewEdit(&namelist,&nm);
}
DataFreeList(&amntlist);
read(fd,&temp,sizeof(UWORD));
for (x=0;x<temp;x++) {
read (fd,&am,sizeof(amntNode));
AmntNewEdit(&amntlist,&am);
}
}
DataInitBalances();
if (close (fd))
return (FALSE);
return (TRUE);
}
/*******************************************************
* DataCountNodes()
*
* Count # nodes in a list
********************************************************/
UWORD DataCountNodes(struct List *lst)
{
UWORD ret = 0;
struct Node *work = lst->lh_Head;
struct Node *next;
if (IsListEmpty(lst))
return (ret);
while (( next = work->ln_Succ)) {
ret++;
work = next;
}
return (ret);
}
/*******************************************************
* DataGetNext()
*
* Get the next node in the list
********************************************************/
struct Node *DataGetNext(struct List *lst, struct Node *parent)
{
if (IsListEmpty(lst))
return (NULL);
if (parent == NULL)
return (lst->lh_Head);
if (parent->ln_Succ->ln_Succ)
return (parent->ln_Succ);
return (NULL);
}
/*******************************************************
* DataGetFileName()
*
* Obtain the file name from an ASL requestor
********************************************************/
BOOL DataGetFileName(char *dest, short destsize, char *drawer, char *file)
{
strncpy(dest, drawer, destsize);
return (AddPart( dest, file, destsize));
}
/*******************************************************
* DataAttachIcon()
*
* Attaches icons to files
********************************************************/
void DataAttachIcon(char *iconpath, char *iconname, char *fname)
{
struct DiskObject *diskobj;
char icon[200];
sprintf(icon,"%s%s",iconpath,iconname);
if ( (diskobj = GetDiskObjectNew(icon)) != NULL) {
PutDiskObject(fname,diskobj);
FreeDiskObject(diskobj);
}
}
/********************************************************
* DataRunningBals()
*
* Calculates running balances for the filters
*********************************************************/
balanceType DataRunningBals(struct MinList *entries, struct MinList *filtered)
{
amountType zero = 0;
balanceType scale,bal;
filterNode *filt;
entryNode *next, *entry = (entryNode *)entries->mlh_Head;
DataInitBal(DEPOSITTYPE,&usrAccount.beginAmount,&bal);
DataInitBal(DEPOSITTYPE,&zero, &scale);
if (entries->mlh_TailPred == (struct Node *)entries)
return (bal);
if (filtered->mlh_TailPred == (struct Node *)filtered)
return (bal);
while ( (next = (entryNode *)entry->node.mln_Succ)) {
if (!(entry->flags & VOIDED)) {
DataAddBal(entry->type,&entry->amount,&bal);
}
if (DataTestFilter(entry,&filterControl) == TRUE) {
if ( DataCmpAmntBal(&entry->amount,&scale) == 1)
DataInitBal(DEPOSITTYPE,&entry->amount,&scale);
else if ( DataCmpBal(FALSE, &bal, &scale) == 1)
memcpy(&scale,&bal,sizeof(balanceType));
filt = (filterNode *)filtered->mlh_Head;
/* locate filter */
while (filt->node.mln_Succ != NULL) {
if (filt->entry == entry) {
if (filt->entry->flags & VOIDED)
DataInitBal(DEPOSITTYPE,&zero,&filt->runningBal);
else
memcpy(&filt->runningBal,&bal,sizeof(balanceType));
break;
}
filt = (filterNode *)filt->node.mln_Succ;
}
}
entry = next;
}
DataAddBal(DEPOSITTYPE,&usrAccount.beginAmount,&scale);
return (scale);
}
/********************************************************
* DataSummarize()
*
* Obtain summary information from account
*********************************************************/
BOOL DataSummarize(char *fname, netNode *net)
{
int fd;
unsigned short magicnum;
if ( (fd = open(fname,O_RDONLY,0)) == -1)
return (FALSE);
/* read magic number */
read (fd,&magicnum,sizeof(UWORD));
if (magicnum < MAGICNUMOLD3) {
close(fd);
return (FALSE);
}
DataReadTaxVars(magicnum,fd,&net->balances);
strcpy(net->acname,fname);
close(fd);
return (TRUE);
}
/************************************************************
* DataFilterBalance()
*
* calculate the filter balance
************************************************************/
void DataFilterBalance(struct MinList *list)
{
amountType zero = 0;
balanceType bal;
filterNode *filter = (filterNode *)list->mlh_Head, *next;
DataInitBal(DEPOSITTYPE,&zero,&bal);
DataInitBal(DEPOSITTYPE,&zero,&filtAmnt);
if (IsListEmpty((struct List *)list))
return;
while ( (next = (filterNode *)filter->node.mln_Succ)) {
if ( !(filter->entry->flags & VOIDED) ) {
DataAddBal(filter->entry->type, &filter->entry->amount,&bal);
}
filter = next;
}
memcpy(&filtAmnt, &bal, sizeof(balanceType));
return;
}
/*******************************************************
* DataInitBalances()
*
* Initializes stmt and curr balances from load.
* They are read from the account, but don't trust
* them.
********************************************************/
void DataInitBalances(void)
{
entryNode *entry = NULL;
DataInitBal(DEPOSITTYPE,&usrAccount.beginAmount,&amntState.currAmnt);
while ( (entry = (entryNode *)DataGetNext((struct List *)&entries,(struct Node *)entry)) != NULL) {
if (!(entry->flags & VOIDED)) {
DataAddBal(entry->type,&entry->amount,&amntState.currAmnt);
}
}
}
/*******************************************************
* DataWriteTemplate()
*
* Write a template to file
********************************************************/
int DataWriteTemplate(int fd, templateNode *temp)
{
if (write(fd,temp->tempname,TEMPNAMESIZE) == -1)
return -1;
return (DataWriteEntry(fd,&temp->template));
}
/*******************************************************
* DataWriteEntry()
*
* Pack entries in file format and write out.
********************************************************/
int DataWriteEntry(int fd, entryNode *entry)
{
struct packit out;
UBYTE catsize;
out.type = entry->type;
out.check = entry->check;
out.flags = entry->flags;
out.amount = entry->amount;
out.date.year = entry->date.year;
out.date.day = entry->date.day;
out.date.month = entry->date.month;
out.namesize = strlen(entry->name);
out.memosize = strlen(entry->memo);
out.addr1size = out.addr2size = out.addr3size = out.addr4size = 0;
out.numBudgets = 1;
/* write out each datumn */
if (write (fd,&out,sizeof(struct packit)) != sizeof(struct packit))
return (-1);
/* write out strings */
if (write(fd,entry->name,out.namesize) != out.namesize)
return (-1);
if (write(fd,entry->memo,out.memosize) != out.memosize)
return (-1);
/* now for each category available... (currently just one) */
catsize = strlen(entry->category);
if (write(fd,&catsize,sizeof(UBYTE)) != sizeof(UBYTE))
return (-1);
if (write(fd,entry->category,catsize) != catsize)
return (-1);
if (write(fd,&entry->amount,sizeof(amountType)) != sizeof(amountType))
return (-1);
return (0);
}
/*************************************************************
* DataCreateDate()
*
* Create date based on multiple formats
**************************************************************/
void DataCreateDate(dateType *date, char *out, BOOL year)
{
switch (dateFormat) {
case DATE_MMDDYY:
if (year)
sprintf(out,"%02d/%02d/%2d",date->month,date->day,date->year % 100);
else sprintf(out,"%02d/%02d/%4d",date->month,date->day,date->year);
break;
case DATE_DDMMYY:
if (year)
sprintf(out,"%02d/%02d/%2d",date->day,date->month,date->year % 100);
else sprintf(out,"%02d/%02d/%4d",date->day,date->month,date->year);
break;
case DATE_DEC_12:
if (year)
sprintf(out,"%s-%02d-%2d",easymonths[date->month-1],date->day,date->year % 100);
else sprintf(out,"%s-%02d-%4d",easymonths[date->month-1],date->day,date->year);
break;
case DATE_12_DEC:
if (year)
sprintf(out,"%02d-%s-%2d",date->day,easymonths[date->month-1],date->year % 100);
else sprintf(out,"%02d-%s-%4d",date->day,easymonths[date->month-1],date->year);
break;
}
}
/***************************************************************
* DataExtractDate()
*
* extract date fields from date strings
****************************************************************/
void DataExtractDate(dateType *date, char *out)
{
ULONG day,year,month;
char str[4];
int x;
str[3]=0;
switch (dateFormat) {
case DATE_MMDDYY:
sscanf(out,"%d/%d/%d",&month,&day,&year);
break;
case DATE_DDMMYY:
sscanf(out,"%d/%d/%d",&day,&month,&year);
break;
case DATE_DEC_12:
sscanf(out,"%c%c%c-%d-%d",&str[0],&str[1],&str[2],&day,&year);
for (x=0;x<12;x++)
if (strcmpi(easymonths[x],str) == 0) {
month = x+1;
break;
}
break;
case DATE_12_DEC:
sscanf(out,"%d-%c%c%c-%d",&day,&str[0],&str[1],&str[2],&year);
for (x=0;x<12;x++)
if (strcmpi(easymonths[x],str) == 0) {
month = x+1;
break;
}
break;
}
date->day = day;
date->month = month;
date->year = year;
}
/****************************************************************
* DataVerifyDateMMDDYY()
*
* Verifies and builds date string
****************************************************************/
BOOL DataVerifyDateMMDDYY(char *instr, char *newstr)
{
char *section1, *section2, *last, *skip, *str;
ULONG day,year,month;
char strhold[DATESIZE+1];
dateType date;
if (instr == NULL)
return (FALSE);
strcpy(strhold,instr);
strhold[DATESIZE] = NULL;
str = strhold;
/* clip spaces off front and end */
while (*str == ' ') str++;
skip = &strhold[strlen(strhold) - 1];
while (*skip == ' ' && skip != str) {
*skip = NULL;
skip--;
}
if (DataStrSet(str,"0123456789/ ") == FALSE)
return (FALSE);
/* quick check for '/' count, grab sections */
section1 = strchr(str,'/');
if (section1 == NULL)
return (FALSE);
*section1 = NULL;
section1++;
section2 = strchr(section1,'/');
if (section2 == NULL)
return (FALSE);
*section2 = NULL;
section2++;
last = strchr(section2,'/');
if (last != NULL)
return (FALSE);
/* check for "/" */
if (strlen(section2) == 1)
return (FALSE);
/* now we have str->month, section1->day, section2->year */
/* grab values, then compare later */
sscanf(str,"%d",&month);
sscanf(section1,"%d",&day);
sscanf(section2,"%d",&year);
if (month > 12 || month == 0)
return (FALSE);
if (day > 31 || day == 0)
return (FALSE);
if (year > 9999) return (FALSE);
if (year < 100) year += currCentury;
/* check for days in month */
if (daysinmonth[month-1] < day )
return (FALSE);
if (month == 2 && day == daysinmonth[month-1] && !DataLeapYear(year))
return (FALSE);
date.day = day;
date.month = month;
date.year = year;
DataCreateDate(&date,newstr, FALSE);
return (TRUE);
}
/****************************************************************
* DataVerifyDateDDMMYY()
*
* Verifies and builds date string
****************************************************************/
BOOL DataVerifyDateDDMMYY(char *instr, char *newstr)
{
char *section1, *section2, *last, *skip, *str;
ULONG day,year,month;
char strhold[DATESIZE+1];
dateType date;
if (instr == NULL)
return (FALSE);
strcpy(strhold,instr);
strhold[DATESIZE] = NULL;
str = strhold;
/* clip spaces off front and end */
while (*str == ' ') str++;
skip = &strhold[strlen(strhold) - 1];
while (*skip == ' ' && skip != str) {
*skip = NULL;
skip--;
}
if (DataStrSet(str,"0123456789/ ") == FALSE)
return (FALSE);
/* quick check for '/' count, grab sections */
section1 = strchr(str,'/');
if (section1 == NULL)
return (FALSE);
*section1 = NULL;
section1++;
section2 = strchr(section1,'/');
if (section2 == NULL)
return (FALSE);
*section2 = NULL;
section2++;
last = strchr(section2,'/');
if (last != NULL)
return (FALSE);
/* check for "/" */
if (strlen(section2) == 1)
return (FALSE);
/* now we have str->month, section1->day, section2->year */
/* grab values, then compare later */
sscanf(str,"%d",&day);
sscanf(section1,"%d",&month);
sscanf(section2,"%d",&year);
if (month > 12 || month == 0)
return (FALSE);
if (day > 31 || day == 0)
return (FALSE);
if (year > 9999) return (FALSE);
if (year < 100) year += currCentury;
/* check for days in month */
if (daysinmonth[month-1] < day )
return (FALSE);
if (month == 2 && day == daysinmonth[month-1] && !DataLeapYear(year))
return (FALSE);
date.day = day;
date.month = month;
date.year = year;
DataCreateDate(&date,newstr, FALSE);
return (TRUE);
}
/****************************************************************
* DataVerifyDateDec12()
*
* Verifies and builds date string
****************************************************************/
BOOL DataVerifyDateDec12(char *instr, char *newstr)
{
char *section1, *section2, *last, *skip, *str;
ULONG day,year,month;
int x;
char strhold[DATESIZE+1];
dateType date;
if (instr == NULL)
return (FALSE);
strcpy(strhold,instr);
strhold[DATESIZE] = NULL;
str = strhold;
/* clip spaces off front and end */
while (*str == ' ') str++;
skip = &strhold[strlen(strhold) - 1];
while (*skip == ' ' && skip != str) {
*skip = NULL;
skip--;
}
/* find date */
month = 0;
for (x=0;x<12;x++) {
if (strnicmp (easymonths[x],str,3) == 0 ) {
month = x+1;
break;
}
}
if (month == 0)
return (FALSE);
/* quick check for '-' count, grab sections */
section1 = strchr(str,'-');
if (section1 == NULL)
return (FALSE);
*section1 = NULL;
section1++;
section2 = strchr(section1,'-');
if (section2 == NULL)
return (FALSE);
*section2 = NULL;
section2++;
last = strchr(section2,'-');
if (last != NULL)
return (FALSE);
/* check for "-" */
if (strlen(section2) == 1)
return (FALSE);
/* now we have str->month, section1->day, section2->year */
/* grab values, then compare later */
sscanf(section1,"%d",&day);
sscanf(section2,"%d",&year);
if (month > 12 || month == 0)
return (FALSE);
if (day > 31 || day == 0)
return (FALSE);
if (year > 9999) return (FALSE);
if (year < 100) year += currCentury;
/* check for days in month */
if (daysinmonth[month-1] < day )
return (FALSE);
if (month == 2 && day == daysinmonth[month-1] && !DataLeapYear(year))
return (FALSE);
date.day = day;
date.month = month;
date.year = year;
DataCreateDate(&date,newstr, FALSE);
return (TRUE);
}
/****************************************************************
* DataVerifyDate12Dec()
*
* Verifies and builds date string
****************************************************************/
BOOL DataVerifyDate12Dec(char *instr, char *newstr)
{
char *section1, *section2, *last, *skip, *str;
ULONG day,year,month;
int x;
char strhold[DATESIZE+1];
dateType date;
if (instr == NULL)
return (FALSE);
strcpy(strhold,instr);
strhold[DATESIZE] = NULL;
str = strhold;
/* clip spaces off front and end */
while (*str == ' ') str++;
skip = &strhold[strlen(strhold) - 1];
while (*skip == ' ' && skip != str) {
*skip = NULL;
skip--;
}
/* quick check for '-' count, grab sections */
section1 = strchr(str,'-');
if (section1 == NULL)
return (FALSE);
*section1 = NULL;
section1++;
section2 = strchr(section1,'-');
if (section2 == NULL)
return (FALSE);
*section2 = NULL;
section2++;
last = strchr(section2,'-');
if (last != NULL)
return (FALSE);
/* check for "-" */
if (strlen(section2) == 1)
return (FALSE);
/* now we have str->month, section1->day, section2->year */
/* grab values, then compare later */
month = 0;
for (x=0;x<12;x++) {
if (strnicmp (easymonths[x],section1,3) == 0 ) {
month = x+1;
break;
}
}
if (month == 0)
return (FALSE);
sscanf(str,"%d",&day);
sscanf(section2,"%d",&year);
if (month > 12 || month == 0)
return (FALSE);
if (day > 31 || day == 0)
return (FALSE);
if (year > 9999) return (FALSE);
if (year < 100) year += currCentury;
/* check for days in month */
if (daysinmonth[month-1] < day )
return (FALSE);
if (month == 2 && day == daysinmonth[month-1] && !DataLeapYear(year))
return (FALSE);
date.day = day;
date.month = month;
date.year = year;
DataCreateDate(&date,newstr, FALSE);
return (TRUE);
}
/************************************************************
* DataAnnounceDate()
*
* Announce date for different formats
*************************************************************/
void DataAnnounceDate(GUIFront *gui)
{
char *str[4] = {
"Illegal Date\nFormat: mm/dd/yy",
"Illegal Date\nFormat: dd/mm/yy",
"Illegal Date\nFormat: mmm-dd-yy",
"Illegal Date\nFormat: dd-mmm-yy",
};
switch (dateFormat) {
case DATE_MMDDYY:
DataAnnounce(gui,str[0]);
break;
case DATE_DDMMYY:
DataAnnounce(gui,str[1]);
break;
case DATE_DEC_12:
DataAnnounce(gui,str[2]);
break;
case DATE_12_DEC:
DataAnnounce(gui,str[3]);
break;
}
}
/************************************************************
* DataAnnounceAmount()
*
* Announce illegal amount
*************************************************************/
void DataAnnounceAmount(GUIFront *gui)
{
DataAnnounce(gui,"Illegal amount value.");
}
/***********************************************************
* DataListUp()
*
* Listview management library: move entry UP
************************************************************/
void DataListUp(GUIFront *gui, struct Gadget *listgad, struct List *list, UWORD *listsel)
{
struct Node *node1, *node2;
/* do we have room to move up? */
if (*listsel == 0)
return;
/* detach list */
GF_SetGadgetAttrs(gui,listgad,
GTLV_Labels, ~0,
TAG_DONE);
node1 = DataOrd2Node(list,*listsel);
if (*listsel > 1)
node2 = DataOrd2Node(list,*listsel-2);
else node2 = NULL;
Remove(node1);
Insert(list, node1, node2);
*listsel = *listsel - 1;
/* re-attach list */
GF_SetGadgetAttrs(gui,listgad,
GTLV_Labels, list,
GTLV_Selected,*listsel,
GTLV_MakeVisible, *listsel,
TAG_DONE);
}
/***********************************************************
* DataListDown()
*
* Listview management library: move entry DOWN
************************************************************/
void DataListDown(GUIFront *gui, struct Gadget *listgad, struct List *list, UWORD *listsel)
{
struct Node *node1, *node2;
/* detach list */
GF_SetGadgetAttrs(gui,listgad,
GTLV_Labels, ~0,
TAG_DONE);
node1 = DataOrd2Node(list,*listsel);
/* is this the last one? */
if ( node1->ln_Succ != (struct Node *)(&list->lh_Tail)) {
node2 = DataOrd2Node(list,*listsel+1);
Remove(node1);
Insert(list,node1,node2);
*listsel = *listsel + 1;
}
/* re-attach list */
GF_SetGadgetAttrs(gui,listgad,
GTLV_Labels, list,
GTLV_Selected,*listsel,
GTLV_MakeVisible, *listsel,
TAG_DONE);
}
/***********************************************************
* DataListBottom()
*
* Listview management library: move entry to BOTTOM
************************************************************/
void DataListBottom(GUIFront *gui, struct Gadget *listgad,
struct List *list, UWORD *listsel, UWORD entries)
{
struct Node *node1;
/* detach list */
GF_SetGadgetAttrs(gui,listgad,
GTLV_Labels, ~0,
TAG_DONE);
node1 = DataOrd2Node(list,*listsel);
Remove(node1);
AddTail(list,node1);
*listsel = entries-1;
/* re-attach list */
GF_SetGadgetAttrs(gui,listgad,
GTLV_Labels, list,
GTLV_Selected,*listsel,
GTLV_MakeVisible, *listsel,
TAG_DONE);
}
/***********************************************************
* DataListTop()
*
* Listview management library: move entry to TOP
************************************************************/
void DataListTop(GUIFront *gui, struct Gadget *listgad,
struct List *list, UWORD *listsel, UWORD topmargin)
{
struct Node *node1, *node2;
if (*listsel <= topmargin)
return;
/* detach list */
GF_SetGadgetAttrs(gui,listgad,
GTLV_Labels, ~0,
TAG_DONE);
node1 = DataOrd2Node(list,*listsel);
if (topmargin != 0 && *listsel > topmargin)
node2 = DataOrd2Node(list,topmargin-1);
else node2 = NULL;
Remove(node1);
Insert(list, node1, node2);
*listsel = topmargin;
/* re-attach list */
GF_SetGadgetAttrs(gui,listgad,
GTLV_Labels, list,
GTLV_Selected, *listsel,
GTLV_MakeVisible, *listsel,
TAG_DONE);
}
/***********************************************************
* DataListRemove()
*
* Listview management library: remove entry
************************************************************/
void DataListRemove(GUIFront *gui, struct Gadget *listgad,
struct List *list, UWORD *listsel)
{
struct Node *node1;
/* detach and modify list */
GF_SetGadgetAttrs(gui,listgad,
GTLV_Labels, ~0,
TAG_DONE);
node1 = DataOrd2Node(list,*listsel);
if (node1->ln_Succ == (struct Node *)(&list->lh_Tail))
*listsel = *listsel - 1;
Remove(node1);
FreeVec(node1);
/* re-attach list */
if (IsListEmpty(list)) {
GF_SetGadgetAttrs(gui,listgad,
GTLV_Labels, list,
GTLV_Selected, ~0,
TAG_DONE);
}
else {
GF_SetGadgetAttrs(gui,listgad,
GTLV_Labels, list,
GTLV_Selected, *listsel,
GTLV_MakeVisible, *listsel,
TAG_DONE);
}
}