home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Utilities / amiCheck / Source / dataBase.c < prev    next >
C/C++ Source or Header  |  1998-04-09  |  86KB  |  3,644 lines

  1. /************************************************
  2. * dataBase.c
  3. *
  4. *       This library keeps track of the register
  5. *       items.  It also calls regGadget to
  6. *       update the display accordingly.
  7. *
  8. ************************************************/
  9. #include <exec/types.h>
  10. #include <exec/lists.h>
  11. #include <exec/nodes.h>
  12. #include <exec/memory.h>
  13.  
  14. #include <clib/intuition_protos.h>
  15. #include <clib/dos_protos.h>
  16. #include <clib/icon_protos.h>
  17. #include <intuition/sghooks.h>
  18. #include <intuition/gadgetclass.h>
  19. #include <clib/alib_protos.h>
  20. #include <clib/exec_protos.h>
  21. #include <string.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <time.h>
  25. #include <fcntl.h>
  26.  
  27. #include "regGadget.h"
  28. #include "amiCheck.h"
  29. #include "dataBase.h"
  30. #include "qdatePanel.h"
  31. #include "memoPanel.h"
  32. #include "namePanel.h"
  33. #include "amntPanel.h"
  34. #include "dataBaseFile.h"
  35.  
  36.  
  37. extern STRPTR demoptr;
  38.  
  39. /* globals and special structures */
  40. struct MinList  entries, filtered;
  41. struct List templates,testtemps, memolist, datelist, namelist, amntlist;
  42. struct List categories, sortfields, grouplist;
  43.  
  44. accntState     usrAccount;
  45. sortState     sortStates;
  46.  
  47. UWORD decimalModulos[] = {
  48.     1,
  49.     10,
  50.     100,
  51.     1000,
  52.     10000,
  53. };
  54.  
  55. char *decimalFormat[] = {
  56.     "%u",
  57.     "%u.%01u",
  58.     "%u.%02u",
  59.     "%u.%03u",
  60.     "%u.%04u",
  61. };
  62.  
  63. arexxNode arexxMacros[MAXMACROS] = 
  64. {
  65. {"UUUUUUUUUUUUUUUUUUUU",""},
  66. {"UUUUUUUUUUUUUUUUUUUU",""},
  67. {"UUUUUUUUUUUUUUUUUUUU",""},
  68. {"UUUUUUUUUUUUUUUUUUUU",""},
  69. {"UUUUUUUUUUUUUUUUUUUU",""},
  70. {"UUUUUUUUUUUUUUUUUUUU",""},
  71. {"UUUUUUUUUUUUUUUUUUUU",""},
  72. {"UUUUUUUUUUUUUUUUUUUU",""},
  73. {"UUUUUUUUUUUUUUUUUUUU",""},
  74. {"UUUUUUUUUUUUUUUUUUUU",""},
  75.  
  76. #if 0
  77. {"MMMMMMMMMMMMMMMMMMMM",""},
  78. {"MMMMMMMMMMMMMMMMMMMM",""},
  79. {"MMMMMMMMMMMMMMMMMMMM",""},
  80. {"MMMMMMMMMMMMMMMMMMMM",""},
  81. {"MMMMMMMMMMMMMMMMMMMM",""},
  82. {"MMMMMMMMMMMMMMMMMMMM",""},
  83. {"MMMMMMMMMMMMMMMMMMMM",""},
  84. {"MMMMMMMMMMMMMMMMMMMM",""},
  85. {"MMMMMMMMMMMMMMMMMMMM",""},
  86. #endif
  87. };
  88.  
  89. BOOL  amiChangedItems;
  90. UWORD entryCount;
  91. UWORD currCheckNumber;
  92. dateType currDate;
  93. UWORD currCentury;
  94. UWORD dateFormat = DATE_MMDDYY;
  95.  
  96. struct stateVars amntState;
  97. balanceType filtAmnt;
  98.  
  99. sortNode sortEntries[SORTENTRIES];
  100.  
  101. struct TagItem strAmntTags[] =
  102. {
  103.     /*{STRINGA_ExitHelp,TRUE},*/
  104.     /*{STRINGA_Justification, STRINGRIGHT},*/
  105.     {GTST_MaxChars,AMNTSIZE},
  106.     {TAG_DONE},
  107. };
  108.  
  109. struct TagItem strDateTags[] =
  110. {
  111.     /*{STRINGA_ExitHelp,TRUE},*/
  112.     {GTST_MaxChars,DATESIZE},
  113.     {TAG_DONE},
  114. };
  115.  
  116. struct TagItem strNameTags[] =
  117. {
  118.     /*{STRINGA_ExitHelp,TRUE},*/
  119.     {GTST_MaxChars,STRINGSIZE},
  120.     {TAG_DONE},
  121. };
  122.  
  123. struct TagItem strMemoTags[] =
  124. {
  125.     /*{STRINGA_ExitHelp,TRUE},*/
  126.     {GTST_MaxChars,STRINGSIZE},
  127.     {TAG_DONE},
  128. };
  129.  
  130. struct TagItem strTempTags[] =
  131. {
  132.     /*{STRINGA_ExitHelp,TRUE},*/
  133.     {GTST_MaxChars,TEMPNAMESIZE},
  134.     {TAG_DONE},
  135. };
  136.  
  137. struct TagItem strCatTags[] =
  138. {
  139.     /*{STRINGA_ExitHelp,TRUE},*/
  140.     {GTST_MaxChars,CATNAMESIZE},
  141.     {TAG_DONE},
  142. };
  143.  
  144. struct TagItem strCheckTags[] =
  145. {
  146.     /*{STRINGA_ExitHelp,TRUE},*/
  147.     {GTIN_Number, 1},
  148.     {GTIN_MaxChars,6},
  149.     {TAG_DONE},
  150. };
  151.  
  152. struct TagItem TxtBorder[] = 
  153. {
  154.     {GTTX_Border, TRUE},
  155.     {GTTX_Text, ""},
  156.     {TAG_DONE},
  157. };
  158.  
  159. struct TagItem TxtNoBorder[] = 
  160. {
  161.     {GTTX_Border, FALSE},
  162.     {GTTX_Text, ""},
  163.     {TAG_DONE},
  164. };
  165.  
  166.  
  167. struct TagItem TxtZero[] =
  168. {
  169.     {GTTX_Border, TRUE},
  170.     {GTTX_Text,"     "},
  171.     {STRINGA_Justification, STRINGRIGHT},
  172.     {TAG_DONE},
  173. };
  174.  
  175. struct TagItem TxtInt[] =
  176. {
  177.     {GTIN_Number, 0},
  178.     {GTIN_MaxChars,6},
  179.     {TAG_DONE},
  180. };
  181.  
  182. struct TagItem NumBorder[] =
  183. {
  184.     {GTNM_Border, TRUE},
  185.     {TAG_DONE},
  186. };
  187.  
  188. struct TagItem ListView[] =
  189. {
  190.         {GTLV_ShowSelected, NULL},
  191.         {TAG_DONE},
  192. };
  193.  
  194. struct TagItem MiscButton[] =
  195. {
  196.         {ALT_Image, ALTI_GetMisc},
  197.         {TAG_DONE},
  198. };
  199.  
  200.  
  201. printControl checkPrint =
  202. {
  203.     5000,TRUE,TRUE,1,0,
  204. };
  205.  
  206. STRPTR fptlabels[] =
  207. {
  208.         "080935cour12",
  209.     "081004cour10",
  210.     "081013cour10",
  211.        "081064cour10",
  212.     "081065cour10",
  213.     "081098cour10",
  214.     "081123cour10",
  215.  
  216.     "091098cour10",
  217.      "091064cour10", 
  218.     "090935cour12",
  219.     "Last Used",
  220.     NULL,
  221. };
  222.  
  223. formControl checkForms = 
  224. {
  225.  "PRT:",
  226.  
  227.     /* 080935 cour p12*/
  228.     {    TRUE,        /* sheet feed */
  229.         17,3,         /* lines/check, checks/page */
  230.         36, 35, 4,    /* pay field m/w/l */
  231.         82,11,4,     /* Date field m/w/l */
  232.         82,10,5,    /* Amount field m/w/l */
  233.         30,38,13,    /* Memo field m/w/l */
  234.         1,3,27,        /* Voucher type, m/w */
  235.         30,60,6,     /* String field m/w/l */
  236.         3,        /* lines to skip */
  237.             120             /* cols/page */       
  238.     },
  239.  
  240.  {
  241.     /* 080935 cour p12*/
  242.     {    TRUE,        /* sheet feed */
  243.         17,3,         /* lines/check, checks/page */
  244.         36, 35, 4,    /* pay field m/w/l */
  245.         82,11,4,     /* Date field m/w/l */
  246.         82,10,5,    /* Amount field m/w/l */
  247.         30,38,13,    /* Memo field m/w/l */
  248.         1,3,27,        /* Voucher type, m/w */
  249.         30,60,6,     /* String field m/w/l */
  250.         3,        /* lines to skip */
  251.             120             /* cols/page */       
  252.     },
  253.  
  254.   
  255.     /* 081004 cour p10*/
  256.     {    TRUE,        /* sheet feed */
  257.         21,1,         /* lines/check, checks/page */
  258.         5, 55, 12,    /* pay field m/w/l */
  259.         49,11,10,     /* Date field m/w/l */
  260.         66,9,10,    /* Amount field m/w/l */
  261.         2,40,17,    /* Memo field m/w/l */
  262.         3,0,0,        /* Voucher type, m/w */
  263.         7,65,7,     /* String field m/w/l */
  264.         3,        /* lines to skip */
  265.             80              /* cols/page */
  266.     },
  267.  
  268.     /* 081013 cour p10*/
  269.     {    TRUE,        /* sheet feed */
  270.         21,1,         /* lines/check, checks/page */
  271.         5, 45, 13,    /* pay field m/w/l */
  272.         50,11,7,     /* Date field m/w/l */
  273.         67,9,7,        /* Amount field m/w/l */
  274.         1,40,17,    /* Memo field m/w/l */
  275.         2,0,0,        /* Voucher type, m/w */
  276.         5,70,10,     /* String field m/w/l */
  277.         3,        /* lines to skip */
  278.             80              /* cols/page */
  279.  
  280.     },
  281.  
  282.       
  283.     /* 081064 cour p10*/
  284.     {    TRUE,        /* sheet feed */
  285.         21,1,         /* lines/check, checks/page */
  286.         8, 55, 8,    /* pay field m/w/l */
  287.         66,11,6,     /* Date field m/w/l */
  288.         66,9,8,        /* Amount field m/w/l */
  289.         6,35,16,    /* Memo field m/w/l */
  290.         3,0,0,        /* Voucher type, m/w */
  291.         1,70,10,     /* String field m/w/l */
  292.         3,        /* lines to skip */
  293.             80              /* cols/page */
  294.     },
  295.  
  296.     /* 081065 cour p10*/
  297.     {    TRUE,        /* sheet feed */
  298.         21,1,         /* lines/check, checks/page */
  299.         5, 55, 12,    /* pay field m/w/l */
  300.         49,11,6,     /* Date field m/w/l */
  301.         66,9,6,        /* Amount field m/w/l */
  302.         2,40,17,    /* Memo field m/w/l */
  303.         3,0,0,        /* Voucher type, m/w */
  304.         5,65,8,     /* String field m/w/l */
  305.         3,        /* lines to skip */
  306.             80              /* cols/page */
  307.     },
  308.  
  309.     /* 081098 cour p10*/
  310.     {    TRUE,        /* sheet feed */
  311.         21,1,         /* lines/check, checks/page */
  312.         5, 45, 14,    /* pay field m/w/l */
  313.         55,11,6,     /* Date field m/w/l */
  314.         67,9,6,        /* Amount field m/w/l */
  315.         1,40,17,    /* Memo field m/w/l */
  316.         2,0,0,        /* Voucher type, m/w */
  317.         5,70,10,     /* String field m/w/l */
  318.         3,        /* lines to skip */
  319.          80              /* cols/page */      
  320.     },
  321.  
  322.  
  323.     /* 081123 cour p10*/
  324.     {    TRUE,        /* sheet feed */
  325.         21,1,         /* lines/check, checks/page */
  326.         5, 50, 14,    /* pay field m/w/l */
  327.         66,11,5,     /* Date field m/w/l */
  328.         66,9,8,        /* Amount field m/w/l */
  329.         1,40,17,    /* Memo field m/w/l */
  330.         3,0,0,        /* Voucher type, m/w */
  331.         5,65,9,     /* String field m/w/l */
  332.         3,        /* lines to skip */
  333.             80              /* cols/page */
  334.     },
  335.  
  336.  
  337.     /* * * line printers * * */
  338.  
  339.      /* 091098 cour p10*/
  340.     {    FALSE,        /* sheet feed */
  341.         21,1,         /* lines/check, checks/page */
  342.         5, 50, 14,    /* pay field m/w/l */
  343.         53,11,6,     /* Date field m/w/l */
  344.         66,9,6,        /* Amount field m/w/l */
  345.         2,40,17,    /* Memo field m/w/l */
  346.         4,0,0,        /* Voucher type, m/w */
  347.         5,65,10,     /* String field m/w/l */
  348.         2,        /* lines to skip */
  349.             80              /* cols/page */
  350.     },
  351.  
  352.      /* 091064 cour p10*/
  353.     {    FALSE,        /* sheet feed */
  354.         21,1,         /* lines/check, checks/page */
  355.         7, 55, 8,    /* pay field m/w/l */
  356.         66,11,5,     /* Date field m/w/l */
  357.         66,12,8,    /* Amount field m/w/l */
  358.         4,35,17,    /* Memo field m/w/l */
  359.         0,0,0,        /* Voucher type, m/w */
  360.         1,65,10,     /* String field m/w/l */
  361.         2,        /* lines to skip */
  362.             80              /* cols/page */
  363.     },
  364.      /* 090935 cour p12*/
  365.     {    FALSE,        /* sheet feed */
  366.         17,1,         /* lines/check, checks/page */
  367.         36, 35, 4,    /* pay field m/w/l */
  368.         83,11,4,     /* Date field m/w/l */
  369.         83,10,5,    /* Amount field m/w/l */
  370.         28,30,13,    /* Memo field m/w/l */
  371.         1,3,27,        /* Voucher type, m/w */
  372.         30,60,6,     /* String field m/w/l */
  373.         3,        /* lines to skip */
  374.             95              /* cols/page */
  375.     },
  376.  }
  377. };
  378.  
  379. char daysinmonth[12] = {31,29,31,30,31,30,31,31,30,31,30,31};
  380. char easymonths[12][4] = {
  381.     "Jan",
  382.     "Feb",
  383.     "Mar",
  384.     "Apr",
  385.     "May",
  386.     "Jun",
  387.     "Jul",
  388.     "Aug",
  389.     "Sep",
  390.     "Oct",
  391.     "Nov",
  392.     "Dec",
  393. };
  394.  
  395.  
  396. reportSetting reportControl;
  397. searchState searchControl;
  398. filterSetting filterControl;
  399.  
  400. /*
  401.  * prototypes
  402.  */
  403. BOOL DataLeapYear(LONG);
  404. BOOL DataStrSet(char *, char *);
  405. void DataSortInit(void);
  406. BOOL DataSortLevel(filterNode *, filterNode **, filterNode **, sortNode *);
  407. void DataReplaceEntryCats(struct List *);
  408. void DataReplaceTempCats(struct List *);
  409. editCatNode *DataLocateCat(struct List *, char *);
  410. BOOL DataSearchMatch(filterNode *, searchState *);
  411. void DataInitBalances(void);
  412. BOOL DataDateRange(entryNode *, filterSetting *);
  413. int DataWriteEntry(int,entryNode *);
  414. void DataExtractDate(dateType *, char *out);
  415. void DataCreateDate(dateType *, char *out, BOOL year);
  416. BOOL DataVerifyDateDec12(char *instr, char *newstr);
  417. BOOL DataVerifyDate12Dec(char *instr, char *newstr);
  418. BOOL DataVerifyDateMMDDYY(char *instr, char *newstr);
  419. BOOL DataVerifyDateDDMMYY(char *instr, char *newstr);
  420. int DataWriteTemplate(int fd, templateNode *temp);
  421.  
  422.  
  423. /****************************************************
  424. * DataListInit()
  425. *
  426. *  Initialize lists
  427. ****************************************************/
  428. void DataListInit(void)
  429. {
  430.  NewList(&grouplist);
  431.  NewList((struct List *)&entries);
  432.  NewList((struct List *)&filtered);
  433.  NewList(&templates);
  434.  NewList(&categories);
  435.  NewList(&testtemps);
  436.  NewList(&sortfields);
  437.  NewList(&memolist);
  438.  NewList(&datelist);
  439.  NewList(&namelist);
  440.  NewList(&amntlist);
  441. }
  442.  
  443. /****************************************************
  444. * DataInit()
  445. *
  446. *    Initialize the lists, create default templates
  447. *****************************************************/
  448. BOOL DataInit(void)
  449. {
  450.  time_t t;
  451.  struct tm *pt;
  452.  templateNode temp;
  453.  categoryNode cat;
  454.  amountType defamount = 0;
  455.  int x;
  456.  
  457.  /*
  458.   * install default templates
  459.   */
  460.  memset(&temp, 0, sizeof(templateNode));
  461.  
  462.  strcpy(temp.tempname,"Check"); 
  463.  strcpy(temp.template.category,"None");
  464.  temp.template.type=CHECKTYPE; 
  465.  DataAddTemp(&templates, &temp); 
  466.  
  467.  strcpy(temp.tempname,"Withdrawal"); 
  468.  strcpy(temp.template.category,"None");
  469.  temp.template.type=WITHDRAWALTYPE; 
  470.  DataAddTemp(&templates, &temp);
  471.  
  472.  strcpy(temp.tempname,"Deposit");
  473.  strcpy(temp.template.category,"None");
  474.  temp.template.type=DEPOSITTYPE; 
  475.  DataAddTemp(&templates,&temp); 
  476.  
  477.  strcpy(temp.tempname,"Script");
  478.  strcpy(temp.template.category,"None");
  479.  temp.template.type=SCRIPTTYPE; 
  480.  DataAddTemp(&templates, &temp); 
  481.  
  482.  /*
  483.   * install default categories
  484.   */
  485.  memset(&cat, 0, sizeof(categoryNode));
  486.  
  487.  strcpy(cat.catname,"None");
  488.  DataAddCat(&categories,&cat);
  489.  
  490.  /*
  491.   * other globals
  492.   */
  493.  amntState.currTemplate = 0;
  494.  amntState.currCheckNumber = 1;
  495.  
  496.  /* get century */
  497.  time (&t);
  498.  pt=localtime(&t);
  499.  currDate.day = pt->tm_mday;
  500.  currDate.month = pt->tm_mon + 1;
  501.  currDate.year = pt->tm_year + 1900;
  502.  currCentury = 1900 + (pt->tm_year/100);
  503.  
  504.  QDateAdd(&currDate);
  505.  
  506.  entryCount = 0;
  507.  
  508.  /* initialize filter to all */
  509.  memset(&filterControl,0,sizeof(filterSetting));
  510.  filterControl.checks=TRUE;
  511.  filterControl.withdrawals=TRUE;
  512.  filterControl.deposits=TRUE;
  513.  filterControl.checkfrom = filterControl.checkto = 1;
  514.  memcpy(&filterControl.dateFrom,&currDate,sizeof(dateType));
  515.  memcpy(&filterControl.dateTo,&currDate,sizeof(dateType));
  516.  
  517.  strcpy(filterControl.category,"None");
  518.  
  519.  /* initialize sort array */
  520.  DataSortInit();
  521.  memset(&sortStates,0,sizeof(sortState));
  522.  
  523.  /* initialize account */
  524.  memset(&usrAccount,0,sizeof(accntState));
  525.  usrAccount.checknumber = amntState.currCheckNumber;
  526.  memcpy(&usrAccount.openDate,&currDate,sizeof(dateType));
  527.  memcpy(&usrAccount.closeDate,&currDate,sizeof(dateType));
  528.  usrAccount.decimal = 2;
  529.  
  530.  /* initalize balance */
  531.  DataInitBal(DEPOSITTYPE,&defamount,&amntState.currAmnt);
  532.  DataInitBal(DEPOSITTYPE,&defamount,&amntState.stateAmnt);
  533.  DataInitBal(DEPOSITTYPE,&defamount,&filtAmnt);
  534.  
  535.  /* initialize search control */
  536.  memset(&searchControl,0,sizeof(searchState));
  537.  memcpy(&searchControl.searchdate,&currDate,sizeof(dateType));
  538.  searchControl.lastrow = -1;
  539.  searchControl.checknum = 1;
  540.  
  541.  memset(&reportControl,0,sizeof(reportSetting));
  542.  reportControl.rows = 66;
  543.  reportControl.cols = 80;
  544.  
  545.  
  546.  for (x=0;x<MAXMACROS;x++) {
  547.     memset(arexxMacros[x].macroname,0,20+1);
  548.     sprintf(arexxMacros[x].macroname,"<unassigned %d>",x+1);
  549.     arexxMacros[x].macrofile[0]=0;
  550.  }
  551.  
  552.  amiChangedItems = FALSE;
  553.  return (TRUE);
  554. }
  555.  
  556. /***************************************************
  557. * DataNode2Ord
  558. *
  559. *     Returns ordinal entry in list by name
  560. *
  561. ****************************************************/
  562. LONG DataNode2Ord (struct List *list, char *name)
  563. {
  564.  struct Node *result;
  565.  struct Node *temp;
  566.  LONG ord = 0;
  567.  
  568.  result = DataFindName(list,name);
  569.  
  570.  if (result == NULL) 
  571.     return (0);
  572.  
  573.  temp = list->lh_Head;
  574.  while (temp != result) {
  575.     ord++;
  576.     temp = temp->ln_Succ;
  577.  }
  578.  
  579.  return (ord);
  580. }
  581.  
  582. /***************************************************
  583. * DataOrd2Node
  584. *
  585. *     Returns Node ptr from ordinal entry
  586. ****************************************************/
  587. struct Node *DataOrd2Node(struct List *list,LONG ord)
  588. {
  589.  struct Node *temp = list->lh_Head;
  590.  LONG myord = 0;
  591.  
  592.  while (temp && myord != ord) {
  593.     myord++;
  594.     temp = temp->ln_Succ;
  595.  }
  596.  
  597.  return (temp);
  598. }
  599.  
  600. /***************************************************
  601. * DataAddCat()
  602. *
  603. *    Adds a category
  604. ****************************************************/
  605. BOOL DataAddCat(struct List *categories, categoryNode *info )
  606. {
  607.  categoryNode *temp;
  608.  
  609.     if ((temp = AllocVec(sizeof(categoryNode),MEMF_CLEAR))){
  610.  
  611.         memcpy((void *)temp,(void *)info,sizeof(categoryNode));
  612.         temp->node.ln_Type = NT_USER;
  613.         temp->node.ln_Pri = 0;
  614.         temp->node.ln_Name = temp->catname;
  615.  
  616.         AddTail(categories,(struct Node *)temp);
  617.     }
  618.     else return (FALSE);
  619.  
  620.  return (TRUE);
  621. }
  622.  
  623. /***************************************************
  624. * DataTestFilter()
  625. *
  626. *    Determine if node belongs to filter set
  627. ****************************************************/
  628. BOOL DataTestFilter(entryNode *en, filterSetting *set)
  629. {
  630.  BOOL retval = TRUE;
  631.  
  632.  /* type check - returns quickly if it can */
  633.  switch (en->type) {
  634.     case CHECKTYPE:
  635.         if (set->checks != TRUE) return (FALSE);
  636.         break;
  637.  
  638.     case WITHDRAWALTYPE:
  639.         if (set->withdrawals != TRUE) return(FALSE);
  640.         break;
  641.  
  642.     case DEPOSITTYPE:
  643.         if (set->deposits != TRUE) return(FALSE);
  644.         break;
  645.  }
  646.  
  647.  /* check range check */
  648.  if (en->type == CHECKTYPE) {
  649.      if (set->checkrange == FILTERIN) {
  650.         if (en->check < set->checkfrom || en->check > set->checkto)
  651.         return (FALSE);
  652.         
  653.      }
  654.      else  if (set->checkrange == FILTEROUT) {
  655.         if (en->check >= set->checkfrom && en->check <= set->checkto)
  656.         return (FALSE);
  657.     }
  658.  }
  659.  
  660.  /* amount range check */
  661.  if (set->amntrange == FILTERIN) {
  662.     if (en->amount < set->amountFrom || en->amount > set->amountTo) 
  663.         return (FALSE);
  664.  }
  665.  else if (set->amntrange == FILTEROUT) {
  666.     if (en->amount >= set->amountFrom && en->amount <= set->amountTo)
  667.         return (FALSE);
  668.  }
  669.  
  670.  /* date range check */
  671.  if (set->daterange == FILTERIN && DataDateRange(en,set) == FALSE)
  672.     return (FALSE);
  673.  
  674.  else if (set->daterange == FILTEROUT && DataDateRange(en,set) == TRUE) 
  675.     return (FALSE);
  676.  
  677.  
  678.  /* category check */
  679.  if (set->usecategory == FILTERIN) {
  680.     if (strcmpi(set->category, en->category) != 0)
  681.         return (FALSE);
  682.  }
  683.  else if (set->usecategory == FILTEROUT) {
  684.     if (strcmpi(set->category, en->category) == 0)
  685.         return (FALSE);
  686.  }
  687.     
  688.  
  689.  /* set operations */
  690.  if ( (en->flags & set->andflag) != set->andflag)
  691.     return (FALSE);
  692.  
  693.  if ( (en->flags & set->notflag) != 0)
  694.     return (FALSE);
  695.  
  696.  /* payee check  */
  697.  if (set->usepayee == FILTERIN ) {
  698.     if ( !MatchPatternNoCase(set->payeetoken, en->name) )
  699.         return (FALSE);
  700.  }
  701.  else if (set->usepayee == FILTEROUT) {
  702.     if (MatchPatternNoCase(set->payeetoken,en->name) )
  703.         return (FALSE);
  704.  }
  705.  
  706.  /* memo check */
  707.  if (set->usememo == FILTERIN) {
  708.     if (!MatchPatternNoCase(set->memotoken, en->memo) )
  709.         return (FALSE);
  710.  }
  711.  else if (set->usememo == FILTEROUT) {
  712.     if (MatchPatternNoCase(set->memotoken,en->memo) )
  713.         return (FALSE);
  714.  }
  715.  
  716.   return (retval);
  717. }
  718.  
  719. /*************************************************
  720. * DataDateRange()
  721. *
  722. *    Range for dates
  723. **************************************************/
  724. BOOL DataDateRange(entryNode *en, filterSetting *set)
  725. {
  726. /* check years */
  727. if( en->date.year < set->dateFrom.year || en->date.year > set->dateTo.year)
  728.     return (FALSE);
  729.  
  730. /* check months */
  731. if (en->date.year == set->dateFrom.year && en->date.month < set->dateFrom.month)
  732.     return (FALSE);
  733.  
  734. if (en->date.year == set->dateTo.year && en->date.month > set->dateTo.month)
  735.     return (FALSE);
  736.  
  737. /* check days */
  738. if (en->date.year == set->dateFrom.year && en->date.month == set->dateFrom.month &&
  739.     en->date.day < set->dateFrom.day)
  740.     return (FALSE);
  741.  
  742. if (en->date.year == set->dateTo.year && en->date.month == set->dateTo.month &&
  743.     en->date.day > set->dateTo.day)
  744.     return (FALSE);
  745.  
  746. return (TRUE);
  747. }
  748.  
  749. /***************************************************
  750. * DataRemoveEntry()
  751. *
  752. *    removes an entry from the list
  753. ****************************************************/
  754. void DataRemoveEntry(entryNode *info, filterNode *filt)
  755. {
  756.  DataRemoveFilter(filt);
  757.  Remove((struct Node *)info);
  758.  FreeVec(info);
  759. }
  760.  
  761. /***************************************************
  762. * DataRemoveFilter()
  763. *
  764. * Removes supplied filter 
  765. ***************************************************/
  766. void DataRemoveFilter(filterNode *filt)
  767. {
  768.  if (filt == NULL)
  769.     return;
  770.  
  771.  entryCount--;
  772.  Remove((struct Node *)filt);
  773.  FreeVec(filt);
  774. }
  775.  
  776. /***************************************************
  777. * DataRemoveEntryFilter()
  778. *
  779. *    Removes a filter based on the node 
  780. ****************************************************/
  781. void DataRemoveEntryFilter(entryNode *node)
  782. {
  783.  filterNode *filt = (filterNode *)filtered.mlh_Head;
  784.  
  785.  /* is this an empty list? */
  786.  if (filtered.mlh_TailPred == &filtered)
  787.     return;
  788.  
  789.  /* locate filter */
  790.  while (filt->node.mln_Succ != NULL) {
  791.     if (filt->entry == node) {
  792.         DataRemoveFilter(filt);
  793.         break;
  794.     }
  795.  
  796.     filt = (filterNode *)filt->node.mln_Succ;
  797.  }
  798.  
  799. }
  800.  
  801. /***************************************************
  802. * DataInsertFilter()
  803. *
  804. *    Add a filter node
  805. ****************************************************/
  806. BOOL DataInsertFilter(filterNode *fparent,filterNode **ret, 
  807.             entryNode *join, struct MinList *filtered)
  808. {
  809.  int x;
  810.  filterNode *temp;
  811.  
  812.  *ret = NULL;
  813.  
  814.     if ((temp = AllocVec(sizeof(filterNode),MEMF_CLEAR))){
  815.  
  816.         temp->entry = join;
  817.     
  818.         for (x=0;x<4;x++)
  819.             temp->printChars[x]= -1;    
  820.  
  821.         Insert((struct List *)filtered,(struct Node *)temp, (struct Node *)fparent);        
  822.     }
  823.     else return (FALSE);
  824.  
  825.  *ret = temp;
  826.  return (TRUE);
  827. }
  828.  
  829. /***************************************************
  830. * DataInsertEntry()
  831. *
  832. *    Add a transaction to proper place
  833. ****************************************************/
  834. BOOL DataInsertEntry(filterNode *fparent, entryNode *eparent,
  835.     entryNode *info, struct MinList *entrylist, filterNode **filt, 
  836.     entryNode **entry)
  837. {
  838.   entryNode *temp;
  839.  
  840.   *filt = NULL;
  841.   *entry = NULL;
  842.  
  843.     if ((temp = AllocVec(sizeof(entryNode),MEMF_CLEAR))){
  844.  
  845.         memcpy((void *)temp,(void *)info,sizeof(entryNode));
  846.         Insert((struct List *)entrylist,(struct Node *)temp, 
  847.             (struct Node *)eparent);
  848.         *entry = temp;
  849.     }
  850.     else return (FALSE);
  851.  
  852.  /* filter it */
  853.  if (DataTestFilter(temp, &filterControl) == TRUE)
  854.     DataInsertFilter(fparent,filt,temp,&filtered);
  855.  
  856.  return (TRUE);
  857. }
  858.  
  859.  
  860. /***************************************************
  861. * DataAddEntry()
  862. *
  863. *    Add a transaction
  864. ****************************************************/
  865. BOOL DataAddEntry(entryNode *info, struct MinList *entrylist, filterNode **filt)
  866. {
  867.   entryNode *temp;
  868.  
  869.  *filt = NULL;
  870.  
  871.  if ((temp = AllocVec(sizeof(entryNode),MEMF_CLEAR))){
  872.  
  873.     memcpy((void *)temp,(void *)info,sizeof(entryNode));
  874.     AddTail((struct List *)entrylist,(struct Node *)temp);        
  875.  }
  876.  else return (FALSE);
  877.  
  878.  /* filter it */
  879.  if (DataTestFilter(temp, &filterControl) == TRUE)
  880.     DataAddFilter(filt,temp,&filtered);
  881.  
  882.  return (TRUE);
  883.  
  884. }
  885.  
  886. /***************************************************
  887. * DataAddTemp()
  888. *
  889. *    Adds a template
  890. ****************************************************/
  891. BOOL DataAddTemp(struct List *templist, templateNode *info)
  892. {
  893.  templateNode *temp;
  894.  
  895.     if ((temp = AllocVec(sizeof(templateNode),MEMF_CLEAR))){
  896.  
  897.         memcpy((void *)temp,(void *)info,sizeof(templateNode));
  898.         temp->node.ln_Type = NT_USER;
  899.         temp->node.ln_Pri = 0;
  900.         temp->node.ln_Name = temp->tempname;
  901.         AddTail(templist,(struct Node *)temp);        
  902.     }
  903.     else return (FALSE);
  904.  
  905.  return (TRUE);
  906. }
  907.  
  908. /***************************************************
  909. * DataAddFilter()
  910. *
  911. *    Add a filter node
  912. ****************************************************/
  913. BOOL DataAddFilter(filterNode **ret, entryNode *join, struct MinList *filtered)
  914. {
  915.  int x;
  916.  filterNode *temp;
  917.  
  918.  *ret = NULL;
  919.  
  920.     if ((temp = AllocVec(sizeof(filterNode),MEMF_CLEAR))){
  921.  
  922.         temp->entry = join;
  923.     
  924.         for (x=0;x<4;x++)
  925.             temp->printChars[x]= -1;    
  926.  
  927.         AddTail((struct List *)filtered,(struct Node *)temp);        
  928.     }
  929.     else return (FALSE);
  930.  
  931.  *ret = temp;
  932.  return (TRUE);
  933.  
  934. }
  935.  
  936. /*****************************************************
  937. * DataFreeAll()
  938. *
  939. *    Free all database allocations
  940. *****************************************************/
  941. void DataFreeAll(void)
  942. {
  943.   DataFreeList((struct List *)&entries);
  944.   DataFreeList((struct List *)&templates);
  945.   DataFreeList((struct List *)&filtered);
  946.   DataFreeList((struct List *)&categories);
  947.   DataFreeGroupCats((struct List *)&grouplist);
  948.   DataFreeList((struct List *)&grouplist);
  949.   DataFreeList((struct List *)&datelist);
  950.   DataFreeList((struct List *)&memolist);
  951.   DataFreeList((struct List *)&namelist);
  952.   DataFreeList((struct List *)&amntlist);
  953. }
  954.  
  955. /****************************************************
  956. * DataStoreAmnt()
  957. *
  958. *    Takes the user string and stores it in a template
  959. *****************************************************/
  960. void DataStoreAmnt(amountType *amount, char *str)
  961. {
  962.  ULONG d=0,c=0;
  963.  
  964.  if (*str == NULL)
  965.     *amount = 0;
  966.  else {
  967.      /* later we will add "DataExtractAmount" */
  968.     if (usrAccount.decimal)
  969.          sscanf(str,"%u.%u",&d,&c);
  970.     else    sscanf(str,"%u",&d);
  971.  
  972.      *amount = (d*decimalModulos[usrAccount.decimal]) + c;
  973.  }
  974. }
  975.  
  976. /***************************************************
  977. * DataStoreDate()
  978. *
  979. *    Stores date into string
  980. ****************************************************/
  981. void DataStoreDate (dateType *date, char *str)
  982. {
  983.  DataExtractDate(date,str);
  984. }
  985.  
  986. /****************************************************
  987. * DataBuildRegDate()
  988. *
  989. *    Builds the reduced date for the register
  990. *****************************************************/
  991. void DataBuildRegDate(dateType *date, char *str)
  992. {
  993.  DataCreateDate(date,str,TRUE);
  994. }
  995.  
  996. /****************************************************
  997. * DataBuildDate()
  998. *
  999. *    Builds string from node of date
  1000. *****************************************************/
  1001. void DataBuildDate (dateType *date, char *str)
  1002.  DataCreateDate(date,str,FALSE);
  1003. }
  1004.  
  1005. /****************************************************
  1006. * DataBuildAmnt()
  1007. *
  1008. *    Routine to build a string from amnt
  1009. *****************************************************/
  1010. void DataBuildAmnt(BOOL zero, amountType *amount, char *str)
  1011. {
  1012.  if (zero != TRUE && *amount == 0)
  1013.     str[0]=0;
  1014.  else {
  1015.     sprintf(str,
  1016.         decimalFormat[usrAccount.decimal],
  1017.         (*amount/decimalModulos[usrAccount.decimal]),
  1018.         (*amount%decimalModulos[usrAccount.decimal]) 
  1019.         );
  1020.  }
  1021. }
  1022.  
  1023. /****************************************************
  1024. * DataBuildBal()
  1025. *
  1026. *    Routine to build a string from balance
  1027. *****************************************************/
  1028. void DataBuildBal(UBYTE decimal, balanceType *bal, char *str)
  1029. {
  1030. char negval = ' ';
  1031.  
  1032.  if (bal->neg) 
  1033.     negval = '-';
  1034.     
  1035.  sprintf(str,"%c",negval);
  1036.  str++;
  1037.     
  1038.  /* again, eventually we will do a createamount */
  1039.  sprintf(str,decimalFormat[decimal],bal->dollar,bal->cent);
  1040. }
  1041.  
  1042. /*******************************************************
  1043. * DataMoveList()
  1044. *
  1045. *    Accept new list as new original list.
  1046. ********************************************************/
  1047. void DataMoveList(struct List *src, struct List *dest)
  1048. {
  1049.  DataFreeList(dest);
  1050.  memcpy(dest,src,sizeof(struct List));
  1051.  
  1052.  dest->lh_Head->ln_Pred = (struct Node *)&(dest->lh_Head);
  1053.  dest->lh_TailPred->ln_Succ = (struct Node *)&(dest->lh_Tail);
  1054.  
  1055.  /* zap out original */
  1056.  NewList(src);
  1057. }
  1058.  
  1059. /*******************************************************
  1060. * DataIsUnique()
  1061. *
  1062. *    Takes any list and replies if an entry is
  1063. *    unique by name.  Boolean option opens
  1064. *    requestor notifying user with custon strings.
  1065. ********************************************************/
  1066. BOOL DataIsUnique(GUIFront *gui, struct List *lst, char *name, BOOL req,
  1067.         char *reqstr)
  1068. {
  1069.  struct Window *win = NULL;
  1070.  struct EasyStruct es;
  1071.  
  1072.  if (strlen(name) > 0 && DataFindName(lst,name) == NULL)
  1073.     return (TRUE);
  1074.  
  1075.  /* oh no, notify user */
  1076.  if (req == TRUE) {
  1077.     GF_GetGUIAttr(gui,
  1078.         GUI_Window,&win,
  1079.         TAG_DONE);
  1080.  
  1081.     DisplayBeep(win->WScreen);
  1082.     if (win != NULL) {
  1083.         es.es_StructSize = sizeof(struct EasyStruct);
  1084.         es.es_Flags = 0;
  1085.         es.es_Title = "amiCheck NOTICE:";
  1086.         es.es_TextFormat = reqstr;
  1087.         es.es_GadgetFormat = "OK";
  1088.         GF_LockGUI(gui);
  1089.         GF_EasyRequest(gui,win,&es,NULL);
  1090.         GF_UnlockGUI(gui);
  1091.     }
  1092.  }
  1093.  
  1094.  return (FALSE);
  1095. }
  1096.  
  1097. /*****************************************************************
  1098. * DataVerifyAmnt()
  1099. *
  1100. *     Force valid entry of amount strings
  1101. ******************************************************************/
  1102. BOOL DataVerifyAmnt(char *instr,char *newstr)
  1103. {
  1104. amountType amnt = 0;
  1105. char *dot1, *dot2, *str, *skip;
  1106. ULONG x=0,y=0,temp;
  1107. char amnthold[AMNTSIZE+1];
  1108.  
  1109.  *newstr = NULL;
  1110.  amnthold[AMNTSIZE]=NULL;
  1111.  strcpy(amnthold,instr);
  1112.  str = amnthold;
  1113.  
  1114.  /* something odd in there? */
  1115.  if (str == NULL)
  1116.     return (FALSE);
  1117.  
  1118.  /* clip spaces off front and end */
  1119.  while (*str == ' ') str++;
  1120.  skip = &amnthold[strlen(amnthold) - 1];
  1121.  while (*skip == ' ' && skip != str) {
  1122.     *skip = NULL;
  1123.     skip--;
  1124.  }
  1125.  
  1126.  if (DataStrSet(str,"0123456789. ") == FALSE) {
  1127.         return (FALSE);
  1128.  }
  1129.  
  1130.  /* grab decimal point if one */
  1131.  dot1 = strchr(str,'.');
  1132.  if (dot1 != NULL) {
  1133.  
  1134.     /* more than two decimal places? */
  1135.     dot2 = dot1+1;
  1136.     temp = strlen(dot2);
  1137.     if (temp > usrAccount.decimal) 
  1138.         return (FALSE);
  1139.     
  1140.     /* pull out data into integers */
  1141.     if (dot1 == str) 
  1142.          sscanf(str,".%u",&y);
  1143.     else sscanf(str,"%u.%u",&x,&y);
  1144.  
  1145.     /* adjust for ".5 -> .50" */
  1146.     if (temp < usrAccount.decimal)
  1147.         y *= decimalModulos[usrAccount.decimal-temp];
  1148.  
  1149.     /* another period? */
  1150.     dot2 = strchr(dot2,'.');
  1151.     if (dot2 != NULL) {
  1152.         return (FALSE);
  1153.     }
  1154.  }
  1155.  else sscanf(str,"%u",&x);
  1156.  
  1157.  /* build new string */
  1158.  amnt = (x*decimalModulos[usrAccount.decimal]) + y;
  1159.  DataBuildAmnt(FALSE,&amnt,newstr);
  1160.  
  1161.  return (TRUE);
  1162. }
  1163.  
  1164. /****************************************************************
  1165. * DataVerifyDate()
  1166. *
  1167. *    Verifies and builds date string
  1168. ****************************************************************/
  1169. BOOL DataVerifyDate(char *instr, char *newstr)
  1170. {
  1171. BOOL retval;
  1172.  
  1173. switch (dateFormat) {
  1174.     case DATE_MMDDYY:
  1175.         retval = DataVerifyDateMMDDYY(instr,newstr);
  1176.         break;
  1177.     case DATE_DDMMYY:
  1178.         retval = DataVerifyDateDDMMYY(instr,newstr);
  1179.         break;
  1180.     case DATE_DEC_12:
  1181.         retval = DataVerifyDateDec12(instr,newstr);
  1182.         break;
  1183.     case DATE_12_DEC:
  1184.         retval = DataVerifyDate12Dec(instr,newstr);
  1185.         break;
  1186. }
  1187.  
  1188. return (retval);
  1189. }
  1190.  
  1191. /********************************************************************
  1192. * DataLeapYear()
  1193. *
  1194. *     TRUE if year is leap year
  1195. *********************************************************************/
  1196. BOOL DataLeapYear(LONG year)
  1197. {
  1198.  
  1199.  /* quick /4 check for now */
  1200.  if ( year%4 || !(year%100) )
  1201.     return (FALSE);
  1202.  
  1203.  return (TRUE);
  1204. }
  1205.  
  1206.  
  1207. /*******************************************************************
  1208. * DataAnnounce()
  1209. *
  1210. *    Announce message to user
  1211. *******************************************************************/
  1212. void DataAnnounce(GUIFront *gui, char *str)
  1213. {
  1214.  struct Window *win = NULL;
  1215.  struct EasyStruct es;
  1216.  
  1217.  if (str == NULL)
  1218.     return;
  1219.  
  1220.  /* oh no, notify user */
  1221.  GF_GetGUIAttr(gui,
  1222.     GUI_Window,&win,
  1223.     TAG_DONE);
  1224.  
  1225.  if (win != NULL) {
  1226.     es.es_StructSize = sizeof(struct EasyStruct);
  1227.     es.es_Flags = 0;
  1228.     es.es_Title = "amiCheck NOTICE:";
  1229.     es.es_TextFormat = str;
  1230.     es.es_GadgetFormat = "OK";
  1231.     GF_LockGUI(gui);
  1232.     GF_EasyRequest(gui,win,&es,NULL);
  1233.     GF_UnlockGUI(gui);
  1234.  }
  1235. }
  1236.  
  1237. /*******************************************************************
  1238. * DataQuery()
  1239. *
  1240. *    Query from  user
  1241. *******************************************************************/
  1242. int DataQuery(GUIFront *gui, char *str, char *query)
  1243. {
  1244.  struct Window *win = NULL;
  1245.  struct EasyStruct es;
  1246.  int val = 0;
  1247.  
  1248.  if (str == NULL)
  1249.     return (val);
  1250.  
  1251.  /* oh no, notify user */
  1252.  GF_GetGUIAttr(gui,
  1253.     GUI_Window,&win,
  1254.     TAG_DONE);
  1255.  
  1256.  if (win != NULL) {
  1257.     es.es_StructSize = sizeof(struct EasyStruct);
  1258.     es.es_Flags = 0;
  1259.     es.es_Title = "amiCheck NOTICE:";
  1260.     es.es_TextFormat = str;
  1261.     es.es_GadgetFormat = query;
  1262.     GF_LockGUI(gui);
  1263.     val = GF_EasyRequest(gui,win,&es,NULL);
  1264.     GF_UnlockGUI(gui);
  1265.  }
  1266.  
  1267.  return (val);
  1268. }
  1269.  
  1270. /**************************************************************
  1271. * DataStrSet ()
  1272. *
  1273. *    SAS/C strcspn replacement
  1274. **************************************************************/
  1275. BOOL DataStrSet(char *src, char *input)
  1276. {
  1277.  WORD a,b;
  1278.  BOOL found;
  1279.  
  1280.  for (a=0;a<strlen(src);a++) {
  1281.     found = FALSE;
  1282.     for (b=0;b<strlen(input);b++) {
  1283.         if (src[a] == input[b]) {
  1284.             found = TRUE;
  1285.             break;
  1286.         }
  1287.     }
  1288.     if (found == FALSE)
  1289.         return (FALSE);
  1290.  }
  1291.  
  1292.  return (TRUE);
  1293. }
  1294.  
  1295. /********************************************************
  1296. * DataUpdateFilters()
  1297. *
  1298. *    Updates the filtered items to the filter criteria
  1299. *    (not all transactions, for SPEED :)
  1300. ********************************************************/
  1301. void DataUpdateFilters(struct MinList *filtered)
  1302. {
  1303.  filterNode *work, *next;
  1304.  
  1305.  if ((struct Node *)(filtered->mlh_TailPred) == (struct Node *)filtered)
  1306.     return;
  1307.  
  1308.  work = (filterNode *)(filtered->mlh_Head);
  1309.  while (next = (filterNode *)(work->node.mln_Succ)) {
  1310.     if (!DataTestFilter(work->entry,&filterControl)) 
  1311.             DataRemoveFilter(work);
  1312.     
  1313.     work = next;
  1314.  } 
  1315. }
  1316.  
  1317. /********************************************************
  1318. * DataBalConvert()
  1319. *
  1320. *    Converts a balance from one decimal format to
  1321. *    another (some data loss possible)
  1322. *********************************************************/
  1323. void DataBalConvert(balanceType *bal, UBYTE from, UBYTE to)
  1324. {
  1325.  UWORD diff;
  1326.  
  1327.  if (from == to)
  1328.     return;
  1329.  
  1330.  if (from > to) {
  1331.     diff = decimalModulos[from - to];
  1332.     bal->cent /= diff;
  1333.  }
  1334.  else    {
  1335.     diff = decimalModulos[to-from];
  1336.     bal->cent *= diff;
  1337.  }
  1338. }
  1339.  
  1340. /********************************************************
  1341. * DataBalToAmnt()
  1342. *
  1343. *    Converts a balance to standard amount type
  1344. *********************************************************/
  1345. void DataBalToAmnt(balanceType *bal, UBYTE *type, amountType *amount)
  1346. {
  1347.  if (bal->neg)
  1348.     *type = WITHDRAWALTYPE;
  1349.  else    *type = DEPOSITTYPE;
  1350.  
  1351.  *amount = (bal->dollar * decimalModulos[usrAccount.decimal]) +
  1352.         bal->cent;
  1353. }
  1354.  
  1355. /********************************************************
  1356. * DataUpdateBal()
  1357. *
  1358. *    Updates a balance, supply string. Decimal assumed
  1359. *    from account setting
  1360. *********************************************************/
  1361. void DataUpdateBal(UBYTE type, amountType *amount, balanceType *bal, char *str)
  1362. {
  1363.  DataAddBal(type, amount, bal);
  1364.  DataBuildBal(usrAccount.decimal,bal,str);
  1365. }
  1366.  
  1367. /********************************************************
  1368. * DataAddBal()
  1369. *
  1370. *    Updates a balance. Decimal assumed
  1371. *    from account setting
  1372. *********************************************************/
  1373. void DataAddBal(UBYTE type, amountType *amount, balanceType *bal)
  1374. {
  1375.  balanceType amntBal;
  1376.  
  1377.  DataInitBal(type, amount, &amntBal);
  1378.  DataBalAddBal(usrAccount.decimal,bal,&amntBal,bal);
  1379. }
  1380.  
  1381. /********************************************************
  1382. * DataBalAddBal()
  1383. *
  1384. *    Adds two balances.
  1385. *********************************************************/
  1386. void DataBalAddBal(UBYTE decimal,balanceType *dest, 
  1387.     balanceType *bal1, balanceType *bal2)
  1388. {
  1389.  balanceType b1, b2;
  1390.  memcpy(&b1,bal1,sizeof(balanceType));
  1391.  memcpy(&b2,bal2, sizeof(balanceType));
  1392.  
  1393.  /* now we need to look at the two balances efficiently */
  1394.  
  1395.  /* - + + */
  1396.  if (b2.neg && !b1.neg) {
  1397.     /* bal is greater or equal to */
  1398.     if ( (b1.dollar > b2.dollar) ||
  1399.          (b1.dollar == b2.dollar && b1.cent >= b2.cent)) {
  1400.             
  1401.         /* borrow if needed */
  1402.         if (b1.cent < b2.cent) {
  1403.             b1.dollar--;
  1404.             b1.cent += decimalModulos[decimal];
  1405.         }
  1406.         b1.cent -= b2.cent;
  1407.         b1.dollar -= b2.dollar;
  1408.     } 
  1409.     /* bal just shrunk! */
  1410.     else {
  1411.         b1.neg = TRUE;
  1412.  
  1413.         /* borrow if needed */
  1414.         if (b2.cent < b1.cent) {
  1415.             b2.dollar--;
  1416.             b2.cent += decimalModulos[decimal];
  1417.         }
  1418.         b1.cent = b2.cent - b1.cent;
  1419.         b1.dollar = b2.dollar - b1.dollar;
  1420.     }
  1421.  }
  1422.  
  1423.  /* + + - */
  1424.  else if (b1.neg && !b2.neg) {
  1425.     /* bal is breater or equal to */
  1426.     if ( (b1.dollar > b2.dollar) ||
  1427.          (b1.dollar == b2.dollar && b1.cent >= b2.cent)) {
  1428.             
  1429.         /* borrow if needed */
  1430.         if (b1.cent < b2.cent) {
  1431.             b1.dollar--;
  1432.             b1.cent += decimalModulos[decimal];
  1433.         }
  1434.         b1.cent -= b2.cent;
  1435.         b1.dollar -= b2.dollar;
  1436.     } 
  1437.     /* bal just shrunk! */
  1438.     else {
  1439.         b1.neg = FALSE;
  1440.  
  1441.         /* borrow if needed */
  1442.         if (b2.cent < b1.cent) {
  1443.             b2.dollar--;
  1444.             b2.cent += decimalModulos[decimal];
  1445.         }
  1446.         b1.cent = b2.cent - b1.cent;
  1447.         b1.dollar = b2.dollar - b1.dollar;
  1448.     }
  1449.  }
  1450.  
  1451.  /* + + +  or - + - */
  1452.  else {
  1453.     b1.dollar += b2.dollar;
  1454.     b1.cent += b2.cent;
  1455.     if (b1.cent >= decimalModulos[decimal]) {
  1456.         b1.dollar++;
  1457.         b1.cent -= decimalModulos[decimal];
  1458.     }
  1459.  } 
  1460.  
  1461.  memcpy(dest,&b1,sizeof(balanceType));
  1462.  if (dest->dollar == 0 && dest->cent == 0)
  1463.     dest->neg = FALSE;
  1464. }
  1465.  
  1466. /********************************************************
  1467. * DataCmpAmntBal()
  1468. *
  1469. *    Compares an amount and a balance. -1 if amnt is 
  1470. *    smaller, 0 if equal and 1 if larger.  The negative
  1471. *    aspect is currently ignored.
  1472. *********************************************************/
  1473. int DataCmpAmntBal(amountType *amnt, balanceType *bal)
  1474. {
  1475.  balanceType store;
  1476.  
  1477.  DataInitBal(DEPOSITTYPE,amnt,&store);
  1478.  return (DataCmpBal(FALSE,&store,bal));
  1479. }
  1480.  
  1481. /********************************************************
  1482. * DataCmpBal()
  1483. *
  1484. *    Compares two balances. -1 if b1 is smaller, 0
  1485. *    if equal and 1 if larger.
  1486. *********************************************************/
  1487. int DataCmpBal(BOOL neg, balanceType *b1,  balanceType *b2)
  1488. {
  1489.  
  1490.  /* do we consider the negative aspect? */
  1491.  if (neg) {
  1492.     if (b1->neg && !b2->neg)
  1493.         return -1;
  1494.     else if (!b1->neg && b2->neg)
  1495.         return 1;
  1496.     else if (b1->dollar == b2->dollar && b1->cent == b2->cent)
  1497.         return 0;
  1498.     else if ( (b1->dollar > b2->dollar) || 
  1499.          (b1->dollar == b2->dollar && b1->cent > b2->cent))
  1500.         return -1;
  1501.     else return 1;
  1502.     
  1503.  }
  1504.  else {
  1505.     if (b1->dollar == b2->dollar && b1->cent == b2->cent)
  1506.         return 0;
  1507.     else if ( (b1->dollar > b2->dollar) || 
  1508.          (b1->dollar == b2->dollar && b1->cent > b2->cent))
  1509.         return 1;
  1510.     else return -1;
  1511.  }
  1512. }
  1513.  
  1514. /********************************************************
  1515. * DataInitBal()
  1516. *
  1517. *    Inits a balance with an amount.  The decimal
  1518. *    is assumed to be the current account's
  1519. *********************************************************/
  1520. void DataInitBal(UBYTE type, amountType *amount, balanceType *bal)
  1521. {
  1522.  
  1523.  bal->dollar = *amount / decimalModulos[usrAccount.decimal];
  1524.  bal->cent = *amount % decimalModulos[usrAccount.decimal];
  1525.  
  1526.  /* now make negative if necessary */
  1527.  if (type != DEPOSITTYPE)
  1528.     bal->neg = TRUE;
  1529.  else    bal->neg = FALSE;
  1530. }
  1531.  
  1532. /************************************************************
  1533. * DataRebuildFilters()
  1534. *
  1535. *    We have changed something and need to free up and
  1536. *    test _ALL_ transactions again.
  1537. *************************************************************/
  1538. void DataRebuildFilters(void)
  1539. {
  1540.  entryNode *work, *next;
  1541.  filterNode *filt;
  1542.  
  1543.  DataFreeList((struct List *)&filtered);
  1544.  
  1545.  entryCount = 0;
  1546.  if (entries.mlh_TailPred == (struct Node *)&entries)
  1547.     return;
  1548.  
  1549.  work = (entryNode *)(entries.mlh_Head);
  1550.  while (next = (entryNode *)(work->node.mln_Succ)) {
  1551.     if (DataTestFilter(work,&filterControl) == TRUE) {
  1552.         entryCount++;
  1553.         DataAddFilter(&filt, work, &filtered);
  1554.     }
  1555.     work = next;
  1556.  }
  1557. }
  1558.  
  1559. /**************************************************************
  1560. * DataSitNSpin()
  1561. *
  1562. *    Wait for window activation
  1563. ***************************************************************/
  1564. void DataSitNSpin(struct Gadget *ga, struct Window *win)
  1565. {
  1566.  BOOL done = FALSE;
  1567.  struct IntuiMessage *imsg = NULL;
  1568.  
  1569.  if (simpleRefresh == TRUE)
  1570.     return;
  1571.  
  1572.  do {
  1573.     while (imsg == NULL)
  1574.         imsg = GF_GetIMsg(guiapp);
  1575.     if (imsg->Class == IDCMP_ACTIVEWINDOW)
  1576.         done = TRUE;
  1577.     GF_ReplyIMsg(imsg);
  1578.  
  1579.  } while (!done);
  1580.  
  1581.  if (ga != NULL && win != NULL)
  1582.     ActivateGadget(ga,win,NULL);
  1583.     
  1584. }
  1585.  
  1586. /***************************************************************
  1587. * DataSortInit()
  1588. *
  1589. *    Initializes the sort field array
  1590. ****************************************************************/
  1591. void DataSortInit(void)
  1592. {
  1593.  strcpy(sortEntries[SORTCHECK].field,"Check Number");
  1594.  sortEntries[SORTCHECK].node.ln_Name = sortEntries[SORTCHECK].field;
  1595.  sortEntries[SORTCHECK].order = 0;
  1596.  sortEntries[SORTCHECK].index = SORTCHECK;
  1597.  
  1598.  strcpy(sortEntries[SORTDATE].field,"Transaction Date");
  1599.  sortEntries[SORTDATE].node.ln_Name = sortEntries[SORTDATE].field;
  1600.  sortEntries[SORTDATE].order = 0;
  1601.  sortEntries[SORTDATE].index = SORTDATE;
  1602.  
  1603.  strcpy(sortEntries[SORTAMNT].field,"Amount"); 
  1604.  sortEntries[SORTAMNT].node.ln_Name = sortEntries[SORTAMNT].field;
  1605.  sortEntries[SORTAMNT].order = 0;
  1606.  sortEntries[SORTAMNT].index = SORTAMNT;
  1607.  
  1608.  strcpy(sortEntries[SORTNAME].field,"Name Field");
  1609.  sortEntries[SORTNAME].node.ln_Name = sortEntries[SORTNAME].field;
  1610.  sortEntries[SORTNAME].order = 0;
  1611.  sortEntries[SORTNAME].index = SORTNAME;
  1612.  
  1613.  strcpy(sortEntries[SORTMEMO].field,"Memo Field");
  1614.  sortEntries[SORTMEMO].node.ln_Name = sortEntries[SORTMEMO].field;
  1615.  sortEntries[SORTMEMO].order = 0;
  1616.  sortEntries[SORTMEMO].index = SORTMEMO;
  1617.  
  1618.  strcpy(sortEntries[SORTCATEGORY].field,"Category");
  1619.  sortEntries[SORTCATEGORY].node.ln_Name = sortEntries[SORTCATEGORY].field;
  1620.  sortEntries[SORTCATEGORY].order = 0;
  1621.  sortEntries[SORTCATEGORY].index = SORTCATEGORY;
  1622. }
  1623.  
  1624. /*******************************************************
  1625. * DataMoveSort()
  1626. *
  1627. *    move a sort list from one to another
  1628. ********************************************************/
  1629. void DataMoveSort(struct List *to, sortNode *to_nodes, 
  1630.     struct List *from, sortNode *from_nodes)
  1631. {
  1632.  sortNode *node = (sortNode *)from->lh_Head;
  1633.  
  1634.  NewList(to);
  1635.  
  1636.  if (IsListEmpty(from))
  1637.     return;
  1638.  
  1639.  while (node->node.ln_Succ != NULL) {
  1640.     AddTail(to, &to_nodes[node->index]);
  1641.     node = (sortNode *)node->node.ln_Succ;
  1642.  }
  1643.  
  1644. }
  1645.  
  1646. /**********************************************************
  1647. * DataReconcile()
  1648. *
  1649. *    Reconciles the current account
  1650. ***********************************************************/
  1651. balanceType DataReconcile(BOOL mark)
  1652. {
  1653.  entryNode *next, *node = (entryNode *)entries.mlh_Head;
  1654.  balanceType curr;
  1655.  
  1656.  DataInitBal(DEPOSITTYPE,&usrAccount.beginAmount,&curr);
  1657.  
  1658.  if (entries.mlh_TailPred == &entries)
  1659.     return (curr);
  1660.  
  1661.  while ( (next = (entryNode *)node->node.mln_Succ)) {
  1662.     if ( (node->flags & CLEARED) &&  !(node->flags & VOIDED)) {
  1663.         DataAddBal(node->type, &node->amount, &curr);
  1664.         if (mark == TRUE) node->flags |= RECONCILED;
  1665.     }
  1666.  
  1667.     node = next;
  1668.  }
  1669.  
  1670.  if (mark) amntState.stateAmnt = curr;
  1671.  return (curr);
  1672. }
  1673.  
  1674. /**************************************************************
  1675. * DataSortFilter()
  1676. *
  1677. *    Sorts filter entries (recursive). Refilter before?
  1678. ****************************************************************/
  1679. void DataSortFilter(filterNode *top, filterNode *bottom, sortNode *node)
  1680. {
  1681.  BOOL swap = TRUE,done = FALSE;
  1682.  filterNode *newtop, *newbottom;
  1683.  filterNode *temptop, *temp, *tempswap;
  1684.  sortNode *next = (sortNode *)node->node.ln_Succ;
  1685.  
  1686.  /* move through each item and sort... not fast but _rhobust_ and easy */
  1687.  temptop = top;
  1688.  temp = (filterNode *)temptop->node.mln_Succ;
  1689.  while (!done) {
  1690.  
  1691.     /* place temptop node: */
  1692.     swap = FALSE;
  1693.     while (!swap && temp != NULL && temp->node.mln_Succ != NULL) {
  1694.         
  1695.         switch (node->index) {
  1696.             case SORTCHECK:
  1697.                 if (node->order == SORTASCEND) {
  1698.                     if (temptop->entry->check > temp->entry->check) 
  1699.                         swap = TRUE;
  1700.                 }
  1701.                 else {
  1702.                     if (temptop->entry->check < temp->entry->check) 
  1703.                         swap = TRUE;
  1704.                 }
  1705.                 break;
  1706.  
  1707.             case SORTDATE:
  1708.                 if (node->order == SORTASCEND) {
  1709.                     if (temptop->entry->date.year > temp->entry->date.year)
  1710.                         swap = TRUE;
  1711.                     else if (temptop->entry->date.year == temp->entry->date.year &&
  1712.                          temptop->entry->date.month > temp->entry->date.month)
  1713.                         swap = TRUE;
  1714.                     else if (temptop->entry->date.year == temp->entry->date.year &&
  1715.                          temptop->entry->date.month == temp->entry->date.month &&
  1716.                          temptop->entry->date.day > temp->entry->date.day)
  1717.                         swap = TRUE;
  1718.                 }
  1719.                 else {
  1720.                     if (temptop->entry->date.year < temp->entry->date.year)
  1721.                         swap = TRUE;
  1722.                     else if (temptop->entry->date.year == temp->entry->date.year &&
  1723.                          temptop->entry->date.month < temp->entry->date.month)
  1724.                         swap = TRUE;
  1725.                     else if (temptop->entry->date.year == temp->entry->date.year &&
  1726.                          temptop->entry->date.month == temp->entry->date.month &&
  1727.                          temptop->entry->date.day < temp->entry->date.day)
  1728.                         swap = TRUE;
  1729.                 }
  1730.                 break;
  1731.  
  1732.             case SORTAMNT:
  1733.                 if (node->order == SORTASCEND) {
  1734.                     if (temptop->entry->amount > temp->entry->amount)
  1735.                         swap = TRUE;
  1736.                 }
  1737.                 else {
  1738.                     if (temptop->entry->amount < temp->entry->amount)
  1739.                         swap = TRUE;
  1740.                 }
  1741.                 break;
  1742.  
  1743.             case SORTNAME:
  1744.                 if (node->order == SORTASCEND) {
  1745.                     if (strcmpi(temptop->entry->name,temp->entry->name) > 0)
  1746.                         swap = TRUE;
  1747.                 }
  1748.                 else {
  1749.                     if (strcmpi(temptop->entry->name,temp->entry->name) < 0)
  1750.                         swap = TRUE;
  1751.                 }
  1752.                 break;
  1753.  
  1754.             case SORTMEMO:
  1755.                 if (node->order == SORTASCEND) {
  1756.                     if (strcmpi(temptop->entry->memo,temp->entry->memo) > 0)
  1757.                         swap = TRUE;
  1758.                 }
  1759.                 else {
  1760.                     if (strcmpi(temptop->entry->memo,temp->entry->memo) < 0)
  1761.                         swap = TRUE;
  1762.                 }
  1763.                 break;
  1764.  
  1765.             case SORTCATEGORY:
  1766.                 if (node->order == SORTASCEND) {
  1767.                     if (strcmpi(temptop->entry->category,temp->entry->category) > 0)
  1768.                         swap = TRUE;
  1769.                 }
  1770.                 else {
  1771.                     if (strcmpi(temptop->entry->category,temp->entry->category) < 0)
  1772.                         swap = TRUE;
  1773.                 }
  1774.                 break;
  1775.         }
  1776.  
  1777.        /* have we scanned the sector? */
  1778.             if (temp == bottom || swap == TRUE)
  1779.         break;
  1780.  
  1781.        /* nope! move on to the next */
  1782.        temp = (filterNode *)temp->node.mln_Succ;
  1783.     }    
  1784.  
  1785.      if (swap) {
  1786.         /* we will swap temptop with temp */
  1787.  
  1788.         /* locate new parent for temptop */
  1789.         tempswap = (filterNode *)temp->node.mln_Pred;
  1790.         if (tempswap == temptop) 
  1791.             tempswap = temp;
  1792.  
  1793.         /* is this the top? */
  1794.         if (temptop == top)
  1795.             top = temp;
  1796.  
  1797.         /* is this the bottom? */
  1798.         if (temp == bottom)
  1799.             bottom = temptop;
  1800.  
  1801.         Remove((struct Node *)temp);
  1802.         Insert((struct List *)&filtered,(struct Node *)temp,(struct Node *)temptop); 
  1803.         Remove((struct Node *)temptop);
  1804.         Insert((struct List *)&filtered,(struct Node *)temptop,(struct Node *)tempswap);
  1805.  
  1806.         /* point to temp for next search */
  1807.         temptop = temp;
  1808.         temp = (filterNode *)temptop->node.mln_Succ;
  1809.     }
  1810.     else {
  1811.         /* the current item needs no movement, next! */
  1812.         if (temptop == bottom) 
  1813.             done = TRUE;
  1814.  
  1815.         else {
  1816.             temptop = (filterNode *)temptop->node.mln_Succ;
  1817.             
  1818.             /* prepare for next round of sorting */
  1819.             if (temptop == NULL || temptop == bottom || temptop->node.mln_Succ == NULL) 
  1820.                 done = TRUE;
  1821.             else temp = (filterNode *)temptop->node.mln_Succ;
  1822.         }
  1823.     }
  1824.  }
  1825.  
  1826.  /* finished, now jump to next level */
  1827.  newtop = newbottom = top;
  1828.  if (next != NULL && next->node.ln_Succ != NULL) {
  1829.  
  1830.     /* find ALL tops and bottoms of this level and sort them */
  1831.     while (    DataSortLevel(bottom,&newtop,&newbottom, node))
  1832.         DataSortFilter(newtop,newbottom,next);    
  1833.  }
  1834. }
  1835.  
  1836. /****************************************************************
  1837. * DataSortLevel()
  1838. *
  1839. *    Finds next block of sublevel entries that need sorting
  1840. *****************************************************************/
  1841. BOOL DataSortLevel(filterNode *bottom, filterNode **stop, filterNode **sbottom, sortNode *sort)
  1842. {
  1843.  BOOL retval = FALSE;
  1844.  BOOL skip = FALSE;
  1845.  UWORD skipcount = 0;
  1846.  filterNode *temptop = NULL; 
  1847.  filterNode *temp;
  1848.  
  1849.  /* are we at the top or subsequent search? */
  1850.  if (*sbottom == *stop) 
  1851.     temptop = *stop;
  1852.  else
  1853.     temptop = (filterNode *)(*sbottom)->node.mln_Succ;
  1854.  
  1855.  /* don't go any farther if this is the bottom */
  1856.  if (*sbottom == bottom || temptop == NULL || temptop == bottom || temptop->node.mln_Succ == NULL) 
  1857.     return(retval);
  1858.  
  1859.  /* scan through while level is equal */
  1860.  temp = (filterNode *)temptop->node.mln_Succ;
  1861.  while (temp != NULL && temp->node.mln_Succ != NULL) {
  1862.     skip = FALSE;
  1863.  
  1864.     /* is this node == to temptop? */
  1865.     switch (sort->index) {
  1866.         case SORTCHECK:
  1867.             if (temptop->entry->check == temp->entry->check) 
  1868.                     skip = TRUE;
  1869.             break;
  1870.  
  1871.         case SORTDATE:
  1872.             if (temptop->entry->date.year == temp->entry->date.year &&
  1873.                  temptop->entry->date.month == temp->entry->date.month &&
  1874.                  temptop->entry->date.day == temp->entry->date.day)
  1875.                     skip = TRUE;
  1876.             break;
  1877.  
  1878.         case SORTAMNT:
  1879.              if (temptop->entry->amount == temp->entry->amount)
  1880.                     skip = TRUE;
  1881.             break;
  1882.  
  1883.         case SORTNAME:
  1884.             if (strcmpi(temptop->entry->name,temp->entry->name) == 0)
  1885.                 skip = TRUE;
  1886.             break;
  1887.  
  1888.         case SORTMEMO:
  1889.             if (strcmpi(temptop->entry->memo,temp->entry->memo) == 0)
  1890.                 skip = TRUE;
  1891.             break;
  1892.  
  1893.         case SORTCATEGORY:
  1894.             if (strcmpi(temptop->entry->category,temp->entry->category) == 0)
  1895.                 skip = TRUE;
  1896.             break;
  1897.  
  1898.     }
  1899.     
  1900.     if (skip == TRUE) {
  1901.         /* yes, check next one (find whole block) */
  1902.         skipcount++;
  1903.         if (temp == bottom) {
  1904.             temp = (filterNode *)temp->node.mln_Succ;
  1905.             break;
  1906.         }
  1907.         else temp = (filterNode *)temp->node.mln_Succ;
  1908.     }
  1909.  
  1910.     else {
  1911.         /* have we captured a region? */
  1912.         if (skipcount > 0)
  1913.             break;
  1914.  
  1915.         /* move temptop down.. */
  1916.         temptop = temp;
  1917.         if (temptop == bottom || temptop == NULL) break;
  1918.         temp = (filterNode *)temptop->node.mln_Succ;
  1919.     }
  1920.  }
  1921.  
  1922.  /* ok what did we grab? */
  1923.  if (skipcount > 0) {
  1924.     temp = (filterNode *)temp->node.mln_Pred;
  1925.     retval = TRUE;
  1926.     *stop = temptop;
  1927.     *sbottom = temp;
  1928.  }
  1929.  
  1930.  return (retval);
  1931. }
  1932.  
  1933. /*************************************************************
  1934. * DataNewEditCat()
  1935. *
  1936. *    Creates a new editcat node and places it at tail
  1937. **************************************************************/
  1938. editCatNode *DataNewEditCat(struct List *el, categoryNode *cat)
  1939. {
  1940.  editCatNode *work;
  1941.  
  1942.  work = (editCatNode *)AllocVec(sizeof(editCatNode), MEMF_CLEAR);
  1943.  memcpy(&work->new,cat,sizeof(categoryNode));
  1944.  work->oldnode = FALSE;
  1945.  work->new.node.ln_Name = work->new.catname;
  1946.  AddTail((struct List *)el,(struct Node *)work);
  1947.  return (work);
  1948. }
  1949.  
  1950. /*************************************************************
  1951. * DataFreeGroupCats()
  1952. *
  1953. *    Special routine to free up group nodes
  1954. **************************************************************/
  1955. void DataFreeGroupCats(struct List *gl)
  1956. {
  1957.  groupNode *work = NULL;
  1958.  
  1959.  while ( (work = (groupNode *)DataGetNext(gl,(struct Node *)work)) != NULL) 
  1960.     DataFreeList(&work->catlist);
  1961. }
  1962.  
  1963. /*************************************************************
  1964. * DataNewGroup()
  1965. *
  1966. *    Creates a new group node and places it at tail
  1967. **************************************************************/
  1968. groupNode *DataNewGroup(struct List *gl, groupNode *grp)
  1969. {
  1970.  groupNode *work;
  1971.  
  1972.  work = (groupNode *)AllocVec(sizeof(groupNode), MEMF_CLEAR);
  1973.  memcpy(work,grp,sizeof(groupNode));
  1974.  NewList(&work->catlist);
  1975.  work->node.ln_Name = work->groupname;
  1976.  AddTail((struct List *)gl,(struct Node *)work);
  1977.  return (work);
  1978. }
  1979.  
  1980. /*************************************************************
  1981. * DataFreeList()
  1982. *
  1983. *    Special free routine for a generic list
  1984. **************************************************************/
  1985. void DataFreeList(struct List *list)
  1986. {
  1987.  struct Node *work = list->lh_Head;
  1988.  struct Node *next;
  1989.  
  1990.  if (IsListEmpty(list))
  1991.     return;
  1992.  
  1993.  while ( (next= work->ln_Succ)) {
  1994.     FreeVec(work);
  1995.     work = next;
  1996.  }
  1997.  
  1998.  NewList(list);
  1999. }
  2000.  
  2001. /**************************************************************
  2002. * DataCopyCatList()
  2003. *
  2004. *    A special copy routine for the edit cat list
  2005. **************************************************************/
  2006. void DataCopyCatList(struct List *editlist, struct List *catlist) 
  2007.  categoryNode *cat =  (categoryNode *)catlist->lh_Head;
  2008.  editCatNode *work;
  2009.  
  2010.  NewList((struct List *)editlist); 
  2011.  if (IsListEmpty(catlist))
  2012.     return;
  2013.  
  2014.  while (cat->node.ln_Succ) {
  2015.     work = (editCatNode *)AllocVec(sizeof(editCatNode), MEMF_CLEAR);
  2016.     memcpy(&work->original,cat,sizeof(categoryNode));
  2017.     memcpy(&work->new,cat,sizeof(categoryNode));
  2018.     work->oldnode = TRUE;
  2019.     work->new.node.ln_Name = work->new.catname;
  2020.     AddTail((struct List *)editlist,(struct Node *)work);
  2021.     cat = (categoryNode*)cat->node.ln_Succ;
  2022.  }
  2023. }
  2024.  
  2025. /********************************************************
  2026. * DataCopyList()
  2027. *
  2028. *    Copy a simple list from one to another
  2029. *********************************************************/
  2030. void DataCopyList(struct List *src, struct List *dest, funcptr func)
  2031. {
  2032.  struct MinNode *work = NULL;
  2033.  
  2034.  /* free up dest */
  2035.  DataFreeList(dest);
  2036.  
  2037.  while ( (work = (struct MinNode *)DataGetNext(src,(struct Node *)work)) != NULL)
  2038.     func(dest,work);
  2039. }
  2040.  
  2041. /****************************************************
  2042. * DataCopyGroupList()
  2043. *
  2044. *    Copies a group list from one list to the other
  2045.  
  2046. ******************************************************/
  2047. void DataCopyGroupList(struct List *src, struct List *dest)
  2048. {
  2049.  groupNode *new, *work = NULL;
  2050.  
  2051.  /* clean up dest */
  2052.  DataFreeGroupCats(dest);
  2053.  DataFreeList(dest);
  2054.  
  2055.  /* copy each node over */
  2056.  while ( (work = (groupNode *)DataGetNext(src,(struct Node *)work)) != NULL) {
  2057.     new = DataNewGroup(dest,work);
  2058.     DataCopyList(&work->catlist, &new->catlist, (funcptr)DataAddCat);
  2059.  }
  2060.  
  2061. }
  2062.  
  2063. /****************************************************
  2064. * DataMoveCatList()
  2065. *
  2066. *    Moves the special edit list into the original.
  2067. *    replaces ALL system wide categories with
  2068. *    their modified version or NONE if deleted.
  2069. ******************************************************/
  2070. void DataMoveCatList(struct List *edit)
  2071. {
  2072.  editCatNode *en, *next;
  2073.  
  2074.  /* replace the database entries */
  2075.  DataReplaceEntryCats(edit);
  2076.  DataReplaceTempCats(edit);
  2077.  /*DataReplaceGroupCats(&grouplist, edit);*/
  2078.  
  2079.  /* replace all control structures */
  2080.  en = DataLocateCat(edit,filterControl.category);
  2081.  strcpy(filterControl.category,en->new.catname);
  2082.  
  2083.  en = DataLocateCat(edit,searchControl.catstr);
  2084.  /* only replace search if _exact_ match */
  2085.  if (strcmpi(en->original.catname,searchControl.catstr) == 0)
  2086.      strcpy(searchControl.catstr,en->new.catname);
  2087.  
  2088. /* what the hell was I thinking...
  2089.  en = DataLocateCat(edit,sortEntries[SORTCATEGORY].field);
  2090.  strcpy(sortEntries[SORTCATEGORY].field,en->new.catname);
  2091. */
  2092.  
  2093.  /* free up original list */
  2094.  DataFreeList(&categories);
  2095.  
  2096.  /* create new cat list */
  2097.  en = (editCatNode *)edit->lh_Head;
  2098.  while ( (next = (editCatNode *)en->new.node.ln_Succ)) {
  2099.     DataAddCat(&categories,(categoryNode *)(&en->new));
  2100.     en = next;
  2101.  }
  2102.  
  2103.   /* free up edit list */
  2104.  DataFreeList(edit);
  2105. }
  2106.  
  2107. /********************************************************
  2108. * DataReplaceGroupCats()
  2109. *
  2110. *    replaces all categories with their new names
  2111. *********************************************************/
  2112. void DataReplaceGroupCats(struct List *grps, struct List *new)
  2113. {
  2114.  editCatNode *en;
  2115.  groupNode *node = NULL;
  2116.  categoryNode *cat;
  2117.  struct Node *find;
  2118.  
  2119.  while ( (node = (groupNode *)DataGetNext(grps, node)) != NULL) {
  2120.     cat = NULL;
  2121.     while ( (cat = (categoryNode *)DataGetNext(&node->catlist,cat)) != NULL) {
  2122.         /* replace all control structures */
  2123.         en = DataLocateCat(new, cat->catname);
  2124.         if (strcmpi(en->new.catname,"none") == 0) {
  2125.              find = DataFindName(new,cat->catname);
  2126.             if (find == NULL) {
  2127.                 Remove(cat);
  2128.                 FreeVec(cat);
  2129.                 cat = NULL;
  2130.             }
  2131.              else     strcpy(cat->catname,en->new.catname);
  2132.         }
  2133.         else    strcpy(cat->catname,en->new.catname);
  2134.     }
  2135.  }
  2136. }
  2137.  
  2138. /********************************************************
  2139. * DataReplaceTempCats()
  2140. *
  2141. *    replaces all categories with their new names
  2142. *********************************************************/
  2143. void DataReplaceTempCats(struct List *new)
  2144. {
  2145.  editCatNode *found;
  2146.  templateNode *node, *next;
  2147.  
  2148.  if (templates.lh_TailPred == (struct Node *)&templates)
  2149.     return;
  2150.  
  2151.  node = (templateNode *)templates.lh_Head;
  2152.  while ( (next = (templateNode *)node->node.ln_Succ) ){
  2153.     found = DataLocateCat(new,node->template.category);
  2154.     strcpy(node->template.category,found->new.catname);
  2155.  
  2156.     node = next;
  2157.  }
  2158. }
  2159.  
  2160. /********************************************************
  2161. * DataReplaceEntryCats()
  2162. *
  2163. *    replaces all categories with their new names
  2164. *********************************************************/
  2165. void DataReplaceEntryCats(struct List *new)
  2166. {
  2167.  editCatNode *found;
  2168.  entryNode *node, *next;
  2169.  
  2170.  if (entries.mlh_TailPred == &entries)
  2171.     return;
  2172.  
  2173.  node = (entryNode *)entries.mlh_Head;
  2174.  while ( (next = (entryNode *)node->node.mln_Succ) ){
  2175.     found = DataLocateCat(new,node->category);
  2176.     strcpy(node->category,found->new.catname);
  2177.  
  2178.     node = next;
  2179.  }
  2180. }
  2181.  
  2182. /********************************************************
  2183. * DataLocateCat()
  2184. *
  2185. *    Locate an original cat name.. return NONE if deleted
  2186. **********************************************************/
  2187. editCatNode *DataLocateCat(struct List *new, char *cat)
  2188. {
  2189.  editCatNode *temp, *next;
  2190.  
  2191.  temp = (editCatNode *)new->lh_Head;
  2192.  while ( (next = (editCatNode *)temp->new.node.ln_Succ) ){
  2193.     if (temp->oldnode == TRUE && strcmpi(cat,temp->original.catname) == 0)
  2194.         return (temp);
  2195.  
  2196.     temp = next;
  2197.  } 
  2198.  
  2199.  return ( (editCatNode*)(new->lh_Head));
  2200. }
  2201.  
  2202. /**********************************************************
  2203. * DataSearchFilter()
  2204. *
  2205. *    Searches through a fliter list for search match
  2206. ***********************************************************/
  2207. WORD DataSearchFilter(struct MinList *fl, searchState *search)
  2208. {
  2209.  WORD entry = 0, firstrow = -1;
  2210.  BOOL findfirst;
  2211.  filterNode *work = (filterNode *)fl->mlh_Head, *next;
  2212.  
  2213.  if (fl->mlh_TailPred == fl)
  2214.     return ( -1 );
  2215.  
  2216.  /* is there any criteria to begin with? */
  2217.  if (!search->check && !search->amnt && !search->date && !search->category &&
  2218.     !search->name && !search->memo)
  2219.     return (-1);
  2220.  
  2221.  /* can we return on the first match? */
  2222.  if (search->lastrow == -1 || search->lastrow >= entryCount)
  2223.     findfirst = TRUE;
  2224.  else findfirst = FALSE;
  2225.  
  2226.  while ( (next = (filterNode *)work->node.mln_Succ) ) {
  2227.  
  2228.     if (DataSearchMatch(work,search)) {
  2229.         if (firstrow == -1) {
  2230.             firstrow = entry;
  2231.             if (findfirst || entry > search->lastrow)
  2232.                 return (entry);
  2233.         }
  2234.         else if (entry > search->lastrow)
  2235.             return (entry);
  2236.     }
  2237.  
  2238.     /* next! */
  2239.     entry++;
  2240.     work = next;
  2241.  }
  2242.  
  2243.  /* did we match before entry? */
  2244.  return (firstrow);
  2245. }
  2246.  
  2247. /********************************************************************
  2248. * DataSearchMatch()
  2249. *
  2250. *    Match a filter to a search criteria
  2251. *********************************************************************/
  2252. BOOL DataSearchMatch(filterNode *fn, searchState *search)
  2253. {
  2254.  
  2255.  if (search->check && fn->entry->type != CHECKTYPE)
  2256.     return (FALSE);
  2257.  
  2258.  if (search->check && (fn->entry->check != search->checknum))
  2259.     return (FALSE);
  2260.  
  2261.  if (search->memo && !MatchPatternNoCase(search->memostrtoken, fn->entry->memo))
  2262.     return (FALSE);
  2263.  
  2264.  if (search->name && !MatchPatternNoCase(search->namestrtoken, fn->entry->name))
  2265.     return (FALSE);
  2266.  
  2267.  if (search->category && !MatchPatternNoCase(search->catstrtoken, fn->entry->category))
  2268.     return (FALSE);
  2269.  
  2270.  if (search->amnt && (fn->entry->amount != search->amount))
  2271.     return (FALSE);
  2272.  
  2273.  if (search->date && (fn->entry->date.year != search->searchdate.year || 
  2274.               fn->entry->date.month != search->searchdate.month ||
  2275.               fn->entry->date.day != search->searchdate.day) )
  2276.     return (FALSE);
  2277.  
  2278.  return (TRUE);
  2279. }
  2280.  
  2281. /**********************************************************
  2282. * DataFindName()
  2283. *
  2284. *    Case insensitive "FindName"
  2285. ***********************************************************/
  2286. struct Node *DataFindName(struct List *l, char *name)
  2287. {
  2288.  struct Node *work = (struct Node *)l->lh_Head, *next;
  2289.  
  2290.  if (IsListEmpty(l))
  2291.     return (NULL);
  2292.  
  2293.  while ( (next = (struct Node *)work->ln_Succ)) {
  2294.     if (strcmpi(work->ln_Name,name) == 0)
  2295.         return (work);
  2296.     work = next;
  2297.  }
  2298.  
  2299.  return (NULL);
  2300. }
  2301.  
  2302. /**********************************************************
  2303. * DataFindNode()
  2304. *
  2305. *    search for node
  2306. ***********************************************************/
  2307. WORD DataFindNode(struct List *l, struct Node *node)
  2308. {
  2309.  WORD index = 0;
  2310.  struct Node *work = (struct Node *)l->lh_Head, *next;
  2311.  
  2312.  if (IsListEmpty(l))
  2313.     return (-1);
  2314.  
  2315.  while ( (next = (struct Node *)work->ln_Succ)) {
  2316.     if (work == node)
  2317.         return (index);
  2318.     work = next;
  2319.     index++;
  2320.  }
  2321.  
  2322.  return (-1);
  2323. }
  2324.  
  2325. /************************************************************
  2326. * DataBalance()
  2327. *
  2328. *    calculate a balance based on flags. ignores
  2329. *     account default balance
  2330. ************************************************************/
  2331. balanceType DataBalance(UBYTE flags, struct MinList *list)
  2332. {
  2333.  amountType amnt=0;
  2334.  balanceType bal;
  2335.  entryNode *entry = (entryNode *)list->mlh_Head, *next;
  2336.  
  2337.  DataInitBal(DEPOSITTYPE,&amnt,&bal);
  2338.  
  2339.  if (IsListEmpty((struct List *)list))
  2340.     return (bal);
  2341.  
  2342.  while ( (next = (entryNode *)entry->node.mln_Succ)) {
  2343.     if ( !(entry->flags & VOIDED) && (entry->flags & flags) == flags) {
  2344.         /*if (entry->type == DEPOSITTYPE)*/
  2345.             DataAddBal(DEPOSITTYPE,&entry->amount,&bal);
  2346. /*
  2347.         bal += entry->amount;
  2348.  
  2349.         else
  2350.             bal -= entry->amount;
  2351. */
  2352.     }
  2353.     entry = next;
  2354.  }
  2355.  
  2356.  return (bal);
  2357. }
  2358.  
  2359. /************************************************************
  2360. * DataSaveFile()
  2361. *
  2362. *    Save an account
  2363. *************************************************************/
  2364. BOOL DataSaveFile(char *fname, BOOL create)
  2365. {
  2366.  int fd;
  2367.  UWORD magicnum = MAGICNUM;
  2368.  UWORD temp;
  2369.  struct netInfoVars netInfo;
  2370.  categoryNode *cat=NULL;
  2371.  templateNode *tmpl=NULL;
  2372.  entryNode *entry=NULL;
  2373.  sortNode *tempsort = NULL;
  2374.  memoNode *memo = NULL;
  2375.  nameNode *nm = NULL;
  2376.  amntNode *am = NULL;
  2377.  groupNode *group = NULL;
  2378.  
  2379.  
  2380.  if ( (fd = open(fname,O_WRONLY | ((create)?O_CREAT:0) ,0)) == -1)
  2381.     return(FALSE);
  2382.  
  2383.  /* write magic number */
  2384.  if (write (fd,&magicnum,sizeof(UWORD)) == -1) {
  2385.     close (fd);
  2386.     return (FALSE);
  2387.  }
  2388.  
  2389.  /* calculate and write tax info */
  2390.  netInfo.taxdeductcurr = DataBalance( (UBYTE)TAXDEDUCT,&entries);
  2391.  netInfo.taxdeductstate = DataBalance( (UBYTE)(TAXDEDUCT | RECONCILED),&entries);
  2392.  netInfo.currAmnt = amntState.currAmnt;
  2393.  netInfo.stateAmnt = amntState.stateAmnt;
  2394.  netInfo.decimal = usrAccount.decimal;
  2395.  if (write (fd, &netInfo, sizeof(struct netInfoVars)) == -1) {
  2396.     close(fd);
  2397.     return (FALSE);
  2398.  }
  2399.  
  2400.  /* write user macros*/
  2401.  if (write (fd, arexxMacros, sizeof(arexxNode)*MAXMACROS) == -1) {
  2402.         close (fd);
  2403.         return (FALSE);
  2404.  }
  2405.  
  2406.  /* write user check form */
  2407.  if (write (fd,&checkForms.userForm,sizeof(checkForm)) == -1) {
  2408.     close(fd);
  2409.     return (FALSE);
  2410.  }
  2411.  
  2412.  /* write print prefs */
  2413.  if (write (fd,&checkPrint,sizeof(printControl)) == -1) {
  2414.     close(fd);
  2415.     return (FALSE);
  2416.  }
  2417.  
  2418.  /* write report structure */
  2419.  if (write (fd,&reportControl,sizeof(reportSetting)) == -1) {
  2420.     close (fd);
  2421.     return (FALSE);
  2422.  }
  2423.  
  2424.  /* write filter structure */
  2425.  if (write (fd,&filterControl,sizeof(filterSetting)) == -1) {
  2426.     close (fd);
  2427.     return (FALSE);
  2428.  }
  2429.  
  2430.  /* write search structure */
  2431.  if (write (fd,&searchControl, sizeof(searchState)) == -1) {
  2432.     close (fd);
  2433.     return (FALSE);
  2434.  }
  2435.  
  2436.  /* write num of sorts */
  2437.  temp = DataCountNodes(&sortfields);
  2438.  if (write (fd, &temp, sizeof(UWORD)) == -1) {
  2439.     close (fd);
  2440.     return (FALSE);
  2441.  }
  2442.  
  2443.  /* write sort structure */
  2444.  while ( (tempsort = (sortNode *)DataGetNext(&sortfields,tempsort)))
  2445.     if (write (fd,tempsort,sizeof(sortNode)) == -1) {
  2446.         close(fd);
  2447.         return (FALSE);
  2448.     }
  2449.  
  2450.  /* write sort state */
  2451.  if (write (fd, &sortStates, sizeof(sortState)) == -1){
  2452.     close(fd);
  2453.     return (FALSE);
  2454.  }
  2455.  
  2456.  /* write account structure */
  2457.  if (write (fd, &usrAccount,sizeof(accntState)) == -1) {
  2458.     close(fd);
  2459.     return (FALSE);
  2460.  }
  2461.  
  2462.  /* write num of categories */
  2463.  temp = DataCountNodes(&categories);
  2464.  if (write (fd, &temp, sizeof(UWORD)) == -1) {
  2465.     close(fd);
  2466.     return (FALSE);
  2467.  }
  2468.  
  2469.  /* write categories */
  2470.  while ( (cat = (categoryNode*)DataGetNext(&categories,cat)))
  2471.     if (write(fd,cat,sizeof(categoryNode)) == -1) {
  2472.         close(fd);
  2473.         return (FALSE);
  2474.     }
  2475.  
  2476.  /* write num groups */
  2477.  temp = DataCountNodes(&grouplist);
  2478.  if (write(fd,&temp,sizeof(UWORD)) == -1) {
  2479.     close(fd);
  2480.     return (FALSE);
  2481.  }
  2482.  
  2483.  /* write groups, one at a time */
  2484.  while ( (group = (groupNode *)DataGetNext(&grouplist,group))) {
  2485.     if (write(fd,group,sizeof(groupNode)) == -1) {
  2486.         close(fd);
  2487.         return(FALSE);
  2488.     }
  2489.  
  2490.     temp = DataCountNodes(&group->catlist);
  2491.     if (write (fd, &temp, sizeof(UWORD)) == -1) {
  2492.         close(fd);
  2493.         return (FALSE);
  2494.     }
  2495.  
  2496.     cat = NULL;
  2497.     while ( (cat = (categoryNode*)DataGetNext(&group->catlist,cat)))
  2498.         if (write(fd,cat,sizeof(categoryNode)) == -1) {
  2499.             close(fd);
  2500.             return (FALSE);
  2501.         }
  2502.  }
  2503.  
  2504.  /* write num of templates */
  2505.  temp = DataCountNodes(&templates);
  2506.  if (write (fd, &temp, sizeof(UWORD)) == -1) {
  2507.     close(fd);
  2508.     return (FALSE);
  2509.  }
  2510.  
  2511.  /* write templates */
  2512.  while ( (tmpl = (templateNode*)DataGetNext(&templates,tmpl)))
  2513.     if (DataWriteTemplate(fd, tmpl) != 0) {
  2514.         close(fd);
  2515.         return(FALSE);
  2516.     }
  2517.  
  2518.  /* write num of entries */
  2519.  temp = DataCountNodes((struct List *)&entries);
  2520.  if (write (fd, &temp, sizeof(UWORD)) == -1) {
  2521.     close(fd);
  2522.     return (FALSE);
  2523.  }
  2524.  
  2525.  /* write entries */
  2526.  while ( (entry = (entryNode*)DataGetNext((struct List *)&entries, (struct Node *)entry)))
  2527.     if (DataWriteEntry(fd,entry) != 0) {
  2528.         close(fd);
  2529.         return(FALSE);
  2530.     }
  2531.  
  2532.  
  2533.  /* checkbook state information */
  2534.  if (write (fd,&amntState,sizeof(struct stateVars)) == -1) {
  2535.     close(fd);
  2536.     return (FALSE);
  2537.  }
  2538.  
  2539.  
  2540.  /* save the memo list */
  2541.  temp = DataCountNodes((struct List *)&memolist);
  2542.  if (write (fd, &temp, sizeof(UWORD)) == -1) {
  2543.     close(fd);
  2544.     return (FALSE);
  2545.  }
  2546.  
  2547.  /* write memos */
  2548.  while ( (memo = (memoNode*)DataGetNext((struct List *)&memolist, (struct Node *)memo)))
  2549.     if (write(fd,memo,sizeof(memoNode)) == -1) {
  2550.         close(fd);
  2551.         return (FALSE);
  2552.     }
  2553.  
  2554.  /* do the same for the names list and amnts list */
  2555.  temp = DataCountNodes((struct List *)&namelist);
  2556.  if (write (fd, &temp, sizeof(UWORD)) == -1) {
  2557.     close(fd);
  2558.     return (FALSE);
  2559.  }
  2560.  
  2561.  /* write names */
  2562.  while ( (nm = (nameNode*)DataGetNext((struct List *)&namelist, (struct Node *)nm)))
  2563.     if (write(fd,nm,sizeof(nameNode)) == -1) {
  2564.         close(fd);
  2565.         return (FALSE);
  2566.     }
  2567.  
  2568.  temp = DataCountNodes((struct List *)&amntlist);
  2569.  if (write (fd, &temp, sizeof(UWORD)) == -1) {
  2570.     close(fd);
  2571.     return (FALSE);
  2572.  }
  2573.  
  2574.  /* write names */
  2575.  while ( (am = (amntNode*)DataGetNext((struct List *)&amntlist, (struct Node *)am)))
  2576.     if (write(fd,am,sizeof(amntNode)) == -1) {
  2577.         close(fd);
  2578.         return (FALSE);
  2579.     }
  2580.  
  2581.  close(fd);
  2582.  return (TRUE);
  2583. }
  2584.  
  2585. /************************************************************
  2586. * DataLoadFile()
  2587. *
  2588. *    Load an account
  2589. *************************************************************/
  2590. BOOL DataLoadFile(char *fname)
  2591. {
  2592.  int fd;
  2593.  int x,y;
  2594.  UWORD magicnum;
  2595.  UWORD temp,temp3;
  2596.  categoryNode cat;
  2597.  entryNode entry;
  2598.  memoNode memo;
  2599.  nameNode nm;
  2600.  amntNode am;
  2601.  templateNode tmpl;
  2602.  sortNode tempsort;
  2603.  filterNode *filt;
  2604.  groupNode *group, tempgroup;
  2605.  struct netInfoVars netInfo;
  2606.  
  2607.  if ( (fd = open(fname,O_RDONLY,0)) == -1)
  2608.     return (FALSE);
  2609.  
  2610.  /* read magic number */
  2611.  read (fd,&magicnum,sizeof(UWORD));
  2612.  
  2613.  if (magicnum > MAGICNUM || magicnum < MAGICNUMOLD1 ) {
  2614.     close(fd);
  2615.     return (FALSE);
  2616.  }
  2617.  
  2618.  /* read tax vars */
  2619.  DataReadTaxVars(magicnum,fd, &netInfo);
  2620.  
  2621.  usrAccount.decimal = netInfo.decimal;
  2622.  
  2623.  /* read in user macros*/
  2624.  if (magicnum > MAGICNUMOLD8) {
  2625.     read (fd, arexxMacros, sizeof(arexxNode)*MAXMACROS);
  2626.  }
  2627.  
  2628.  if (magicnum >= MAGICNUMOLD6) {
  2629.      /* user check form */
  2630.     if (magicnum == MAGICNUMOLD6)
  2631.          read (fd,&checkForms.userForm,sizeof(checkForm)-(sizeof(ULONG)*3));
  2632.     else     read (fd,&checkForms.userForm,sizeof(checkForm));
  2633.  
  2634.      /* print prefs */
  2635.      read (fd,&checkPrint,sizeof(printControl));
  2636.  }
  2637.  
  2638.  /* read report structure */
  2639.  read (fd,&reportControl,sizeof(reportSetting));
  2640.  
  2641.  /* read filter structure */
  2642.  DataReadFilterSetting(magicnum,fd,&filterControl);
  2643.  
  2644.  /* read search structure */
  2645.  DataReadSearchControl(magicnum,fd,&searchControl);
  2646.  
  2647.  /* read num of sorts */
  2648.  read (fd, &temp, sizeof(UWORD));
  2649.  
  2650.  /* read sort structure */
  2651.  NewList(&sortfields);
  2652.  for (x=0;x<temp;x++) {
  2653.     read (fd,&tempsort,sizeof(sortNode));
  2654.     memcpy(&sortEntries[tempsort.index],&tempsort,sizeof(sortNode));
  2655.     sortEntries[tempsort.index].node.ln_Succ = sortEntries[tempsort.index].node.ln_Pred = 0;
  2656.     sortEntries[tempsort.index].node.ln_Name = sortEntries[tempsort.index].field;
  2657.     AddTail(&sortfields,&sortEntries[tempsort.index]);
  2658.  }
  2659.  
  2660.  /* read sort state */
  2661.  read (fd, &sortStates, sizeof(sortState));
  2662.  
  2663.  /* read account structure */
  2664.  DataReadAccountInfo(magicnum,fd,&usrAccount);
  2665.  
  2666.  /* read num of categories */
  2667.  read (fd, &temp, sizeof(UWORD));
  2668.  
  2669.  /* read categories */
  2670.  DataFreeList(&categories);
  2671.  for (x=0;x<temp;x++) {
  2672.     read (fd,&cat,sizeof(categoryNode));
  2673.     DataAddCat(&categories,&cat);
  2674.  }
  2675.  
  2676.  /* read in groups */
  2677.  if (magicnum > MAGICNUMOLD7) {
  2678.  
  2679.     /* read num of groups */
  2680.      read (fd, &temp, sizeof(UWORD));
  2681.  
  2682.     DataFreeGroupCats(&grouplist);
  2683.     DataFreeList(&grouplist);
  2684.     
  2685.     /* read in each group */
  2686.     for (x=0;x<temp;x++) {
  2687.         read(fd,&tempgroup,sizeof(groupNode));
  2688.         group = DataNewGroup(&grouplist,&tempgroup);
  2689.         
  2690.         /* read each group category in */
  2691.         read(fd,&temp3,sizeof(UWORD));
  2692.         for (y=0;y<temp3;y++) {
  2693.             read(fd,&cat,sizeof(categoryNode));
  2694.             DataAddCat(&group->catlist,&cat);
  2695.         }
  2696.     }
  2697.  }
  2698.  
  2699.  /* read num of templates */
  2700.  read (fd, &temp, sizeof(UWORD));
  2701.  
  2702.  /* read templates */
  2703.  DataFreeList(&templates);
  2704.  for (x=0;x<temp;x++) {
  2705.     DataReadTemplate(magicnum,fd,&tmpl);
  2706.     DataAddTemp(&templates, &tmpl);
  2707.  }
  2708.  
  2709.  /* read num of entries */
  2710.  read (fd, &temp, sizeof(UWORD));
  2711.  
  2712.  /* read entries */
  2713.  DataFreeList((struct List *)&filtered);
  2714.  entryCount = 0;
  2715.  DataFreeList((struct List *)&entries);
  2716.  for (x=0;x<temp;x++) {
  2717.     DataReadEntry(magicnum,fd,&entry);
  2718.     DataAddEntry(&entry,&entries,&filt);
  2719.     if (filt) entryCount++;
  2720.  }
  2721.  
  2722.  /* basic state variables */
  2723.  DataReadStateVars(magicnum,fd, &amntState);
  2724.  
  2725.  /* read in memos */
  2726.  if (magicnum >= MAGICNUMOLD4) {
  2727.     DataFreeList(&memolist);
  2728.     read (fd, &temp, sizeof(UWORD));
  2729.     for (x=0;x<temp;x++) {
  2730.         read (fd,&memo,sizeof(memoNode));
  2731.         MemoNewEdit(&memolist,&memo);
  2732.      }
  2733.  }
  2734.  
  2735.  if (magicnum > MAGICNUMOLD4) {
  2736.     DataFreeList(&namelist);
  2737.     read(fd,&temp,sizeof(UWORD));
  2738.     for (x=0;x<temp;x++) {
  2739.         read (fd,&nm,sizeof(nameNode));
  2740.         NameNewEdit(&namelist,&nm);
  2741.      }
  2742.  
  2743.     DataFreeList(&amntlist);
  2744.     read(fd,&temp,sizeof(UWORD));
  2745.     for (x=0;x<temp;x++) {
  2746.         read (fd,&am,sizeof(amntNode));
  2747.         AmntNewEdit(&amntlist,&am);
  2748.      }
  2749.  }
  2750.  
  2751.  DataInitBalances();
  2752.  
  2753.  if (close (fd))
  2754.     return (FALSE);
  2755.  return (TRUE);
  2756. }
  2757.  
  2758. /*******************************************************
  2759. * DataCountNodes()
  2760. *
  2761. *    Count # nodes in a list
  2762. ********************************************************/
  2763. UWORD DataCountNodes(struct List *lst)
  2764. {
  2765.  UWORD ret = 0;
  2766.  struct Node *work = lst->lh_Head;
  2767.  struct Node *next;
  2768.  
  2769.  if (IsListEmpty(lst))
  2770.     return (ret);
  2771.  
  2772.  while (( next = work->ln_Succ)) {
  2773.     ret++;
  2774.     work = next;
  2775.  }
  2776.  
  2777.  return (ret);
  2778. }
  2779.  
  2780. /*******************************************************
  2781. * DataGetNext()
  2782. *
  2783. *    Get the next node in the list
  2784. ********************************************************/
  2785. struct Node *DataGetNext(struct List *lst, struct Node *parent)
  2786. {
  2787.  if (IsListEmpty(lst))
  2788.     return (NULL);
  2789.  
  2790.  if (parent == NULL)
  2791.     return (lst->lh_Head);
  2792.  
  2793.  if (parent->ln_Succ->ln_Succ)
  2794.     return (parent->ln_Succ);
  2795.  
  2796.  return (NULL);
  2797. }
  2798.  
  2799. /*******************************************************
  2800. * DataGetFileName()
  2801. *
  2802. *    Obtain the file name from an ASL requestor
  2803. ********************************************************/
  2804. BOOL DataGetFileName(char *dest, short destsize, char *drawer, char *file)
  2805. {
  2806.  strncpy(dest, drawer, destsize);
  2807.  return (AddPart( dest, file, destsize));
  2808. }
  2809.  
  2810. /*******************************************************
  2811. * DataAttachIcon()
  2812. *
  2813. *    Attaches icons to files    
  2814. ********************************************************/
  2815. void DataAttachIcon(char *iconpath, char *iconname, char *fname)
  2816. {
  2817.  struct DiskObject *diskobj;
  2818.  char icon[200];
  2819.  
  2820.  sprintf(icon,"%s%s",iconpath,iconname);
  2821.  if ( (diskobj = GetDiskObjectNew(icon)) != NULL) {
  2822.      PutDiskObject(fname,diskobj);
  2823.     FreeDiskObject(diskobj);
  2824.  }
  2825. }
  2826.  
  2827. /********************************************************
  2828. * DataRunningBals()
  2829. *
  2830. *    Calculates running balances for the filters
  2831. *********************************************************/
  2832. balanceType DataRunningBals(struct MinList *entries, struct MinList *filtered)
  2833. {
  2834.  amountType zero = 0;
  2835.  balanceType scale,bal;
  2836.  filterNode *filt;
  2837.  entryNode *next, *entry = (entryNode *)entries->mlh_Head;
  2838.  
  2839.  DataInitBal(DEPOSITTYPE,&usrAccount.beginAmount,&bal);
  2840.  DataInitBal(DEPOSITTYPE,&zero, &scale);
  2841.  
  2842.  if (entries->mlh_TailPred == (struct Node *)entries)
  2843.     return (bal);
  2844.  
  2845.  if (filtered->mlh_TailPred == (struct Node *)filtered)
  2846.     return (bal);
  2847.  
  2848.  while ( (next = (entryNode *)entry->node.mln_Succ)) {
  2849.     if (!(entry->flags & VOIDED)) {
  2850.         DataAddBal(entry->type,&entry->amount,&bal);
  2851.     }
  2852.  
  2853.     if (DataTestFilter(entry,&filterControl) == TRUE) {
  2854.  
  2855.         if ( DataCmpAmntBal(&entry->amount,&scale) == 1)
  2856.             DataInitBal(DEPOSITTYPE,&entry->amount,&scale);
  2857.         else if ( DataCmpBal(FALSE, &bal, &scale) == 1)
  2858.             memcpy(&scale,&bal,sizeof(balanceType));
  2859.  
  2860.         filt = (filterNode *)filtered->mlh_Head;
  2861.     
  2862.          /* locate filter */
  2863.          while (filt->node.mln_Succ != NULL) {
  2864.             if (filt->entry == entry) {
  2865.                 if (filt->entry->flags & VOIDED)
  2866.                     DataInitBal(DEPOSITTYPE,&zero,&filt->runningBal);
  2867.                 else
  2868.                     memcpy(&filt->runningBal,&bal,sizeof(balanceType));
  2869.                 break;
  2870.             }
  2871.  
  2872.             filt = (filterNode *)filt->node.mln_Succ;
  2873.         }
  2874.     }    
  2875.     entry = next;
  2876.  }
  2877.  
  2878.  DataAddBal(DEPOSITTYPE,&usrAccount.beginAmount,&scale);
  2879.  return (scale);
  2880. }
  2881.  
  2882. /********************************************************
  2883. * DataSummarize()
  2884. *
  2885. *      Obtain summary information from account
  2886. *********************************************************/
  2887. BOOL DataSummarize(char *fname, netNode *net)
  2888. {
  2889.  int fd;
  2890.  unsigned short magicnum;
  2891.  
  2892.  if ( (fd = open(fname,O_RDONLY,0)) == -1)
  2893.     return (FALSE);
  2894.  
  2895.  /* read magic number */
  2896.  read (fd,&magicnum,sizeof(UWORD));
  2897.  
  2898.  if (magicnum < MAGICNUMOLD3) {
  2899.     close(fd);
  2900.     return (FALSE);
  2901.  }
  2902.  
  2903.  DataReadTaxVars(magicnum,fd,&net->balances);
  2904.  
  2905.  strcpy(net->acname,fname);
  2906.  close(fd);
  2907.  return (TRUE);
  2908. }
  2909.  
  2910. /************************************************************
  2911. * DataFilterBalance()
  2912. *
  2913. *    calculate the filter balance
  2914. ************************************************************/
  2915. void DataFilterBalance(struct MinList *list)
  2916. {
  2917.  amountType zero = 0;
  2918.  balanceType bal;
  2919.  filterNode *filter = (filterNode *)list->mlh_Head, *next;
  2920.  
  2921.  DataInitBal(DEPOSITTYPE,&zero,&bal);
  2922.  DataInitBal(DEPOSITTYPE,&zero,&filtAmnt);
  2923.  
  2924.  if (IsListEmpty((struct List *)list))
  2925.     return;
  2926.  
  2927.  while ( (next = (filterNode *)filter->node.mln_Succ)) {
  2928.     if ( !(filter->entry->flags & VOIDED) ) {
  2929.         DataAddBal(filter->entry->type, &filter->entry->amount,&bal);
  2930.     }
  2931.     filter = next;
  2932.  }
  2933.  
  2934.  memcpy(&filtAmnt, &bal, sizeof(balanceType));
  2935.  
  2936.  return;
  2937. }
  2938.  
  2939. /*******************************************************
  2940. * DataInitBalances()
  2941. *
  2942. *     Initializes stmt and curr balances from load.
  2943. *    They are read from the account, but don't trust
  2944. *    them.
  2945. ********************************************************/
  2946. void DataInitBalances(void)
  2947. {
  2948.  entryNode *entry = NULL;
  2949.  
  2950.  DataInitBal(DEPOSITTYPE,&usrAccount.beginAmount,&amntState.currAmnt);
  2951.   
  2952.  while ( (entry = (entryNode *)DataGetNext((struct List *)&entries,(struct Node *)entry)) != NULL) {
  2953.     if (!(entry->flags & VOIDED)) {
  2954.         DataAddBal(entry->type,&entry->amount,&amntState.currAmnt);
  2955.      }
  2956.  }
  2957. }
  2958.  
  2959. /*******************************************************
  2960. * DataWriteTemplate()
  2961. *
  2962. *    Write a template to file 
  2963. ********************************************************/
  2964. int DataWriteTemplate(int fd, templateNode *temp)
  2965. {
  2966.  if (write(fd,temp->tempname,TEMPNAMESIZE) == -1)
  2967.     return -1;
  2968.  
  2969.  return (DataWriteEntry(fd,&temp->template));
  2970. }
  2971.  
  2972. /*******************************************************
  2973. * DataWriteEntry()
  2974. *
  2975. *    Pack entries in file format and write out.     
  2976. ********************************************************/
  2977. int DataWriteEntry(int fd, entryNode *entry)
  2978. {
  2979.  struct packit out;
  2980.  UBYTE catsize;
  2981.  
  2982.  out.type = entry->type;
  2983.  out.check = entry->check;
  2984.  out.flags = entry->flags;
  2985.  out.amount = entry->amount;
  2986.  out.date.year = entry->date.year;
  2987.  out.date.day = entry->date.day;
  2988.  out.date.month = entry->date.month;
  2989.  out.namesize = strlen(entry->name);
  2990.  out.memosize = strlen(entry->memo);
  2991.  
  2992.  out.addr1size = out.addr2size = out.addr3size = out.addr4size = 0;
  2993.  out.numBudgets = 1;
  2994.  
  2995.  /* write out each datumn */
  2996.  if (write (fd,&out,sizeof(struct packit)) != sizeof(struct packit))
  2997.     return (-1);
  2998.  
  2999.  /* write out strings */
  3000.  if (write(fd,entry->name,out.namesize) != out.namesize)
  3001.     return (-1);
  3002.  if (write(fd,entry->memo,out.memosize) != out.memosize)
  3003.     return (-1);
  3004.  
  3005.  /* now for each category available... (currently just one) */ 
  3006.  
  3007.  catsize = strlen(entry->category);
  3008.  if (write(fd,&catsize,sizeof(UBYTE)) != sizeof(UBYTE))
  3009.     return (-1);
  3010.  if (write(fd,entry->category,catsize) != catsize)
  3011.     return (-1);
  3012.  if (write(fd,&entry->amount,sizeof(amountType)) != sizeof(amountType))
  3013.     return (-1);
  3014.  
  3015.  return (0);
  3016. }
  3017.  
  3018. /*************************************************************
  3019. * DataCreateDate()
  3020. *
  3021. *    Create date based on multiple formats 
  3022. **************************************************************/
  3023. void DataCreateDate(dateType *date, char *out, BOOL year)
  3024. {
  3025.  
  3026. switch (dateFormat) {
  3027.     case DATE_MMDDYY:
  3028.         if (year)
  3029.             sprintf(out,"%02d/%02d/%2d",date->month,date->day,date->year % 100);
  3030.         else    sprintf(out,"%02d/%02d/%4d",date->month,date->day,date->year);
  3031.         break;
  3032.  
  3033.     case DATE_DDMMYY:
  3034.         if (year)
  3035.             sprintf(out,"%02d/%02d/%2d",date->day,date->month,date->year % 100);
  3036.         else    sprintf(out,"%02d/%02d/%4d",date->day,date->month,date->year);
  3037.  
  3038.         break;
  3039.  
  3040.     case DATE_DEC_12:
  3041.         if (year)
  3042.             sprintf(out,"%s-%02d-%2d",easymonths[date->month-1],date->day,date->year % 100);
  3043.         else    sprintf(out,"%s-%02d-%4d",easymonths[date->month-1],date->day,date->year);
  3044.  
  3045.         break;
  3046.  
  3047.     case DATE_12_DEC:
  3048.         if (year)
  3049.             sprintf(out,"%02d-%s-%2d",date->day,easymonths[date->month-1],date->year % 100);
  3050.         else    sprintf(out,"%02d-%s-%4d",date->day,easymonths[date->month-1],date->year);
  3051.  
  3052.         break;
  3053. }
  3054. }
  3055.  
  3056. /***************************************************************
  3057. * DataExtractDate()
  3058. *
  3059. *    extract date fields from date strings
  3060. ****************************************************************/
  3061. void DataExtractDate(dateType *date, char *out)
  3062. {
  3063.  ULONG day,year,month;
  3064.  char str[4];
  3065.  int x;
  3066.  
  3067.  str[3]=0;
  3068.  
  3069.  switch (dateFormat) {
  3070.     case DATE_MMDDYY:
  3071.         sscanf(out,"%d/%d/%d",&month,&day,&year);
  3072.         break;
  3073.  
  3074.     case DATE_DDMMYY:
  3075.         sscanf(out,"%d/%d/%d",&day,&month,&year);
  3076.         break;
  3077.  
  3078.     case DATE_DEC_12:
  3079.         sscanf(out,"%c%c%c-%d-%d",&str[0],&str[1],&str[2],&day,&year);
  3080.         for (x=0;x<12;x++)
  3081.             if (strcmpi(easymonths[x],str) == 0) {
  3082.                 month = x+1;
  3083.                 break;
  3084.             }
  3085.         break;
  3086.  
  3087.     case DATE_12_DEC:
  3088.         sscanf(out,"%d-%c%c%c-%d",&day,&str[0],&str[1],&str[2],&year);
  3089.         for (x=0;x<12;x++)
  3090.             if (strcmpi(easymonths[x],str) == 0) {
  3091.                 month = x+1;
  3092.                 break;
  3093.             }
  3094.  
  3095.         break;
  3096.  }
  3097.  
  3098.  date->day = day;
  3099.  date->month = month;
  3100.  date->year = year;
  3101. }
  3102.  
  3103. /****************************************************************
  3104. * DataVerifyDateMMDDYY()
  3105. *
  3106. *    Verifies and builds date string
  3107. ****************************************************************/
  3108. BOOL DataVerifyDateMMDDYY(char *instr, char *newstr)
  3109. {
  3110. char *section1, *section2, *last, *skip, *str;
  3111. ULONG day,year,month;
  3112. char strhold[DATESIZE+1];
  3113. dateType date;
  3114.  
  3115.  if (instr == NULL)
  3116.     return (FALSE);
  3117.  
  3118.  strcpy(strhold,instr);
  3119.  strhold[DATESIZE] = NULL;
  3120.  str = strhold;
  3121.  
  3122.  /* clip spaces off front and end */
  3123.  while (*str == ' ') str++;
  3124.  skip = &strhold[strlen(strhold) - 1];
  3125.  while (*skip == ' ' && skip != str) {
  3126.     *skip = NULL;
  3127.     skip--;
  3128.  }
  3129.  
  3130.  if (DataStrSet(str,"0123456789/ ") == FALSE)
  3131.     return (FALSE);
  3132.  
  3133.  /* quick check for '/' count, grab sections */
  3134.  section1 = strchr(str,'/');
  3135.  if (section1 == NULL)
  3136.     return (FALSE);
  3137.  *section1 = NULL;
  3138.  section1++;
  3139.  section2 = strchr(section1,'/');
  3140.  if (section2 == NULL)
  3141.     return (FALSE);
  3142.  *section2 = NULL;
  3143.  section2++;
  3144.  last = strchr(section2,'/');
  3145.  if (last != NULL)
  3146.     return (FALSE);
  3147.  
  3148.  /* check for "/" */
  3149.  if (strlen(section2) == 1)
  3150.     return (FALSE);
  3151.  
  3152.  /* now we have str->month, section1->day, section2->year */
  3153.  
  3154.  /* grab values, then compare later */
  3155.  sscanf(str,"%d",&month);
  3156.  sscanf(section1,"%d",&day);
  3157.  sscanf(section2,"%d",&year);
  3158.  if (month > 12 || month == 0)
  3159.     return (FALSE);
  3160.  if (day > 31 || day == 0)
  3161.     return (FALSE);
  3162.  
  3163.  if (year > 9999) return (FALSE);
  3164.  if (year < 100) year += currCentury;
  3165.  
  3166.  /* check for days in month */
  3167.  if (daysinmonth[month-1] < day )
  3168.     return (FALSE);
  3169.  
  3170.  if (month == 2 && day == daysinmonth[month-1] && !DataLeapYear(year))
  3171.     return (FALSE);
  3172.  
  3173.  date.day = day;
  3174.  date.month = month;
  3175.  date.year = year;
  3176.  DataCreateDate(&date,newstr, FALSE);
  3177.  return (TRUE);
  3178. }
  3179.  
  3180. /****************************************************************
  3181. * DataVerifyDateDDMMYY()
  3182. *
  3183. *    Verifies and builds date string
  3184. ****************************************************************/
  3185. BOOL DataVerifyDateDDMMYY(char *instr, char *newstr)
  3186. {
  3187. char *section1, *section2, *last, *skip, *str;
  3188. ULONG day,year,month;
  3189. char strhold[DATESIZE+1];
  3190. dateType date;
  3191.  
  3192.  if (instr == NULL)
  3193.     return (FALSE);
  3194.  
  3195.  strcpy(strhold,instr);
  3196.  strhold[DATESIZE] = NULL;
  3197.  str = strhold;
  3198.  
  3199.  /* clip spaces off front and end */
  3200.  while (*str == ' ') str++;
  3201.  skip = &strhold[strlen(strhold) - 1];
  3202.  while (*skip == ' ' && skip != str) {
  3203.     *skip = NULL;
  3204.     skip--;
  3205.  }
  3206.  
  3207.  if (DataStrSet(str,"0123456789/ ") == FALSE)
  3208.     return (FALSE);
  3209.  
  3210.  /* quick check for '/' count, grab sections */
  3211.  section1 = strchr(str,'/');
  3212.  if (section1 == NULL)
  3213.     return (FALSE);
  3214.  *section1 = NULL;
  3215.  section1++;
  3216.  section2 = strchr(section1,'/');
  3217.  if (section2 == NULL)
  3218.     return (FALSE);
  3219.  *section2 = NULL;
  3220.  section2++;
  3221.  last = strchr(section2,'/');
  3222.  if (last != NULL)
  3223.     return (FALSE);
  3224.  
  3225.  /* check for "/" */
  3226.  if (strlen(section2) == 1)
  3227.     return (FALSE);
  3228.  
  3229.  /* now we have str->month, section1->day, section2->year */
  3230.  
  3231.  /* grab values, then compare later */
  3232.  sscanf(str,"%d",&day);
  3233.  sscanf(section1,"%d",&month);
  3234.  sscanf(section2,"%d",&year);
  3235.  if (month > 12 || month == 0)
  3236.     return (FALSE);
  3237.  if (day > 31 || day == 0)
  3238.     return (FALSE);
  3239.  
  3240.  if (year > 9999) return (FALSE);
  3241.  if (year < 100) year += currCentury;
  3242.  
  3243.  /* check for days in month */
  3244.  if (daysinmonth[month-1] < day )
  3245.     return (FALSE);
  3246.  
  3247.  if (month == 2 && day == daysinmonth[month-1] && !DataLeapYear(year))
  3248.     return (FALSE);
  3249.  
  3250.  date.day = day;
  3251.  date.month = month;
  3252.  date.year = year;
  3253.  DataCreateDate(&date,newstr, FALSE);
  3254.  return (TRUE);
  3255. }
  3256.  
  3257. /****************************************************************
  3258. * DataVerifyDateDec12()
  3259. *
  3260. *    Verifies and builds date string
  3261. ****************************************************************/
  3262. BOOL DataVerifyDateDec12(char *instr, char *newstr)
  3263. {
  3264. char *section1, *section2, *last, *skip, *str;
  3265. ULONG day,year,month;
  3266. int x;
  3267. char strhold[DATESIZE+1];
  3268. dateType date;
  3269.  
  3270.  if (instr == NULL)
  3271.     return (FALSE);
  3272.  
  3273.  strcpy(strhold,instr);
  3274.  strhold[DATESIZE] = NULL;
  3275.  str = strhold;
  3276.  
  3277.  /* clip spaces off front and end */
  3278.  while (*str == ' ') str++;
  3279.  skip = &strhold[strlen(strhold) - 1];
  3280.  while (*skip == ' ' && skip != str) {
  3281.     *skip = NULL;
  3282.     skip--;
  3283.  }
  3284.  
  3285.  /* find date */
  3286.  month = 0;
  3287.  for (x=0;x<12;x++) {
  3288.     if (strnicmp (easymonths[x],str,3) == 0    ) {
  3289.         month = x+1;
  3290.         break;
  3291.     }
  3292.  }
  3293.  
  3294.  if (month == 0)
  3295.     return (FALSE);
  3296.  
  3297.  /* quick check for '-' count, grab sections */
  3298.  section1 = strchr(str,'-');
  3299.  if (section1 == NULL)
  3300.     return (FALSE);
  3301.  *section1 = NULL;
  3302.  section1++;
  3303.  section2 = strchr(section1,'-');
  3304.  if (section2 == NULL)
  3305.     return (FALSE);
  3306.  *section2 = NULL;
  3307.  section2++;
  3308.  last = strchr(section2,'-');
  3309.  if (last != NULL)
  3310.     return (FALSE);
  3311.  
  3312.  /* check for "-" */
  3313.  if (strlen(section2) == 1)
  3314.     return (FALSE);
  3315.  
  3316.  /* now we have str->month, section1->day, section2->year */
  3317.  
  3318.  /* grab values, then compare later */
  3319.  sscanf(section1,"%d",&day);
  3320.  sscanf(section2,"%d",&year);
  3321.  if (month > 12 || month == 0)
  3322.     return (FALSE);
  3323.  if (day > 31 || day == 0)
  3324.     return (FALSE);
  3325.  
  3326.  if (year > 9999) return (FALSE);
  3327.  if (year < 100) year += currCentury;
  3328.  
  3329.  /* check for days in month */
  3330.  if (daysinmonth[month-1] < day )
  3331.     return (FALSE);
  3332.  
  3333.  if (month == 2 && day == daysinmonth[month-1] && !DataLeapYear(year))
  3334.     return (FALSE);
  3335.  
  3336.  date.day = day;
  3337.  date.month = month;
  3338.  date.year = year;
  3339.  DataCreateDate(&date,newstr, FALSE);
  3340.  
  3341.  return (TRUE);
  3342. }
  3343.  
  3344. /****************************************************************
  3345. * DataVerifyDate12Dec()
  3346. *
  3347. *    Verifies and builds date string
  3348. ****************************************************************/
  3349. BOOL DataVerifyDate12Dec(char *instr, char *newstr)
  3350. {
  3351. char *section1, *section2, *last, *skip, *str;
  3352. ULONG day,year,month;
  3353. int x;
  3354. char strhold[DATESIZE+1];
  3355. dateType date;
  3356.  
  3357.  if (instr == NULL)
  3358.     return (FALSE);
  3359.  
  3360.  strcpy(strhold,instr);
  3361.  strhold[DATESIZE] = NULL;
  3362.  str = strhold;
  3363.  
  3364.  /* clip spaces off front and end */
  3365.  while (*str == ' ') str++;
  3366.  skip = &strhold[strlen(strhold) - 1];
  3367.  while (*skip == ' ' && skip != str) {
  3368.     *skip = NULL;
  3369.     skip--;
  3370.  }
  3371.  
  3372.  /* quick check for '-' count, grab sections */
  3373.  section1 = strchr(str,'-');
  3374.  if (section1 == NULL)
  3375.     return (FALSE);
  3376.  *section1 = NULL;
  3377.  section1++;
  3378.  section2 = strchr(section1,'-');
  3379.  if (section2 == NULL)
  3380.     return (FALSE);
  3381.  *section2 = NULL;
  3382.  section2++;
  3383.  last = strchr(section2,'-');
  3384.  if (last != NULL)
  3385.     return (FALSE);
  3386.  
  3387.  /* check for "-" */
  3388.  if (strlen(section2) == 1)
  3389.     return (FALSE);
  3390.  
  3391.  /* now we have str->month, section1->day, section2->year */
  3392.  
  3393.  /* grab values, then compare later */
  3394.  
  3395.  month = 0;
  3396.  for (x=0;x<12;x++) {
  3397.     if (strnicmp (easymonths[x],section1,3) == 0    ) {
  3398.         month = x+1;
  3399.         break;
  3400.     }
  3401.  }
  3402.  
  3403.  if (month == 0)
  3404.     return (FALSE);
  3405.  
  3406.  sscanf(str,"%d",&day);
  3407.  sscanf(section2,"%d",&year);
  3408.  if (month > 12 || month == 0)
  3409.     return (FALSE);
  3410.  if (day > 31 || day == 0)
  3411.     return (FALSE);
  3412.  
  3413.  if (year > 9999) return (FALSE);
  3414.  if (year < 100) year += currCentury;
  3415.  
  3416.  /* check for days in month */
  3417.  if (daysinmonth[month-1] < day )
  3418.     return (FALSE);
  3419.  
  3420.  if (month == 2 && day == daysinmonth[month-1] && !DataLeapYear(year))
  3421.     return (FALSE);
  3422.  
  3423.  date.day = day;
  3424.  date.month = month;
  3425.  date.year = year;
  3426.  DataCreateDate(&date,newstr, FALSE);
  3427.  
  3428.  return (TRUE);
  3429. }
  3430.  
  3431. /************************************************************
  3432. * DataAnnounceDate()
  3433. *
  3434. *    Announce date for different formats 
  3435. *************************************************************/
  3436. void DataAnnounceDate(GUIFront *gui)
  3437. {
  3438.  char *str[4] = {
  3439.     "Illegal Date\nFormat: mm/dd/yy",
  3440.     "Illegal Date\nFormat: dd/mm/yy",
  3441.     "Illegal Date\nFormat: mmm-dd-yy",
  3442.     "Illegal Date\nFormat: dd-mmm-yy",
  3443.  };
  3444.  
  3445.  switch (dateFormat) {
  3446.     case DATE_MMDDYY:
  3447.          DataAnnounce(gui,str[0]);
  3448.         break;
  3449.     case DATE_DDMMYY:
  3450.          DataAnnounce(gui,str[1]);
  3451.         break;
  3452.     case DATE_DEC_12:
  3453.         DataAnnounce(gui,str[2]);
  3454.         break;
  3455.     case DATE_12_DEC:
  3456.         DataAnnounce(gui,str[3]);
  3457.         break;
  3458.  }
  3459. }
  3460.  
  3461. /************************************************************
  3462. * DataAnnounceAmount()
  3463. *
  3464. *    Announce illegal amount 
  3465. *************************************************************/
  3466. void DataAnnounceAmount(GUIFront *gui)
  3467. {
  3468.  DataAnnounce(gui,"Illegal amount value.");
  3469. }
  3470.  
  3471. /***********************************************************
  3472. *  DataListUp()
  3473. *
  3474. *    Listview management library: move entry UP
  3475. ************************************************************/
  3476. void DataListUp(GUIFront *gui, struct Gadget *listgad, struct List *list, UWORD *listsel)
  3477. {
  3478.  struct Node *node1, *node2;
  3479.  
  3480.  /* do we have room to move up? */
  3481.  if (*listsel == 0)
  3482.     return;
  3483.  
  3484.  /* detach list */
  3485.  GF_SetGadgetAttrs(gui,listgad,
  3486.      GTLV_Labels, ~0,
  3487.     TAG_DONE);
  3488.  
  3489.  node1 = DataOrd2Node(list,*listsel);
  3490.  if (*listsel > 1)
  3491.     node2 = DataOrd2Node(list,*listsel-2);
  3492.  else    node2 = NULL;
  3493.  
  3494.  Remove(node1);
  3495.  Insert(list, node1, node2);
  3496.         
  3497.  *listsel = *listsel - 1;
  3498.  
  3499.  /* re-attach list */        
  3500.  GF_SetGadgetAttrs(gui,listgad,
  3501.     GTLV_Labels, list,
  3502.     GTLV_Selected,*listsel,
  3503.     GTLV_MakeVisible, *listsel,
  3504.     TAG_DONE);
  3505. }
  3506.  
  3507. /***********************************************************
  3508. *  DataListDown()
  3509. *
  3510. *    Listview management library: move entry DOWN
  3511. ************************************************************/
  3512. void DataListDown(GUIFront *gui, struct Gadget *listgad, struct List *list, UWORD *listsel)
  3513. {
  3514.  struct Node *node1, *node2;
  3515.  
  3516.  /* detach list */
  3517.  GF_SetGadgetAttrs(gui,listgad,
  3518.     GTLV_Labels, ~0,
  3519.     TAG_DONE);
  3520.  
  3521.  node1 = DataOrd2Node(list,*listsel);
  3522.  
  3523.  /* is this the last one? */
  3524.  if ( node1->ln_Succ != (struct Node *)(&list->lh_Tail)) {
  3525.     node2 = DataOrd2Node(list,*listsel+1);
  3526.     Remove(node1);
  3527.     Insert(list,node1,node2);
  3528.  
  3529.     *listsel = *listsel + 1;
  3530.  }
  3531.  
  3532.  /* re-attach list */
  3533.  GF_SetGadgetAttrs(gui,listgad,
  3534.     GTLV_Labels, list,
  3535.     GTLV_Selected,*listsel,
  3536.     GTLV_MakeVisible, *listsel,
  3537.     TAG_DONE);
  3538. }
  3539.  
  3540. /***********************************************************
  3541. *  DataListBottom()
  3542. *
  3543. *    Listview management library: move entry to BOTTOM
  3544. ************************************************************/
  3545. void DataListBottom(GUIFront *gui, struct Gadget *listgad, 
  3546.         struct List *list, UWORD *listsel, UWORD entries)
  3547. {
  3548.  struct Node *node1;
  3549.  
  3550.  /* detach list */
  3551.  GF_SetGadgetAttrs(gui,listgad,
  3552.     GTLV_Labels, ~0,
  3553.     TAG_DONE);
  3554.  
  3555.  node1 = DataOrd2Node(list,*listsel);
  3556.  Remove(node1);
  3557.  AddTail(list,node1);
  3558.  *listsel = entries-1;
  3559.  
  3560.  /* re-attach list */
  3561.  GF_SetGadgetAttrs(gui,listgad,
  3562.     GTLV_Labels, list,
  3563.     GTLV_Selected,*listsel,
  3564.     GTLV_MakeVisible, *listsel,
  3565.     TAG_DONE);    
  3566. }
  3567.  
  3568. /***********************************************************
  3569. *  DataListTop()
  3570. *
  3571. *    Listview management library: move entry to TOP
  3572. ************************************************************/
  3573. void DataListTop(GUIFront *gui, struct Gadget *listgad, 
  3574.         struct List *list, UWORD *listsel, UWORD topmargin)
  3575. {
  3576.  struct Node *node1, *node2;
  3577.  
  3578.  if (*listsel <= topmargin)
  3579.     return;
  3580.  
  3581.  /* detach list */
  3582.  GF_SetGadgetAttrs(gui,listgad,
  3583.     GTLV_Labels, ~0,
  3584.     TAG_DONE);
  3585.     
  3586.  node1 = DataOrd2Node(list,*listsel);
  3587.  if (topmargin != 0 && *listsel > topmargin)
  3588.     node2 = DataOrd2Node(list,topmargin-1);
  3589.  else    node2 = NULL;
  3590.  
  3591.  Remove(node1);
  3592.  Insert(list, node1, node2);
  3593.  
  3594.  *listsel = topmargin;
  3595.  
  3596.  /* re-attach list */
  3597.  GF_SetGadgetAttrs(gui,listgad,
  3598.     GTLV_Labels, list,
  3599.     GTLV_Selected, *listsel,
  3600.     GTLV_MakeVisible, *listsel,
  3601.     TAG_DONE);
  3602. }
  3603.  
  3604. /***********************************************************
  3605. *  DataListRemove()
  3606. *
  3607. *    Listview management library: remove entry
  3608. ************************************************************/
  3609. void DataListRemove(GUIFront *gui, struct Gadget *listgad, 
  3610.         struct List *list, UWORD *listsel)
  3611. {
  3612.  struct Node *node1;
  3613.  
  3614.  /* detach and modify list */
  3615.  GF_SetGadgetAttrs(gui,listgad,
  3616.     GTLV_Labels, ~0,
  3617.     TAG_DONE);
  3618.             
  3619.  node1 = DataOrd2Node(list,*listsel);
  3620.  
  3621.  if (node1->ln_Succ == (struct Node *)(&list->lh_Tail)) 
  3622.     *listsel = *listsel - 1;
  3623.  
  3624.  Remove(node1);
  3625.  FreeVec(node1);
  3626.     
  3627.  /* re-attach list */
  3628.  if (IsListEmpty(list)) {
  3629.      GF_SetGadgetAttrs(gui,listgad,
  3630.         GTLV_Labels, list,
  3631.         GTLV_Selected, ~0,
  3632.         TAG_DONE);        
  3633.  }
  3634.  else {
  3635.      GF_SetGadgetAttrs(gui,listgad,
  3636.         GTLV_Labels, list,
  3637.         GTLV_Selected, *listsel,
  3638.         GTLV_MakeVisible, *listsel,
  3639.         TAG_DONE);        
  3640.  }
  3641. }
  3642.