home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #3 / amigamamagazinepolishissue1998.iso / bazy / db3.4 / db.c < prev    next >
C/C++ Source or Header  |  1997-03-16  |  83KB  |  3,132 lines

  1.  
  2. /**********************************************************************/
  3. /*                              Includes                              */
  4. /**********************************************************************/
  5.  
  6. #include <stdio.h>
  7. #include <time.h>
  8. #include <dos.h>    /* For getpath() */
  9. #include <dos/stdio.h>
  10. #include <stdlib.h>    /* qsort ... */
  11. #include <string.h>
  12. #include <ctype.h>
  13.  
  14. #include <exec/types.h>
  15. #include <exec/memory.h>
  16. #include <exec/ports.h>
  17. #include <clib/alib_protos.h>        /* NewList() */
  18. #include <intuition/intuition.h>
  19. #include <intuition/classes.h>
  20. #include <intuition/classusr.h>
  21. #include <intuition/imageclass.h>
  22. #include <intuition/gadgetclass.h>
  23. #include <gadgets/textfield.h>
  24.  
  25. #include <workbench/workbench.h>    /* For the project icon creation */
  26. #include <workbench/startup.h> /* For the project icon start */
  27. #include <libraries/asl.h>
  28. #include <libraries/gadtools.h>
  29. #include <libraries/commodities.h> /* This has a nice qualifier #define */
  30. #include <libraries/iffparse.h>
  31. #include <devices/serial.h>    /* For dialing */
  32. #include <datatypes/textclass.h>    /* This has defines for IFF IDs */
  33. #include <graphics/displayinfo.h>
  34. #include <graphics/gfxbase.h>
  35. #include <graphics/text.h>
  36. #include <proto/exec.h>
  37. #include <proto/dos.h>
  38. #include <proto/intuition.h>
  39. #include <proto/gadtools.h>
  40. #include <proto/iffparse.h>
  41. #include <proto/graphics.h>
  42. #include <proto/utility.h>
  43. #include <proto/icon.h>
  44. #include <proto/asl.h>
  45. #include <proto/wb.h>
  46. #include <proto/diskfont.h>
  47. #include <proto/textfield.h>
  48. #include <clib/alib_protos.h>
  49.  
  50. #include "dbGUI.h"
  51. #include "db.h"
  52. #include "dbparser.h"
  53. #include "dbtexts.h"
  54. #include "Select.h"
  55. #include "dbRexx.h"
  56. #include "Design.h"
  57. #include "Version.h"
  58.  
  59. /**********************************************************************/
  60. /*                              Defines                               */
  61. /**********************************************************************/
  62.  
  63. #ifdef LATTICE
  64. void __regargs __chkabort(void); /* Disable SAS CTRL/C handling */
  65. void __regargs __chkabort(void) {} /* One may also use the nocheckabort flag */
  66. #endif
  67.  
  68. #define MY_FILE_BUF 65536
  69.  
  70. /* Argument to DoSort() offset */ 
  71. #define NORMAL_SORT -1
  72. #define UNSORT -2
  73.  
  74. /**********************************************************************/
  75. /*                              Globals                               */
  76. /**********************************************************************/
  77.  
  78. char EmptyString[]="";
  79.  
  80. struct TagItem frtags[] =
  81. {
  82.     ASLFR_InitialHeight,    MYHEIGHT,
  83.     ASLFR_InitialWidth,        MYWIDTH,
  84.     ASLFR_InitialLeftEdge,    MYLEFTEDGE,
  85.     ASLFR_InitialTopEdge,    MYTOPEDGE,
  86.     ASLFR_DoPatterns,        TRUE,
  87.     ASLFR_RejectIcons,        TRUE,
  88.     TAG_DONE
  89. };
  90.  
  91. struct LocaleInfo LocaleInfo = {    NULL, NULL };
  92. struct Locale *MyLocale = NULL;
  93.  
  94.  /* For correct 'Default Tool' in icons */
  95. char ProgramDirAndName[FMSIZE];
  96.  
  97. LONG WinSig = 0; /* For IDCMP handling */
  98.  
  99. struct TextFont *UserTextFont = NULL;    /* Global so OpenLayWin() can check */
  100.                                                     /* If this font should be used */
  101.  
  102. struct Pro *FirstPro = NULL;
  103. struct Pro *CurrentPro = NULL;
  104.  
  105. /* For ReadArgs() */
  106.  
  107. UBYTE SerialUnit = 0;
  108. UBYTE DialSpeed = 4;
  109. int UserFontYSize = -1;    /* Illegal height defaults to screen font */
  110.  
  111. struct RDArgs *MyRDArgs = NULL;        /* Shell arguments hook */
  112. UBYTE **TTypes = NULL;                    /* WB ToolTypes hook */
  113.  
  114. UBYTE MyTemplate[] = "Files/M,DEVICE/K,UNIT/K/N,DIALPREFIX/K,DIALPOSTFIX/K,"
  115.  "AREACODE/K,PUBSCREEN/K,FONTNAME/K,FONTSIZE/K/N,NOICONS/S,NOSPEEDRENDER/S,"
  116.  "NORETURNSTEP/S,NOSERIAL/S,HORIZBAR/S,ESCQUIT/S,TONEDIAL/S,"
  117.  "TONEDIALSPEED/K/N,CCITT5/S,MAKEBACKUP/S,LOCALESORT/S,HIGHLABEL/S,NOBORDER/S"; 
  118.  
  119. LONG MyArgArray[] = {
  120.     NULL,
  121.     (LONG)"serial.device",
  122.     (LONG)&SerialUnit,
  123.     (LONG)"ATDT ",
  124.     (LONG)";H\r",
  125.     (LONG)"",
  126.     (LONG) NULL,
  127.     (LONG)"",
  128.     (LONG)&UserFontYSize,
  129.     FALSE,
  130.     FALSE,
  131.     FALSE,
  132.     FALSE,
  133.     FALSE,
  134.     FALSE,
  135.     FALSE,
  136.     (LONG)&DialSpeed,
  137.     FALSE,
  138.     FALSE,
  139.     FALSE,
  140.     FALSE,
  141.     FALSE
  142. };
  143. /* Global Prefs settings.. */
  144.  
  145. BOOL DisplayWarnings = TRUE;
  146.  
  147. /* sorting stuff */
  148.  
  149. BOOL AutoSort = FALSE;
  150.  
  151. typedef int (*CompFunc)(char *, char *);
  152.  
  153. struct SortOrder {
  154.     short Order;
  155.     short Offset;
  156.     CompFunc CmpFunc;    /* numeric fieldtypes require other sort functions */
  157. };
  158.     
  159. struct SortInfo {
  160.     struct SortOrder *so;
  161.     size_t norders;
  162.     char SortDir;
  163.     BOOL UnSort;    /* Sort the database based upon each record's address instead */
  164. } SI = { NULL, 0, SORT_DIR_AZ, FALSE };
  165.  
  166.  
  167. /* AppWindow specifics */
  168. struct MsgPort *AWPort =  NULL;
  169. /* End of AppWindow specifics */
  170.  
  171.  
  172. /* Security variables */
  173. char UserName[50] = "«No keyfile needed»";
  174. int UserID = 0;
  175.  
  176. /* For the serial device used in dialing*/
  177. struct MsgPort *SerialMP = NULL;
  178. struct IOExtSer *SerialIO = NULL;
  179.  
  180.  
  181. /* For the clipboard */
  182. struct IFFHandle *Iff0 = NULL, *Iff1 = NULL;
  183.  
  184. BOOL PassWordOk = TRUE;    /* Security */
  185.  
  186. struct Library *RexxSysBase = NULL;
  187. struct Library *LocaleBase = NULL;
  188. struct Library *DiskfontBase = NULL;
  189. struct Library *IFFParseBase = NULL;
  190. struct Library *IconBase = NULL;
  191. struct Library *CxBase = NULL;
  192. struct Library *AslBase = NULL;
  193. struct GfxBase *GfxBase = NULL;
  194. struct IntuitionBase *IntuitionBase = NULL;
  195. struct Library *GadToolsBase = NULL;
  196. struct Library *UtilityBase = NULL;
  197. struct Library *WorkbenchBase = NULL;    /* For AppWindow */
  198. struct Library *TextFieldBase = NULL;
  199. Class *TextFieldClass = NULL;
  200.  
  201.  
  202. /**********************************************************************/
  203. /*                             Prototypes                             */
  204. /**********************************************************************/
  205.  
  206.  
  207. /**********************************************************************/
  208. /*                             Functions                              */
  209. /**********************************************************************/
  210.  
  211.  
  212. LONG EasyLocRequest(struct Window *w, struct EasyStruct *es, ULONG *idcmp,
  213.  APTR arg1, ...)
  214. {
  215.     /* Displays an EasyRequest where the strings are locale string-indexes */
  216.     LONG ret_val;
  217.     struct EasyStruct nes;
  218.     nes.es_StructSize = sizeof(struct EasyStruct);
  219.     nes.es_Flags = 0;
  220.     nes.es_Title = GetAppStr((LONG)es->es_Title);
  221.     nes.es_TextFormat = GetAppStr((LONG)es->es_TextFormat);
  222.     nes.es_GadgetFormat = GetAppStr((LONG)es->es_GadgetFormat);
  223.     
  224.     if (w) BlockInput(w, TRUE);
  225.     ret_val = EasyRequestArgs(w, &nes, idcmp, &arg1);
  226.     if (w) FreeInput(w);
  227.     return ret_val;
  228. }
  229.  
  230.  
  231. void ShowError(int errnum, char *text)
  232. {
  233.     struct Window *w;
  234.     if (errnum >= 0) return;
  235.     if (CurrentPro->CurrentLayout) w = CurrentPro->CurrentLayout->Window;
  236.  
  237.     switch (errnum) {
  238.         case MEM_ERR:
  239.             EasyLocRequest(w, &ES_MemWarn, NULL, text);
  240.             break;
  241.         case RFF_ERR:
  242.             EasyLocRequest(w, &ES_MangledRFF, NULL, text);
  243.             break;
  244.         case FILE_ERR:
  245.             EasyLocRequest(w, &ES_WrongFileType, NULL, text);
  246.             break;
  247.         case GAD_ERR:
  248.         case WIN_ERR:
  249.         case MENU_ERR:
  250.             EasyLocRequest(w, &ES_WinOpenErr, NULL, NULL);
  251.             break;
  252.         case WINSIZE_ERR:
  253.             EasyLocRequest(w, &ES_WinSizeErr, NULL, NULL);
  254.             break;
  255.         default:
  256.             EasyLocRequest(w, &ES_DefaultErr, NULL, NULL);
  257.             break;
  258.     }
  259. }
  260.  
  261. BOOL JumpList(struct Pro *Pr, int delta)
  262. {
  263.     int newnum = Pr->RecNum+delta;
  264.     struct Rec *rp = Pr->CurrentRec;
  265.  
  266.     if (newnum >= Pr->RecSum || newnum < 0) return FALSE;        /* Outside */
  267.  
  268.     Pr->RecNum = newnum;        /* First correct the record number */
  269.  
  270.     if (delta>0) while (delta) { rp=rp->Next; delta--; }
  271.     else while (delta) { rp=rp->Prev; delta++; }
  272.     Pr->CurrentRec = rp;
  273.     return TRUE;
  274.  
  275. }
  276.  
  277. Field GetFld(struct Rec *crp, short Offset)
  278. {
  279.     if (!crp->Fields || Offset >= crp->FldSum) return EmptyString;
  280.     return crp->Fields[Offset];
  281. }
  282.  
  283.  
  284. /* Functions to support reading and updating arbitrary fieldtypes */
  285.  
  286. unsigned char *convertLF(unsigned char *s)
  287. {
  288.     unsigned char *start;
  289.     for (start = s; *s; s++) {
  290.         if (*s == '\n') *s = 0xb6;    /* The paragraph character */
  291.         else if (*s == 0xb6) *s = '\n';
  292.     }
  293.     return s;
  294. }
  295.  
  296. char *ReadVisFld(struct Pro *Pr, struct VisFldInfo *vf)
  297. /* CheckBox and CycleGadgets that are disabled  return empty string  */
  298. {
  299. //    static char returnstring[10];        /* All VisFld's shall return strings */
  300.     static char returnstring[10000];        /* All VisFld's shall return strings */
  301.     char *s;
  302.     ULONG size;
  303.  
  304.     if (!vf) return EmptyString;        /* Safety */
  305.  
  306.     switch (vf->Gadget->GadgetID) {
  307.         case STRING_KIND :
  308.             return (char *)GetStr(vf->Gadget);
  309.             break;    
  310.         case TEXT_KIND :
  311.             return GetFld(*Pr->Recpp, vf->Offset);
  312.             break;
  313.             
  314.         case CHECKBOX_KIND :
  315.         case CYCLE_KIND :
  316.             if (vf->Gadget->Flags & GFLG_DISABLED) return EmptyString;
  317.             stci_d(returnstring, vf->Code);
  318.             return returnstring;
  319.             break;
  320.         case TEXTFIELD_KIND :
  321.             OffGadget(vf->Gadget, Pr->CurrentLayout->Window, NULL);
  322.             GetAttr(TEXTFIELD_Size, vf->Gadget, (ULONG *)&size);
  323.             GetAttr(TEXTFIELD_Text, vf->Gadget, (ULONG *)&s);
  324.             OnGadget(vf->Gadget, Pr->CurrentLayout->Window, NULL);
  325.             if (size) {
  326.                 stccpy(returnstring, s, size+1);
  327.                 convertLF(returnstring);
  328.                 return returnstring;
  329.             } else return EmptyString;
  330.             break;
  331.     }
  332. }
  333.  
  334. char *CodeToText(struct VisFldInfo *vf, char *s)
  335. /* For vf:s of string kind, returns s */
  336. /* For vf:s of checkbox returns space or X */
  337. /* For vf:s of cycle kind returns full text */
  338. /* CheckBox and CycleGadgets that are disabled  return empty string  */
  339. {
  340.     static char returnstring[3];        /* All VisFld's shall return strings */
  341.     int x;
  342.  
  343.     if (!(vf && s)) return s;
  344.  
  345.     switch (vf->Gadget->GadgetID) {
  346.         case STRING_KIND :
  347.         case TEXT_KIND :
  348.         case TEXTFIELD_KIND :
  349.             return s;
  350.             break;
  351.     }
  352.     stcd_i(s, &x);            
  353.     switch (vf->Gadget->GadgetID) {
  354.         case CHECKBOX_KIND :
  355.             returnstring[0]=' ';
  356.             returnstring[1]='\0';
  357.             if (x) returnstring[0] = 'X';
  358.             return returnstring;
  359.             break;
  360.  
  361.         case CYCLE_KIND :
  362.             returnstring[0] = '\0';
  363.             if (vf->Gadget->Flags & GFLG_DISABLED) return returnstring;
  364.             return vf->CEnt[x % vf->NEnt];    /* % is for safety */
  365.             break;
  366.     }
  367. }
  368.  
  369. void WriteVisFld(struct VisFldInfo *vf, struct Window *Win, char *s)
  370. /* Only updates CheckBox and Cyclegadgets if a change has been made */
  371. {
  372.     int NewCode;
  373.     
  374.     if (!s) s = EmptyString;
  375.  
  376.     switch (vf->Gadget->GadgetID) {
  377.         case  STRING_KIND :
  378.             GT_SetGadgetAttrs(vf->Gadget,Win,NULL, GTST_String, s,TAG_DONE);
  379.             break;
  380.  
  381.         case TEXT_KIND :
  382.             GT_SetGadgetAttrs(vf->Gadget,Win,NULL, GTTX_Text, s, TAG_DONE);
  383.             break;
  384.  
  385.         case TEXTFIELD_KIND :
  386.             convertLF(s);
  387.             SetGadgetAttrs(vf->Gadget,Win,NULL, TEXTFIELD_Text, s, TAG_DONE); /* NOT GT_ */
  388.             convertLF(s);
  389.             break;
  390.  
  391.         default :
  392.             stcd_i(s, &NewCode);
  393.             if (NewCode != vf->Code) {
  394.                 vf->Code = NewCode;
  395.                 switch (vf->Gadget->GadgetID) {
  396.                     case CHECKBOX_KIND :
  397.                         GT_SetGadgetAttrs(vf->Gadget,Win,NULL,
  398.                          GTCB_Checked, NewCode, TAG_DONE);
  399.                         break;
  400.                         
  401.                     case CYCLE_KIND :
  402.                         GT_SetGadgetAttrs(vf->Gadget,Win,NULL,
  403.                          GTCY_Active, NewCode, TAG_DONE);
  404.                         break;
  405.                 }
  406.             }
  407.             break;
  408.     }
  409. }
  410.  
  411. __inline char *MyStrCpy(char *dest, char *src)
  412. {
  413.     while(*dest++ = *src++);
  414.     return dest;
  415. }
  416.  
  417. __inline int QuickLen(struct Rec *crp, short offset)
  418. {
  419.     return crp->Fields[offset+1] - crp->Fields[offset] - 1;
  420. }
  421.  
  422. BOOL UpdateFld(struct Rec *crp, short offset, char *s)
  423. {
  424.     /* Return TRUE if some change has been made */
  425.     Field *nl, *ol = crp->Fields;
  426.     Field next, oldfld, olddata = NULL;
  427.     int i, len, diff, size, oldsize = 0;
  428.  
  429.     /* Is an update necessary? */
  430.     if (!strcmp(s, GetFld(crp, offset))) return FALSE;
  431.  
  432.     /* Ok, lets do the tedious update now */
  433.     len = strlen(s);
  434.     if (ol) {
  435.         olddata = ol[0];
  436.         oldsize = ol[crp->FldSum]-ol[0];
  437.     }
  438.     diff = offset - (crp->FldSum-1);
  439.  
  440.     if (diff > 0) {                 /* expand list. i.e. create a new one */
  441.         size = oldsize + diff + len;    /* (diff-1) + (len+1) */
  442.         if (!(nl = AllocMem((2+offset)*sizeof(Field), 0))) return FALSE;
  443.         if (!(nl[0] = AllocMem(size, 0))) {
  444.             FreeMem(nl, (2+offset)*sizeof(Field));
  445.             return FALSE;
  446.         }
  447.         /* Copy data */
  448.         for (i=0; i < crp->FldSum; i++) {
  449.             nl[i+1] = MyStrCpy(nl[i], ol[i]);    /* MyStrCpy returns address after end of dest. */
  450.         }
  451.         for (; i < offset; i++) {
  452.             nl[i+1] = MyStrCpy(nl[i], EmptyString);
  453.         }
  454.         nl[i+1] = MyStrCpy(nl[i], s);
  455.  
  456.         /* Clean up */
  457.         if (ol) FreeMem(ol, (1+crp->FldSum)*sizeof(Field));
  458.         crp->Fields = nl;
  459.         crp->FldSum = offset+1;
  460.     }
  461.     else {    /* Reuse old list (there is always an old list here) */
  462.         size = oldsize - (ol[offset+1]-ol[offset]) + len+1;
  463.  
  464.         if (!(ol[0] = AllocMem(size, 0))) { ol[0] = olddata; return FALSE; }
  465.  
  466.         /* Copy data */
  467.         for (i=0, oldfld = olddata; i < crp->FldSum; i++) {
  468.             if (i == offset) next = MyStrCpy(ol[i], s);
  469.             else next = MyStrCpy(ol[i], oldfld);
  470.             oldfld = ol[i+1];
  471.             ol[i+1] = next;
  472.         }
  473.     }
  474.     if (olddata) FreeMem(olddata, oldsize);            /* Clean up */
  475.     return TRUE;
  476. }
  477.  
  478.  
  479. void UpdateRecord(struct Pro *Pr)
  480. {
  481.     BOOL mod = FALSE;
  482.     struct Rec *crp = *Pr->Recpp;
  483.     struct VisFldInfo *vf = Pr->CurrentLayout->FirstVisFldInfo;
  484.     char *s;
  485.  
  486.     if (Pr->Quiet || !(Pr->Modified & RECMODIFIED)) return;
  487.  
  488.     for (; vf; vf = vf->Next) {
  489.         s = ReadVisFld(Pr, vf);
  490.         if (UpdateFld(crp, vf->Offset, s)) mod = TRUE;
  491.     }
  492.     Pr->Modified &= ~RECMODIFIED;
  493.     if (mod && (Pr->CurrentRec == crp)) Pr->Modified |= PROMODIFIED;
  494. }
  495.  
  496.  
  497. void UpdateTitleBar(struct Pro *Pr, char *InfoTxt)
  498. {
  499.     if (Pr->Quiet) return;
  500.     if (InfoTxt) {
  501.         sprintf(Pr->CurrentLayout->Title,"%s", InfoTxt);
  502.     }
  503.     else {
  504.         if    (Pr->Modified & PROMODIFIED) {  /* File modified */  
  505.             sprintf(Pr->CurrentLayout->Title,"* %s/%s %5d/%d",
  506.              Pr->Name,Pr->CurrentLayout->Name,Pr->RecNum+1,Pr->RecSum);
  507.         } else {
  508.             sprintf(Pr->CurrentLayout->Title,"  %s/%s %5d/%d",
  509.              Pr->Name,Pr->CurrentLayout->Name,Pr->RecNum+1,Pr->RecSum);
  510.         }
  511.     }
  512.     SetWindowTitles(Pr->CurrentLayout->Window,Pr->CurrentLayout->Title,(UBYTE *)-1);
  513. }
  514.  
  515.  
  516. void UpdateDragBar(struct Pro *Pr)
  517. {
  518.     if (Pr->Quiet) return;
  519.     GT_SetGadgetAttrs(Pr->CurrentLayout->DragGad,Pr->CurrentLayout->Window, NULL,
  520.      GTSC_Total, Pr->RecSum+1,
  521.      GTSC_Top, Pr->RecNum, TAG_DONE);
  522. }
  523.  
  524. void MyActivateGadget(struct VisFldInfo *vf, struct Window *Win)
  525.     /* Gets called when user hits a field's corresponding key */
  526.     /* Stringgadgets gets activated, checkbox gadgets gets toggled and */
  527.     /* cyclegadgets gets cycled */
  528. {
  529.     VisFldSelected(vf->Gadget);
  530.  
  531.     switch (vf->Gadget->GadgetID) {
  532.         case STRING_KIND :
  533.         case TEXTFIELD_KIND :
  534.             ActivateGadget(vf->Gadget, Win, NULL);
  535.             break;
  536.  
  537.         case CHECKBOX_KIND :
  538.             vf->Code = (vf->Code) ? 0 : 1;
  539.             GT_SetGadgetAttrs(vf->Gadget,Win,NULL,
  540.              GTCB_Checked, vf->Code, TAG_DONE);
  541.             break;
  542.             
  543.         case CYCLE_KIND :
  544.             if (DB_Msg.Qualifier & IXSYM_SHIFTMASK)    /* Cycle backwards */
  545.                 vf->Code = (vf->Code+vf->NEnt-1) % vf->NEnt;
  546.             else vf->Code = (vf->Code+1) % vf->NEnt;
  547.  
  548.             GT_SetGadgetAttrs(vf->Gadget,Win,NULL,
  549.              GTCY_Active, vf->Code, TAG_DONE);
  550.             break;
  551.     }
  552. }
  553.  
  554. void UpdateGadgets(struct Pro *Pr)
  555. {
  556.     UWORD pos;
  557.     struct Rec *crp = *Pr->Recpp;
  558.     struct VisFldInfo *vf = Pr->CurrentLayout->FirstVisFldInfo;
  559.  
  560.     if (Pr->Quiet) return;
  561.     if (!vf) return;
  562.     if (Pr->CurrentLayout->ComplexGadgets) {    /* CheckBox and Cyclegadgets */
  563.         for (; vf; vf = vf->Next)
  564.             WriteVisFld(vf, Pr->CurrentLayout->Window, GetFld(crp,vf->Offset));
  565.     }
  566.     else {    /* Just Stringadgets in current view. This one is faster. */
  567.         pos = RemoveGList(Pr->CurrentLayout->Window, Pr->CurrentLayout->FirstVisFldInfo->Gadget, -1);
  568.         /* Do the update here */
  569.  
  570.         for (; vf; vf = vf->Next) 
  571.                 strcpy(GetStr(vf->Gadget), GetFld(crp, vf->Offset));
  572.  
  573.         /* Re link */
  574.         AddGList(Pr->CurrentLayout->Window, Pr->CurrentLayout->FirstVisFldInfo->Gadget, pos, -1, NULL);
  575.         RefreshGList(Pr->CurrentLayout->FirstVisFldInfo->Gadget, Pr->CurrentLayout->Window, NULL, -1);
  576.     }
  577.  
  578.     if (MyRexxPort && (Pr->Mode == MODE_NORMAL)) {    /* Run rexx scripts when a new record appears */
  579.         struct RFFTag *rxtag;
  580.         BOOL success = FALSE;
  581.  
  582.         if (rxtag = SearchTags(CurrentPro, NULL, NULL, NEWRECORDRXFILE, NEWRECORDRXSTRING))
  583.             if (rxtag->ID == NEWRECORDRXSTRING) success = SendRexxStrCommand(rxtag->Data);
  584.             else success = SendRexxCommand(rxtag->Data);
  585.  
  586.         if (success) {
  587.             do WaitPort(MyRexxPort);
  588.             while (!HandleRexxMessage(MyRexxPort));
  589.         }
  590.     }
  591. }
  592.  
  593. void UpdateWindow(struct Pro *Pr)
  594. {
  595.     UpdateTitleBar(Pr,NULL);
  596.     UpdateGadgets(Pr);
  597. }
  598.  
  599. BOOL CopyToClipboard(struct Pro *Pr)
  600. {
  601.     Field fld;
  602.     struct Rec *crp = *Pr->Recpp;
  603.     struct VisFldInfo *vf = Pr->CurrentLayout->FirstVisFldInfo;
  604.     struct FldInfo *f = Pr->FirstFldInfo;
  605.     int i, len;
  606.     char normalsep[]="X", parasep[] = "\n\n", *separator = NULL;
  607.     char *s;
  608.     
  609.     if (OpenIFF(Iff0, IFFF_WRITE)) return FALSE;
  610.     if (PushChunk(Iff0, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN)) {
  611.         CloseIFF(Iff0);
  612.         return FALSE;
  613.     }
  614.     if (PushChunk(Iff0, 0, ID_CHRS, IFFSIZE_UNKNOWN)) {
  615.         CloseIFF(Iff0);
  616.         return FALSE;
  617.     }
  618.  
  619.     for (; vf; vf = vf->Next) {
  620.         if (separator) {
  621.             if (strlen(separator) != WriteChunkBytes(
  622.              Iff0,separator,strlen(separator))) {
  623.                 CloseIFF(Iff0);
  624.                 return FALSE;
  625.             }
  626.         }
  627.         if (*(fld = GetFld(crp,vf->Offset))) {
  628.             s = CodeToText(vf, fld);
  629.             len = strlen(s);
  630.             if (len != WriteChunkBytes(Iff0,s,len)) {
  631.                 CloseIFF(Iff0);
  632.                 return FALSE;
  633.             }
  634.         }
  635.         if ((normalsep[0] = vf->VisSep) == '\f') separator = parasep;
  636.         else separator = normalsep;
  637.     }
  638.  
  639.     if (!PopChunk(Iff0)) PopChunk(Iff0);
  640.     CloseIFF(Iff0);
  641.  
  642.     /* Now do unit 1 */    
  643.     if (OpenIFF(Iff1, IFFF_WRITE)) return FALSE;
  644.     if (PushChunk(Iff1, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN)) {
  645.         CloseIFF(Iff1);
  646.         return FALSE;
  647.     }
  648.     if (PushChunk(Iff1, 0, ID_CHRS, IFFSIZE_UNKNOWN)) {
  649.         CloseIFF(Iff1);
  650.         return FALSE;
  651.     }
  652.  
  653.     for (i=0; f; f = f->Next,i++) {
  654.         if (*(fld = GetFld(crp,i))) {
  655.             len = strlen(f->Name);
  656.             if (len != WriteChunkBytes(Iff1,f->Name,len)) {
  657.                 CloseIFF(Iff1);
  658.                 return FALSE;
  659.             }
  660.             if (1 != WriteChunkBytes(Iff1,"\t",1)) {
  661.                 CloseIFF(Iff1);
  662.                 return FALSE;
  663.             }
  664.             len = strlen(fld);
  665.             if (len != WriteChunkBytes(Iff1,fld,len)) {
  666.                 CloseIFF(Iff1);
  667.                 return FALSE;
  668.             }
  669.             if (1 != WriteChunkBytes(Iff1,"\n",1)) {
  670.                 CloseIFF(Iff1);
  671.                 return FALSE;
  672.             }    
  673.         }
  674.     }
  675.  
  676.     if (!PopChunk(Iff1)) PopChunk(Iff1);
  677.     CloseIFF(Iff1);
  678.  
  679.     return TRUE;
  680. }
  681.  
  682. BOOL ClipToRec(struct Pro *Pr, struct Rec *crp, char *clipbuf)
  683. {
  684.     struct FldInfo *f;
  685.     short offset;
  686.     char *p;
  687.     BOOL retval = FALSE, found;
  688.  
  689.     while (*clipbuf) {
  690.         found = FALSE;
  691.         if (!(p = strpbrk(clipbuf,"\t"))) break;
  692.         *p = '\0';
  693.         for (offset = 0,f = Pr->FirstFldInfo; f; offset++, f = f->Next) {
  694.             if (!(Stricmp(f->Name,clipbuf))) {
  695.                 found = TRUE;
  696.                 clipbuf = p+1;                /* Move to data */
  697.                 if (!(p = strpbrk(clipbuf,"\n"))) return FALSE;
  698.                 *p = '\0';
  699.                 UpdateFld(crp, offset, clipbuf);
  700.                 retval = TRUE;
  701.             }
  702.         }
  703.         clipbuf = p+1;
  704.         if (!found) {    /* Skip unknown data */
  705.             if (!(p = strpbrk(clipbuf,"\n"))) return FALSE;
  706.             clipbuf = p+1;
  707.         }
  708.     }
  709.     return retval;
  710. }
  711.  
  712.  
  713. BOOL PasteFromClipboard(struct Pro *Pr, struct Rec *crp)
  714. {
  715.     struct ContextNode *cn;
  716.     UBYTE *buf;
  717.     BOOL retval = FALSE;
  718.     long error, rlen;
  719.     if (!(buf = AllocMem(LOADBUFFERSIZE*10,0))) return FALSE;
  720.  
  721. /*    if (Iff1 = AllocIFF()) {
  722.         if (Iff1->IFF_Stream = (ULONG) OpenClipboard(1)) {
  723.             InitIFFasClip(Iff1); */
  724.             if (!OpenIFF(Iff1, IFFF_READ)) {
  725.                 /* Stop on CHRS chunks */
  726.                 if (!StopChunk(Iff1, ID_FTXT, ID_CHRS)) {
  727.                     /* Find all FTXT CHRS chunks */
  728.                     while (1) {
  729.                         error = ParseIFF(Iff1, IFFPARSE_SCAN);
  730.                         if (error == IFFERR_EOC) continue;    /* End of context */
  731.                         else if (error) break;
  732.                         cn = CurrentChunk(Iff1);
  733.                     
  734.                         if((cn)&&(cn->cn_Type == ID_FTXT)&&(cn->cn_ID == ID_CHRS)) {
  735.                             while((rlen = ReadChunkBytes(Iff1,buf,LOADBUFFERSIZE-1)) > 0) {
  736.                                 buf[rlen] = (UBYTE)'\0';    /* ReadChunkBytes won't do this */
  737.                                 retval = ClipToRec(Pr,crp, buf);
  738.                             }
  739.                             if(rlen < 0) error = rlen;
  740.                         }
  741.                     } /* while */
  742.                     if((error)&&(error != IFFERR_EOF)) retval = FALSE;
  743.                 } /* StopChunk */
  744.                 CloseIFF(Iff1);
  745.             } /* OpenIFF */
  746. /*            CloseClipboard((struct ClipboardHandle *)Iff1->IFF_Stream);
  747.         } /* OpenClipboard */
  748.         FreeIFF(Iff1);
  749.     } /* AllocIFF */
  750. */    FreeMem(buf,LOADBUFFERSIZE*10);
  751.     return retval;
  752. }
  753.  
  754. void DisableComplex(struct Layout *Lay, BOOL disable)
  755. /* Disables/enables complex gadgets, ie checkbox and cyclegadgets in a view */
  756. {
  757.     struct VisFldInfo *vf = Lay->FirstVisFldInfo;
  758.     for (; vf; vf = vf->Next) {
  759.         if ((vf->Gadget->GadgetID == CHECKBOX_KIND) ||
  760.              (vf->Gadget->GadgetID == CYCLE_KIND))
  761.             GT_SetGadgetAttrs(vf->Gadget,Lay->Window,NULL,
  762.              GA_Disabled, disable, TAG_DONE);
  763.     }
  764. }
  765.  
  766. void SetProMode(struct Pro *Pr, char Mode)
  767. /* Sets the mode and corrects the menus and gadgets */
  768. /* Old data in gadgets has to be saved prior to calling this function */
  769. {
  770. //    if (Pr->Mode == Mode) return;        /* Already this mode */
  771.     if (!(Pr->CurrentLayout && Pr->CurrentLayout->Window)) return;
  772.  
  773.     if (!Pr->Quiet) UpdateRecord(Pr);    
  774.     Pr->Mode = Mode;
  775.  
  776.     switch (Mode) {    /* New mode */
  777.     case MODE_NORMAL:
  778.         Pr->Recpp = &Pr->CurrentRec;
  779.         if (Pr->Quiet) break;
  780.         OnMenu(Pr->CurrentLayout->Window, FULLMENUNUM(0,NOITEM,NOSUB)); /* Project */
  781.         OnMenu(Pr->CurrentLayout->Window, FULLMENUNUM(1,4,NOSUB)); /* Edit->Add */
  782.         OnMenu(Pr->CurrentLayout->Window, FULLMENUNUM(3,5,NOSUB)); /* Action->Browse */
  783.         OnMenu(Pr->CurrentLayout->Window, FULLMENUNUM(2,NOITEM,NOSUB)); /* Action */
  784.  
  785.         DisableComplex(Pr->CurrentLayout, FALSE);
  786.         UpdateWindow(Pr);
  787.         UpdateDragBar(Pr);
  788.         break;
  789.     case MODE_FIND:
  790.         Pr->Recpp = &Pr->FindRec;
  791.         if (Pr->Quiet) break;
  792.         OffMenu(Pr->CurrentLayout->Window, FULLMENUNUM(0,NOITEM,NOSUB)); /* Project */
  793.         OffMenu(Pr->CurrentLayout->Window, FULLMENUNUM(1,4,NOSUB)); /* Edit->Add */
  794.         OffMenu(Pr->CurrentLayout->Window, FULLMENUNUM(3,5,NOSUB)); /* Action->Browse */
  795.         OffMenu(Pr->CurrentLayout->Window, FULLMENUNUM(2,NOITEM,NOSUB)); /* Action */
  796.  
  797.         UpdateTitleBar(Pr, GetAppStr(MSG_FIND_MODE_WINMSG));
  798.         GT_SetGadgetAttrs(Pr->CurrentLayout->DragGad,
  799.          Pr->CurrentLayout->Window, NULL,
  800.          GTSC_Total, 2,
  801.          GTSC_Top, 0, TAG_DONE);
  802.  
  803.         DisableComplex(Pr->CurrentLayout, TRUE);
  804.         UpdateGadgets(Pr);
  805.         break;
  806.  
  807.     case MODE_SORT:
  808.         Pr->Recpp = &Pr->SortRec;
  809.         if (Pr->Quiet) break;
  810.         OffMenu(Pr->CurrentLayout->Window, FULLMENUNUM(0,NOITEM,NOSUB)); /* Project */
  811.         OffMenu(Pr->CurrentLayout->Window, FULLMENUNUM(1,4,NOSUB)); /* Edit->Add */
  812.         OffMenu(Pr->CurrentLayout->Window, FULLMENUNUM(3,5,NOSUB)); /* Action->Browse */
  813.         OffMenu(Pr->CurrentLayout->Window, FULLMENUNUM(2,NOITEM,NOSUB)); /* Action */
  814.  
  815.         UpdateTitleBar(Pr, GetAppStr(MSG_SORT_MODE_WINMSG));
  816.  
  817.         GT_SetGadgetAttrs(Pr->CurrentLayout->DragGad,
  818.          Pr->CurrentLayout->Window, NULL,
  819.          GTSC_Total, 2,
  820.          GTSC_Top, 0, TAG_DONE);
  821.         DisableComplex(Pr->CurrentLayout, TRUE);
  822.         UpdateGadgets(Pr);
  823.         break;
  824.     }
  825. /**/    if (ReactivateGad)
  826.          ActivateGadget(LastGad, CurrentPro->CurrentLayout->Window, NULL);
  827.  
  828. }
  829.  
  830.  
  831. __inline void ClearRecord(struct Rec *crp)
  832. {
  833.     if (!crp->Fields) return;
  834.     FreeMem(crp->Fields[0], crp->Fields[crp->FldSum] - crp->Fields[0]);
  835.     FreeMem(crp->Fields, (1+crp->FldSum)*sizeof(Field));
  836.     crp->Fields = NULL;
  837.     crp->FldSum = 0;
  838. }
  839.  
  840. struct Rec *NewRecord(void)
  841. {
  842.     struct Rec *rp;
  843.     if (!(rp = (struct Rec *) AllocMem(sizeof(struct Rec),0))) return NULL;
  844.     /* Initialize the data */
  845.     rp->Prev = rp->Next = NULL;
  846.     rp->Fields = NULL;
  847.     rp->FldSum = 0;
  848. }
  849.  
  850. struct Rec *AddRecord(struct Rec **crpp) /* Pointer to pointer to curr rec */
  851. {
  852.     /* Unfortunately this function also creates a record */
  853.     struct Rec *rp = NewRecord();
  854.  
  855.     if (!rp) return NULL;
  856.     
  857.     if (*crpp) {
  858.         rp->Next = (*crpp)->Next;                /* Curr  New->Next */
  859.         (*crpp)->Next = rp;                        /* Curr->New  Next */
  860.         rp->Prev = *crpp;                            /* Curr<-New  Next */
  861.         if (rp->Next) rp->Next->Prev = rp;    /* Curr  New<-Next */
  862.     }
  863.     else { /* First record */
  864.         rp->Next = NULL;
  865.         rp->Prev = NULL;
  866.         *crpp = rp;
  867.     }
  868.     return rp;
  869. }
  870.  
  871.  
  872. void DeleteRecord(struct Rec **crpp)
  873. {
  874.     struct Rec *rp = *crpp;
  875.  
  876.     ClearRecord(*crpp);
  877.  
  878.     if (rp->Next) *crpp = rp->Next;            /* Prev  Curr >Next */
  879.      else if (rp->Prev) *crpp = rp->Prev;    /* Prev< Curr  Next */
  880.       else *crpp = NULL;                            /* Empty list */
  881.  
  882.     /* unlink it */
  883.     if (rp->Prev)    rp->Prev->Next = rp->Next;            /* Prev   ->   Next */
  884.     if (rp->Next) rp->Next->Prev = rp->Prev;            /* Prev   <-   Next */
  885.     FreeMem(rp,sizeof(struct Rec));
  886.  
  887. }
  888.  
  889. BOOL KillRecord(struct Pro *Pr)
  890. /* Does some checking, handles RecNum and RecSum and calls DeleteRecord */
  891. {
  892.     if (Pr->RecSum > 1) {
  893.         Pr->RecSum--;
  894.         if (Pr->RecNum >= Pr->RecSum)
  895.             Pr->RecNum--;
  896.         DeleteRecord(&Pr->CurrentRec);
  897.         return TRUE;
  898.     }
  899.     return FALSE;
  900. }
  901.  
  902. BOOL Match(struct Rec *Rec, struct Rec *T, struct Rec *TokenRec)
  903. {
  904.     short  offset;
  905.     Field fld, tfld, tokf;
  906.  
  907.     for (offset = 0; offset < T->FldSum; offset++) {
  908.         if (*(tfld = GetFld(T, offset))) {                     /* There is a pattern */
  909.             fld = GetFld(Rec,offset);
  910.             if (*(tokf = GetFld(TokenRec, offset))) {         /* Check if AmigaDOS match */
  911.                 if (!MatchPatternNoCase(tokf, fld)) return FALSE;
  912.             }
  913.             else if (Strnicmp(fld, tfld, QuickLen(T, offset))) return FALSE;
  914.         }
  915.     }
  916.     return TRUE;
  917. }
  918.  
  919. struct Rec *BuildTokenRec(struct Rec *FindRec)
  920. {
  921.     struct Rec *tokenrec = NewRecord();
  922.     Field f, tmp;
  923.     short offset, tmpsize;
  924.  
  925.     if (!tokenrec) return NULL;
  926.     for (offset = FindRec->FldSum-1; offset >= 0; offset--) {    /* efficient UpdateFld */
  927.         if (*(f = GetFld(FindRec, offset))) {
  928.             tmpsize = strlen(f)*2+10;        /* Enough according to autodocs */
  929.             if (!(tmp = AllocMem(tmpsize, 0))) break;
  930.             if (ParsePatternNoCase(f, tmp, tmpsize))      /* WildCards exist */
  931.                 UpdateFld(tokenrec, offset, tmp);
  932.             FreeMem(tmp, tmpsize);
  933.         }
  934.     }
  935.     return tokenrec;
  936. }        
  937.  
  938. struct Rec *FindRecord(struct Pro *Pr, int StartRec, int Dir)
  939. {
  940.     int TmpRecNum;
  941.     struct Rec *TmpCurrentRec, *tokenrec;
  942.     
  943.     if (StartRec >= Pr->RecSum) { /* Out of bounds */
  944.         if (!Pr->Quiet) DisplayBeep(Scr);
  945.         return NULL;
  946.     }
  947.  
  948.     TmpRecNum = Pr->RecNum;
  949.     TmpCurrentRec = Pr->CurrentRec;
  950.     
  951.     UpdateRecord(Pr);
  952.  
  953.     /* Build a tokenrec for MatchPatternNoCase() */
  954.     if (!(tokenrec = BuildTokenRec(Pr->FindRec))) return NULL;
  955.  
  956.     JumpList(Pr,-Pr->RecNum+StartRec);
  957.  
  958.     do {
  959.         if (Match(Pr->CurrentRec,Pr->FindRec,tokenrec)) {
  960.             DeleteRecord(&tokenrec);
  961.             SetProMode(Pr,MODE_NORMAL);
  962.             return Pr->CurrentRec;
  963.         }
  964.     } while (JumpList(Pr,Dir));
  965.      
  966.     /* No match */
  967.     /* First free the tokenrec */
  968.     DeleteRecord(&tokenrec);
  969.     
  970.     if (!Pr->Quiet) DisplayBeep(Scr);
  971.     Pr->RecNum = TmpRecNum;
  972.     Pr->CurrentRec = TmpCurrentRec;
  973.     return NULL;
  974. }
  975.  
  976.  
  977. BOOL LoadRecord(BPTR fp, char *buf, struct Pro *Pr, struct Rec *crp)
  978. {
  979.     /* The contents in this function takes more than 7/8 of the loading time to execute */
  980.     /* Conclusion: Load the whole database in one chunk using AmigaDOS functions! */
  981.  
  982.     int i = 0;     /* d */
  983.     register char *bp = buf;
  984.  
  985.     if (!FGets(fp, buf, LOADBUFFERSIZE-1)) return FALSE;    /* -1 is a v36 safety */
  986.     for (bp = buf; *bp; bp++) if (*bp == '\t') crp->FldSum++;
  987.  
  988.     if (bp > buf && bp[-1] == '\n') *--bp = '\0';
  989.     if (bp == buf) return TRUE;
  990.     crp->FldSum++;
  991.  
  992. /* From here to the end of this function takes 1/8 of the loading time */
  993.  
  994.     if (!(crp->Fields = AllocMem((crp->FldSum+1)*sizeof(Field), 0))) return FALSE;
  995.     if (!(crp->Fields[0] = AllocMem(bp-buf+1, 0))) {
  996.         FreeMem(crp->Fields, (crp->FldSum+1)*sizeof(Field));
  997.         crp->Fields = NULL;
  998.         return FALSE;
  999.     }
  1000.     for (bp = crp->Fields[0]; *bp = *buf; bp++, buf++) {
  1001.         if (*bp == '\t') {
  1002.             *bp = '\0';
  1003.             crp->Fields[++i] = bp+1;
  1004.         }
  1005.     }
  1006.     crp->Fields[++i] = bp+1;
  1007.  
  1008.     return TRUE;
  1009. }
  1010.  
  1011.  
  1012. BOOL Save1stLine(struct Pro *Pr, BPTR fp, char SaveMode)
  1013. {
  1014.     struct FldInfo *f;
  1015.     char separator = '\0';
  1016.  
  1017.     for (f = Pr->FirstFldInfo; f; f=f->Next) {
  1018.         if(!separator) {
  1019.             if (SaveMode == SAVE_COMMA_ASCII) separator = ',';
  1020.             else separator = '\t';
  1021.         }
  1022.         else if (FPutC(fp, separator) == EOF) return FALSE;
  1023.         if (SaveMode == SAVE_COMMA_ASCII) if (FPutC(fp, '\"') == EOF) return FALSE;
  1024.         if (FPuts(fp, f->Name) == EOF) return FALSE;
  1025.         if (SaveMode == SAVE_COMMA_ASCII) if (FPutC(fp, '\"') == EOF) return FALSE;
  1026.     }
  1027.     if (FPutC(fp, '\n') == EOF) return FALSE;
  1028.     return TRUE;            
  1029. }
  1030.  
  1031.  
  1032. BOOL SaveRecord(struct Rec *crp, BPTR fp, char SaveMode)
  1033. {
  1034.     Field fld;
  1035.     int nsepa = 0;
  1036.     int i;
  1037.     BOOL empty = TRUE;
  1038.  
  1039.     if (SaveMode == SAVE_COMMA_ASCII) {
  1040.         for (i = 0; i < crp->FldSum; i++) {
  1041.             if (*(fld = GetFld(crp, i))) {
  1042.                 empty = FALSE;
  1043.                 while (nsepa--)    if (FPutC(fp, ',') == EOF) return FALSE;
  1044.                 if (FPutC(fp, '\"') == EOF) return FALSE;
  1045.                 if (FPuts(fp, fld) == EOF) return FALSE;
  1046.                 if (FPutC(fp, '\"') == EOF) return FALSE;
  1047.                 nsepa = 0;
  1048.             }
  1049.             nsepa++;
  1050.         }
  1051.     }
  1052.     else {
  1053.         for (i = 0; i < crp->FldSum; i++) {
  1054.             if (*(fld = GetFld(crp, i))) {
  1055.                 empty = FALSE;
  1056.                 while (nsepa--)    if (FPutC(fp, '\t') == EOF) return FALSE;
  1057.                 if (FPuts(fp, fld) == EOF) return FALSE;
  1058.                 nsepa = 0;
  1059.             }
  1060.             nsepa++;
  1061.         }
  1062.     }
  1063.     if (!empty && FPutC(fp, '\n') == EOF) return FALSE;
  1064.     return TRUE;
  1065. }
  1066.  
  1067.  
  1068. BOOL SaveView(struct Pro *Pr, struct Rec *crp, BPTR fp, BOOL names)
  1069. {
  1070.     char buffer[FIELDNAMELENGTH];
  1071.     char *bufp, *namep, *s;
  1072.  
  1073.     Field fld;
  1074.     struct VisFldInfo *vf = Pr->CurrentLayout->FirstVisFldInfo;
  1075.  
  1076.     for (; vf; vf = vf->Next) {
  1077.         if (names) {
  1078.             /* Strip underscore _ in gadetname for correct length */
  1079.             for (bufp = buffer, namep = vf->Name;; namep++) {
  1080.                 if (*namep != '_') *bufp++ = *namep;
  1081.                 if (!(*namep)) break;    /* Also copy the \0 char */
  1082.             }
  1083.             if (FPuts(fp, buffer) == EOF) return FALSE;
  1084.             if (FPuts(fp, ": ") == EOF) return FALSE;
  1085.         }
  1086.  
  1087.         if (*(fld = GetFld(crp,vf->Offset))) {
  1088.             s = CodeToText(vf, fld);
  1089.             if (FPuts(fp, s) == EOF) return FALSE;
  1090.         }
  1091.         if (vf->VisSep == '\f') {
  1092.             if (FPutC(fp, '\n') == EOF) return FALSE;
  1093.             if (FPutC(fp, '\n') == EOF) return FALSE;
  1094.         }
  1095.         else if (FPutC(fp, vf->VisSep) == EOF) return FALSE;
  1096.     }
  1097.     return TRUE;
  1098. }
  1099.  
  1100.  
  1101. BOOL ClearPro(struct Pro *Pr)
  1102. {
  1103.     /* First delete old data */
  1104.     JumpList(Pr,Pr->RecSum-Pr->RecNum-1);            /* Jump to last record for speed */
  1105.     while (Pr->RecSum--) DeleteRecord(&Pr->CurrentRec); 
  1106.     Pr->RecNum = 0;
  1107.     Pr->RecSum = 0; /* No risk that RecSum gets -1 */
  1108.  
  1109.     /* Add one record */
  1110.     if (!AddRecord(&Pr->CurrentRec)) return FALSE;
  1111.     Pr->RecSum++;
  1112.  
  1113.     /* We really don't use FirstRec, but we initialize it anyway */
  1114.     Pr->FirstRec = Pr->CurrentRec;
  1115.     /* This also updates the window with empty fields */
  1116.     SetProMode(Pr,MODE_NORMAL);
  1117.     return TRUE;
  1118. }
  1119.  
  1120. void DeleteLayout(struct Pro *Pr, struct Layout *Lay)
  1121. {
  1122.     struct RFFTag *ot;
  1123.     struct VisFldInfo *vf, *nextvf;
  1124.     
  1125.     if (!Lay) return; /* Safety */
  1126.  
  1127.      if (Lay->Browser) DeleteSelect(Lay->Browser);
  1128.  
  1129.     CloseLayWin(Pr, Lay);
  1130.  
  1131.     for (vf = Lay->FirstVisFldInfo; vf; vf=nextvf) {
  1132.         nextvf = vf->Next;
  1133.         DeleteVisFldInfo(vf);
  1134.     }
  1135.     Lay->FirstVisFldInfo = NULL;
  1136.  
  1137.     while (ot = (struct RFFTag *)RemHead((struct List *)&Lay->LayTags))
  1138.      DeleteTag(ot);
  1139.  
  1140.     FreeMem(Lay, sizeof(struct Layout));
  1141. }
  1142.  
  1143. struct Layout *NewLayout(struct Pro *Pr)
  1144. {
  1145.     struct Layout *Lay, *l;
  1146.  
  1147.     if (!(Lay = AllocMem(sizeof(struct Layout), MEMF_CLEAR))) return NULL;
  1148.     NewList((struct List *)&Lay->LayTags);
  1149.     
  1150.     strcpy(Lay->Name,Pr->Name);    /* Same name initially */
  1151.     Lay->ComplexGadgets = FALSE;    /* Faster redraw routines without checkbox */
  1152.                                             /* and cyclegadgets */
  1153.  
  1154.     Lay->XPos = Lay->YPos = -1;    /* Let db think */
  1155.     
  1156.     /* Add this struct to the list */
  1157.     if (!(l = Pr->FirstLayout)) Pr->FirstLayout = Lay;
  1158.     else {
  1159.         while (l->NextLayout) l = l->NextLayout;
  1160.         l->NextLayout = Lay;
  1161.     }
  1162.  
  1163.     /* Browser stuff */
  1164.      Lay->Browser = NewSelect();
  1165.  
  1166.  
  1167.     Pr->CurrentLayout = Lay;
  1168.     return Lay;
  1169. }
  1170.  
  1171. void DeletePro(struct Pro *Pr)
  1172. {
  1173.     struct FldInfo *f, *old;
  1174.     struct RxInfo *ri, *oldri;
  1175.     struct RFFTag *ot;
  1176.     struct RFFLine *oline;
  1177.     struct Layout *l,*nextl;
  1178.  
  1179.     if (!Pr) return; /* Safety */
  1180.  
  1181.     /* Jumping to last record actually improves de-alloc speed a lot */
  1182.     /* as this is the reverse order that the records where allocated */
  1183.     JumpList(Pr,Pr->RecSum-Pr->RecNum-1);            /* Jump to last record */
  1184.     while (Pr->RecSum--) DeleteRecord(&Pr->CurrentRec); 
  1185.     if (Pr->FindRec) DeleteRecord(&Pr->FindRec);
  1186.     if (Pr->SortRec) DeleteRecord(&Pr->SortRec);
  1187.  
  1188.     ri = Pr->FirstRxInfo;
  1189.     while (ri) {
  1190.         while (ot = (struct RFFTag *)RemHead((struct List *)&ri->RxTags))
  1191.          DeleteTag(ot);
  1192.         oldri = ri; ri = ri->Next;
  1193.         FreeMem(oldri, sizeof(struct RxInfo));
  1194.     }
  1195.     Pr->FirstRxInfo = NULL;
  1196.  
  1197.     f = Pr->FirstFldInfo;
  1198.     while (f) {
  1199.         while (ot = (struct RFFTag *)RemHead((struct List *)&f->FldTags))
  1200.          DeleteTag(ot);
  1201.         old = f; f = f->Next;
  1202.         FreeMem(old,sizeof(struct FldInfo));
  1203.     }
  1204.     Pr->FirstFldInfo = NULL;
  1205.  
  1206.     while (ot = (struct RFFTag *)RemHead((struct List *)&Pr->ProTags))
  1207.      DeleteTag(ot);
  1208.     while (oline = (struct RFFLine *)RemHead((struct List *)&Pr->UnknownLines))
  1209.      DeleteRFFLine(oline);
  1210.  
  1211.     for (l = Pr->FirstLayout; l;) {
  1212.         nextl = l->NextLayout;
  1213.         DeleteLayout(Pr, l);
  1214.         l = nextl;
  1215.     }
  1216.     Pr->FirstLayout = NULL;
  1217.     
  1218.     CloseMenu(Pr);
  1219.  
  1220.     FreeMem(Pr, sizeof(struct Pro));
  1221. }
  1222.  
  1223. struct Pro *NewPro(void)
  1224. {
  1225.     struct Pro *Pr;
  1226.  
  1227.     if (!(Pr = AllocMem(sizeof(struct Pro), MEMF_CLEAR))) return NULL;
  1228.  
  1229.     NewList((struct List *)&Pr->ProTags);
  1230.     NewList((struct List *)&Pr->UnknownLines);
  1231.  
  1232.     strcpy(Pr->Name, GetAppStr(MSG_UNTITLED_PRO));
  1233.     Pr->Mode = MODE_NORMAL;
  1234.     Pr->Sep = '\t';
  1235.     Pr->Modified = NOTMODIFIED;
  1236.     Pr->Quiet = FALSE;
  1237.     Pr->Recpp = &Pr->CurrentRec;
  1238.     
  1239.     /* Add one FindRec and SortRec */
  1240.  
  1241.     if (!AddRecord(&Pr->FindRec)) {
  1242.         DeletePro(Pr);
  1243.         return NULL;
  1244.     }
  1245.     if (!AddRecord(&Pr->SortRec)) {
  1246.         DeletePro(Pr);
  1247.         return NULL;
  1248.     }
  1249.  
  1250.     if (!ClearPro(Pr)) {    /* Just to add one default record */
  1251.         DeletePro(Pr);
  1252.         return NULL;
  1253.     }
  1254.     return Pr;
  1255. }
  1256.  
  1257.  
  1258. void SwapSwed(struct Rec *crp)
  1259. {
  1260. /* Correct the order of the swedish åäö characters */
  1261. /* Uses the global struct SI (SortInfo) to determine which fields to manipulate */
  1262.  
  1263.     int i;
  1264.     Field fld;
  1265.     signed char *p;    /* To be explicit */
  1266.     
  1267.     for (i=0; i<SI.norders; i++) {
  1268.         if (*(fld = GetFld(crp,SI.so[i].Offset))) {
  1269.             for (p = fld; *p; p++) {
  1270.                 if (*p & 0x80)
  1271.                     switch (*p) {
  1272.                         case 'Å': *p = 'Ä'; break;
  1273.                         case 'Ä': *p = 'Å'; break;
  1274.                         case 'å': *p = 'ä'; break;
  1275.                         case 'ä': *p = 'å'; break;
  1276.                     }
  1277.             }
  1278.         }
  1279.     }
  1280. }
  1281.  
  1282.  
  1283. int CompareRec(struct Rec **rpp1, struct Rec **rpp2)
  1284. {
  1285.     /* This function is used by qsort() to compare records. It returns values like */
  1286.     /* strcmp(). It uses the global struct SI (SortInfo) to determine details like */
  1287.     /* the sort order and which fields to sort on. */
  1288.  
  1289.     int i;
  1290.     Field fld1,fld2;
  1291.     LONG res;
  1292.     
  1293.     if (SI.UnSort) return *rpp1 - *rpp2;
  1294.  
  1295.     for (i=0; i<SI.norders; i++) {
  1296.         fld1 = GetFld(*rpp1,SI.so[i].Offset);
  1297.         fld2 = GetFld(*rpp2,SI.so[i].Offset);
  1298.  
  1299.         res = SI.so[i].CmpFunc(fld1, fld2);
  1300.         if (res) return (SI.SortDir) ? -res : res;
  1301.     }
  1302.     return 0;
  1303. }
  1304.  
  1305.  
  1306. int LocaleCmp(char *str1, char *str2)
  1307. {
  1308.     /* Frontend for the locale.library StrnCmp() string compare function. */
  1309.     return StrnCmp(MyLocale, str1, str2, -1, SC_COLLATE2);
  1310. }
  1311.  
  1312.  
  1313. int StringCmp(char *str1, char *str2)
  1314. {
  1315.     /* Frontend as one can't take the address of a dynamically linked function */
  1316.     return Stricmp(str1, str2);
  1317. }
  1318.  
  1319.  
  1320. int IntegerCmp(char *str1, char *str2)
  1321. {
  1322.     return atoi(str1) - atoi(str2);
  1323. }
  1324.  
  1325.  
  1326. int SortOrderCmp(struct SortOrder *sop1, struct SortOrder *sop2)
  1327. {
  1328.     return sop1->Order - sop2->Order;
  1329. }
  1330.  
  1331. CompFunc DecideCmpFunc(struct Pro *Pr, short offset)
  1332. {
  1333.     struct FldInfo *fi = GetFldInfo(Pr, offset);
  1334.     struct RFFTag *tag;
  1335.  
  1336.     if (!fi) return StringCmp;    /* Safety, should never happen */
  1337.     tag = FindTag(&fi->FldTags, FTYP);
  1338.  
  1339.     if (tag && !Stricmp(tag->Data,"integer")) return IntegerCmp;
  1340.     else if (MyLocale) return LocaleCmp;
  1341.     else return StringCmp;
  1342. }
  1343.  
  1344.  
  1345. void DoSort(struct Pro *Pr, short offset)
  1346. {
  1347.     /* If offset is non-negative, sort on it instead of using what is entered in */
  1348.     /* the visual fields. (The Browser uses it to do an AutoSort) */
  1349.  
  1350.     int i, offs, temp;
  1351.     struct Rec *trec = Pr->CurrentRec;
  1352.     struct Rec **recArray;
  1353.  
  1354.     if (Pr->RecSum < 2) return;
  1355.  
  1356.     /* Init SI */
  1357.     SI.norders = 0;
  1358.  
  1359.     if (offset >= 0) {
  1360.         SI.norders = 1;
  1361.         if (!(SI.so = AllocMem(sizeof(struct SortOrder),0))) {
  1362.             SetProMode(Pr,MODE_NORMAL);
  1363.             return; /* Out of memory */
  1364.         }
  1365.         SI.so->Order = 1; /* Safety */
  1366.         SI.so->Offset = offset;
  1367.         SI.so->CmpFunc = DecideCmpFunc(Pr, offset);
  1368.     }
  1369.     else if (offset == NORMAL_SORT) {
  1370.         /* First check how many valid "orderfields" there are */
  1371.         UpdateRecord(Pr);
  1372.  
  1373.         for (offs=0; offs < Pr->SortRec->FldSum; offs++) {
  1374.             if (stcd_i(GetFld(Pr->SortRec, offs), &temp)) SI.norders++;
  1375.         }
  1376.         if (SI.norders) {
  1377.             if (!(SI.so = AllocMem(SI.norders * sizeof(struct SortOrder),0))) {
  1378.                 SetProMode(Pr,MODE_NORMAL);
  1379.                 return; /* Out of memory */
  1380.             }
  1381.             for (offs=i=0; offs < Pr->SortRec->FldSum; offs++) {
  1382.                 if (stcd_i(GetFld(Pr->SortRec, offs), &temp)) {
  1383.                     SI.so[i].Order = temp;
  1384.                     SI.so[i].Offset = offs;
  1385.                     SI.so[i++].CmpFunc = DecideCmpFunc(Pr, offs);
  1386.                 }
  1387.             }
  1388.             qsort(SI.so, SI.norders, sizeof(struct SortOrder), SortOrderCmp);
  1389.         }
  1390.         else {
  1391.             SI.UnSort = TRUE; /* Perform an UNSORT */
  1392.             UpdateRecord(Pr);
  1393.         }
  1394.     }
  1395.     else SI.UnSort = TRUE;    /* Perform an UNSORT */
  1396.     
  1397.     /* Prepare an array of pointers to all records for qsort() */
  1398.     if (!(recArray = AllocMem (Pr->RecSum * sizeof(struct Rec *), 0))) {
  1399.         SetProMode(Pr, MODE_NORMAL);
  1400.         FreeMem(SI.so, SI.norders * sizeof(struct SortOrder));
  1401.         return;
  1402.     }
  1403.     while (trec->Prev) trec = trec->Prev; /* find start */
  1404.     if (MyLocale) for (i=0; trec; trec = trec->Next, i++) recArray[i] = trec;
  1405.     else for (i=0; trec; trec = trec->Next, i++) {
  1406.             recArray[i] = trec;
  1407.             SwapSwed(trec);
  1408.     }
  1409.  
  1410.     UpdateTitleBar(Pr,GetAppStr(MSG_SORTING_WINMSG)); /* Sorting might take some time */
  1411.     BlockInput(Pr->CurrentLayout->Window,FALSE);
  1412.  
  1413.     /****  qsort() ****/
  1414.     qsort(recArray, Pr->RecSum, sizeof(struct Rec *), CompareRec);
  1415.  
  1416.     if (SI.UnSort) {
  1417.         Pr->IsSorted = FALSE;
  1418.         SI.UnSort = FALSE;
  1419.     }
  1420.     else Pr->IsSorted = TRUE;
  1421.  
  1422.     Pr->CurrentRec = recArray[0];
  1423.     Pr->RecNum=0;
  1424.  
  1425.     /* Repair the doubly linked list now */
  1426.     recArray[0]->Prev = NULL;
  1427.     for (i=0; i < Pr->RecSum-1; i++) {
  1428.         recArray[i]->Next = recArray[i+1];
  1429.         recArray[i+1]->Prev = recArray[i];
  1430.     }
  1431.     recArray[i]->Next = NULL;    /* List repaired */
  1432.  
  1433.     if (!MyLocale) for (trec = Pr->CurrentRec; trec; trec = trec->Next) SwapSwed(trec);
  1434.     
  1435.     FreeMem(recArray, Pr->RecSum * sizeof(struct Rec *));
  1436.     if (SI.norders) FreeMem(SI.so, SI.norders * sizeof(struct SortOrder));
  1437.  
  1438.     FreeInput(Pr->CurrentLayout->Window);
  1439.     SetProMode(Pr,MODE_NORMAL);
  1440. }
  1441.  
  1442.  
  1443.  
  1444. BOOL IsPhoneNumber(char *nr)
  1445. {
  1446.     /* Checks if nr contains at least one number */
  1447.     BOOL ret = FALSE;
  1448.     if (!nr) return FALSE;
  1449.     while (*nr) if (isdigit(*nr++)) { ret = TRUE; break; }
  1450.     return ret;
  1451. }
  1452.  
  1453.  
  1454. BOOL SpeedRenderOn(struct Layout *Lay)
  1455. /* We build a linked list of SR structs */
  1456. {
  1457.     struct VisFldInfo *vf = Lay->FirstVisFldInfo;
  1458.     struct SR *tp, *old = NULL;
  1459.  
  1460.     if (MyArgArray[NOSPEEDRENDER]) return TRUE;    /* Break out */
  1461.  
  1462.     for (; vf; vf = vf->Next) {
  1463.         /* SpeedRender only works for stringgadgets */
  1464.         if (vf->Gadget->GadgetID != STRING_KIND) continue;
  1465.  
  1466.         if (!(tp = AllocMem(sizeof(struct SR),0))) return FALSE;
  1467.         tp->GadgetRender = vf->Gadget->GadgetRender;
  1468.         vf->Gadget->GadgetRender = NULL;
  1469.         tp->Next = NULL;
  1470.         if (!old) {
  1471.             old = tp;
  1472.             Lay->FirstSR = tp;
  1473.         }
  1474.         else {
  1475.             old->Next = tp;
  1476.             old = tp;
  1477.         }
  1478.     }
  1479.     return TRUE;
  1480. }
  1481.  
  1482. void SpeedRenderOff(struct Layout *Lay)
  1483. {
  1484.     struct VisFldInfo *vf = Lay->FirstVisFldInfo;
  1485.     struct SR *tp = Lay->FirstSR, *old;
  1486.     
  1487.     if (MyArgArray[NOSPEEDRENDER]) return;    /* Break out */
  1488.  
  1489.     for (; vf; vf = vf->Next) {
  1490.         /* SpeedRender only works for stringgadgets */
  1491.         if (vf->Gadget->GadgetID != STRING_KIND) continue;
  1492.  
  1493.         vf->Gadget->GadgetRender = tp->GadgetRender;
  1494.         old = tp; tp = tp->Next;
  1495.         FreeMem(old,sizeof(struct SR));
  1496.     }
  1497.     Lay->FirstSR = NULL;
  1498. }
  1499.  
  1500. void CloseSerial(void)
  1501. {
  1502.     /* Serial device specifics */
  1503.     if (SerialIO) {
  1504.         if (SerialIO->IOSer.io_Device) CloseDevice((struct IORequest *)SerialIO);
  1505.         DeleteExtIO((struct IORequest *)SerialIO);
  1506.     }
  1507.     if (SerialMP) DeletePort(SerialMP);
  1508.  
  1509.     SerialMP = NULL;
  1510.     SerialIO = NULL;    
  1511. }
  1512.  
  1513. /**********************************************************************/
  1514. /*                              Byebye()                              */
  1515. /**********************************************************************/
  1516.  
  1517. void ByeBye(void)
  1518. {
  1519.     struct AppMessage *AppMsg;
  1520.  
  1521.     /* Serial specifics */
  1522.     CloseSerial();
  1523.  
  1524.     /* Clipboard specifics */
  1525.     if (Iff0) {
  1526.         if (Iff0->iff_Stream)
  1527.          CloseClipboard((struct ClipboardHandle *)Iff0->iff_Stream);
  1528.         FreeIFF(Iff0);
  1529.     }
  1530.     if (Iff1) {
  1531.         if (Iff1->iff_Stream)
  1532.          CloseClipboard((struct ClipboardHandle *)Iff1->iff_Stream);
  1533.         FreeIFF(Iff1);
  1534.     }
  1535.  
  1536.     /* Reclaim memory used by ReadArgs(). Don't access MyArgArray after this! */
  1537.     if (MyRDArgs) FreeArgs(MyRDArgs);
  1538.     else if (TTypes) ArgArrayDone();
  1539.  
  1540.     if (CurrentPro->IsSorted) DoSort(CurrentPro, UNSORT);    /* Speed. Let's help FreeMem() */
  1541.     DeletePro(CurrentPro);
  1542.  
  1543.     if (UserTextFont) CloseFont(UserTextFont);
  1544.     CloseDownScreen();    /*GadToolBox*/
  1545.  
  1546.     /* Make sure there are no more outstanding AppWin messages */
  1547.     if (AWPort) {
  1548.         while(AppMsg = (struct AppMessage *)GetMsg(AWPort))
  1549.             ReplyMsg((struct Message *)AppMsg);
  1550.         DeleteMsgPort(AWPort);
  1551.     }
  1552.  
  1553.     if (MyRexxPort) CloseRexxPort(MyRexxPort);
  1554.  
  1555.     if (LocaleBase) {
  1556.         if (MyLocale) CloseLocale(MyLocale);
  1557.         if (LocaleInfo.li_Catalog) CloseCatalog(LocaleInfo.li_Catalog);
  1558.         CloseLibrary (LocaleBase);
  1559.     }
  1560.     if (TextFieldBase)    CloseLibrary(TextFieldBase);
  1561.     if (RexxSysBase)        CloseLibrary(RexxSysBase);
  1562.     if (DiskfontBase)        CloseLibrary(DiskfontBase);
  1563.     if (IFFParseBase)        CloseLibrary(IFFParseBase);
  1564.     if (WorkbenchBase)    CloseLibrary(WorkbenchBase);
  1565.     if (IconBase)            CloseLibrary(IconBase);
  1566.     if (AslBase)            CloseLibrary(AslBase);
  1567.     if (CxBase)                CloseLibrary(CxBase);
  1568.     if (GadToolsBase)        CloseLibrary(GadToolsBase);
  1569.     if (UtilityBase)        CloseLibrary(UtilityBase);
  1570.     if (GfxBase)            CloseLibrary((struct Library *)GfxBase);
  1571.     if (IntuitionBase)    CloseLibrary((struct Library *)IntuitionBase);
  1572.  
  1573.     exit(0);
  1574. }
  1575.  
  1576. void HandleQuit(struct Pro *Pr)
  1577. /* This routine gets called by all quit-program routines */
  1578. {
  1579.     UpdateRecord(Pr);
  1580.     if    (Pr->Modified & PROMODIFIED)  /* File modified */  
  1581.         if    (!EasyLocRequest(Pr->CurrentLayout->Window, &ES_QuitWarn, NULL, NULL)) return;
  1582.  
  1583.     ByeBye();
  1584. }
  1585.  
  1586. BOOL PerformSave(struct Pro *Pr, BPTR fp, char SaveMode, struct Rec *tokenrec)
  1587. {
  1588.     /* Called from SavePro. Performs the actual saving */
  1589.     /* This function exists to simplify bail-out if an error occurs */
  1590.  
  1591.     struct Rec *SaveRec;
  1592.     BOOL names = (SaveMode == SAVE_VIEW_WN);
  1593.     BOOL noview = (SaveMode != SAVE_VIEW) && (SaveMode != SAVE_VIEW_WN);
  1594.  
  1595.     if (noview)
  1596.         if(!Save1stLine(Pr, fp, SaveMode)) return FALSE;
  1597.  
  1598.     if (SaveMode == SAVE_PRO)
  1599.         if(!RFFOut(Pr, fp)) return FALSE;
  1600.  
  1601.     /* Seek first record */
  1602.     for (SaveRec = Pr->CurrentRec; SaveRec->Prev; SaveRec = SaveRec->Prev);
  1603.  
  1604.     /* Save the records */
  1605.  
  1606.     if (tokenrec) {    /* ie filtered output */
  1607.  
  1608.         if (noview) {
  1609.             do {
  1610.                 if (Match(SaveRec,Pr->FindRec,tokenrec))
  1611.                     if (!SaveRecord(SaveRec,fp,SaveMode)) return FALSE;
  1612.             } while (SaveRec = SaveRec->Next);
  1613.         }
  1614.         else {
  1615.             do {
  1616.                 if (Match(SaveRec,Pr->FindRec,tokenrec))
  1617.                     if (!SaveView(Pr,SaveRec,fp,names)) return FALSE;
  1618.             } while (SaveRec = SaveRec->Next);
  1619.         }
  1620.     }
  1621.     else {
  1622.  
  1623.         if (noview) {
  1624.             do {
  1625.                 if (!SaveRecord(SaveRec,fp,SaveMode)) return FALSE;
  1626.             } while (SaveRec = SaveRec->Next);
  1627.         }
  1628.         else {
  1629.             do {
  1630.                 if (!SaveView(Pr,SaveRec,fp,names)) return FALSE;
  1631.             } while (SaveRec = SaveRec->Next);
  1632.         }
  1633.     }
  1634.  
  1635.     return TRUE;
  1636. }
  1637.  
  1638. BOOL MakeBackup(char *filename)
  1639. {
  1640.     char bakname[FMSIZE];
  1641.     strcpy(bakname, filename);
  1642.     strcat(bakname, ".bak");
  1643.     DeleteFile(bakname);
  1644.     if (!Rename(filename, bakname)) return FALSE;
  1645.     return TRUE;
  1646. }
  1647.  
  1648. BOOL SavePro(struct Pro *Pr, char *Drawer, char *Name, char SaveMode, BOOL Filter)
  1649. {
  1650.     BPTR fp;
  1651.     char filename[FMSIZE];
  1652.     struct DiskObject *DO;    /* For handling icons */
  1653.     struct Rec *tokenrec = NULL;
  1654.  
  1655.     strcpy(filename,Drawer);
  1656.     if (!AddPart(filename,Name,FMSIZE-1)) { /* incorrect filename */
  1657.         /* display error req */
  1658.         return FALSE;
  1659.     }
  1660.  
  1661.     if (SaveMode == SAVE_PRO && MyArgArray[MAKEBACKUP]) MakeBackup(filename);
  1662.  
  1663.     /* Open file */
  1664.     if (!(fp = Open(filename, MODE_NEWFILE))) { /* open fail */
  1665.         EasyLocRequest(Pr->CurrentLayout->Window,
  1666.          &ES_OpenFail, NULL, filename);
  1667.         return FALSE;
  1668.     }
  1669.     /* Set a large buffer for increased load speed */
  1670.     SetVBuf(fp, NULL, BUF_FULL, MY_FILE_BUF);
  1671.     
  1672.     if (SaveMode == SAVE_PRO) {
  1673.         strcpy(Pr->Drawer,Drawer);
  1674.         strcpy(Pr->Name,Name);
  1675.     }
  1676.     else {
  1677.         strcpy(Pr->OutputName,Name);
  1678.         strcpy(Pr->OutputDrawer,Drawer);
  1679.     }
  1680.  
  1681.     if (Filter) {
  1682.         /* Build a tokenrec for MatchPatternNoCase() */
  1683.         if (!(tokenrec = BuildTokenRec(Pr->FindRec))) {
  1684.             Close(fp);
  1685.             return FALSE;
  1686.         }
  1687.     }
  1688.  
  1689.     UpdateTitleBar(Pr,GetAppStr(MSG_SAVING_WINMSG)); /* User feedback that file will be saved */
  1690.     BlockInput(Pr->CurrentLayout->Window,TRUE);
  1691.     UpdateRecord(Pr); /* Don't forget this! */
  1692.  
  1693.  
  1694.     if (!PerformSave(Pr,fp,SaveMode, tokenrec)) {
  1695.         /* Save error */
  1696.         EasyLocRequest(Pr->CurrentLayout->Window,
  1697.          &ES_SaveError, NULL, filename);
  1698.         Close(fp);
  1699.         if (tokenrec) DeleteRecord(&tokenrec);
  1700.         FreeInput(Pr->CurrentLayout->Window);
  1701.         UpdateTitleBar(Pr,NULL); /* Maybe a new name? */
  1702.         return FALSE;
  1703.     }
  1704.  
  1705.     if (SaveMode == SAVE_PRO) {
  1706.         Pr->Modified = NOTMODIFIED;
  1707.  
  1708.         if (!MyArgArray[NOICONS]) {
  1709.             /* Everything OK, Save an icon if one doesn't exist */
  1710.             if (DO = GetDiskObject(filename)) FreeDiskObject(DO); /* Icon found */
  1711.             else PutDiskObject(filename,&DataIcon); /* if no icon, create one */
  1712.         }
  1713.     }
  1714.     Close(fp);
  1715.     if (tokenrec) DeleteRecord(&tokenrec);
  1716.     FreeInput(Pr->CurrentLayout->Window);
  1717.     UpdateTitleBar(Pr,NULL); /* Maybe a new name? */
  1718.     return TRUE;
  1719. }
  1720.  
  1721. void Save(struct Pro *Pr, char SaveMode)
  1722. {
  1723.     /* Called from "Save as..", and the "Output..." submenu */
  1724.  
  1725.    struct FileRequester *fr;
  1726.     char fullname[FMSIZE];
  1727.     BOOL dosave = TRUE;
  1728.     BOOL filter = FALSE;
  1729.     int answer;
  1730.     char *title[5];
  1731.     char *name;
  1732.     char *drawer;
  1733.  
  1734.     title[0] = GetAppStr(MSG_SAVE_AS_ASLREQ_TITLE);
  1735.     title[1] = GetAppStr(MSG_OUTPUT_VIEW_ASLREQ_TITLE);
  1736.     title[2] = GetAppStr(MSG_OUTPUT_VIEW_WN_ASLREQ_TITLE);
  1737.     title[3] = GetAppStr(MSG_OUTPUT_TAB_ASCII_ASLREQ_TITLE);
  1738.     title[4] = GetAppStr(MSG_OUTPUT_COMMA_ASCII_ASLREQ_TITLE);
  1739.  
  1740.     if (SaveMode == SAVE_PRO) {
  1741.         name = Pr->Name;
  1742.         drawer = Pr->Drawer;
  1743.     }
  1744.     else {    /* Output menu */
  1745.         name = Pr->OutputName;
  1746.         drawer = Pr->OutputDrawer;
  1747.  
  1748.         if (answer = EasyLocRequest(Pr->CurrentLayout->Window, &ES_Ask_Filtering, NULL, NULL)) {
  1749.              if (answer == 2) filter = TRUE;
  1750.         }
  1751.         else return;
  1752.     }
  1753.  
  1754.     /* By supplying the dimension tags to AllocAslRequest, PD programs like */
  1755.     /* SetASLDim may modify the size to the users preference */
  1756.    fr = AllocAslRequest(ASL_FileRequest, frtags);
  1757.  
  1758.     if (AslRequestTags(fr,ASLFR_Window,Pr->CurrentLayout->Window,
  1759.      ASLFR_SleepWindow,TRUE,
  1760.      ASLFR_DoSaveMode,TRUE,
  1761.      ASLFR_TitleText,title[SaveMode],
  1762.      ASLFR_InitialDrawer, drawer,
  1763.      ASLFR_InitialFile, name,
  1764.      TAG_DONE)) {
  1765.         strcpy(fullname,fr->fr_Drawer);
  1766.         AddPart(fullname,fr->fr_File,FMSIZE-1);
  1767.         if (!access(fullname, F_OK))    /* Found a file with the same name */
  1768.             if (!EasyLocRequest(Pr->CurrentLayout->Window, &ES_SaveWarn, NULL,fr->fr_File)) dosave = FALSE;
  1769.         if (dosave == TRUE) SavePro(Pr,fr->fr_Drawer,fr->fr_File, SaveMode, filter);
  1770.     }
  1771.     FreeAslRequest(fr);
  1772. }
  1773.  
  1774.  
  1775. struct Pro *LoadPro(char *Drawer, char *Name)
  1776. {
  1777.     struct Pro *npr;
  1778.     BPTR fp;
  1779.     char *buf;    /* This buffer holds max one field at a time */
  1780.     char fullname[FMSIZE];
  1781.     int retval;
  1782.  
  1783.     UpdateRecord(CurrentPro);
  1784.     if    (CurrentPro->Modified & PROMODIFIED)  /* File modified */  
  1785.         if    (!EasyLocRequest(CurrentPro->CurrentLayout->Window, &ES_LoadWarn,
  1786.          NULL, NULL)) return NULL;
  1787.         
  1788.     strcpy(fullname,Drawer);
  1789.     if (!AddPart(fullname,Name,FMSIZE-1))    { /* incorrect filename */
  1790.         /* display error req */
  1791.         return NULL;
  1792.     }
  1793.     if (!(fp = Open(fullname, MODE_OLDFILE))) { /* open fail */
  1794.         EasyLocRequest(CurrentPro->CurrentLayout->Window,
  1795.          &ES_OpenFail, NULL, fullname);
  1796.         return NULL;
  1797.     }
  1798.     SetVBuf(fp, NULL, BUF_FULL, MY_FILE_BUF);
  1799.     /* So far so good. Setup a new project */
  1800.     if (!(npr = NewPro())) return NULL;
  1801.     strcpy(npr->Drawer,Drawer);
  1802.     strcpy(npr->Name,Name);
  1803.  
  1804.     /* Make a call to RFFParse */
  1805.     if ((retval = RFFParse(npr,fp)) < 0) {
  1806.         ShowError(retval,fullname);
  1807.         Close(fp);
  1808.         DeletePro(npr);
  1809.         return NULL;
  1810.     }
  1811.  
  1812.     /* Now we waste the old project and make the new project the current one */
  1813.     DeletePro(CurrentPro);
  1814.     CurrentPro = npr;
  1815.  
  1816.     /* Open the window so the user can see the loading */
  1817.     if ((retval = OpenLayWin(npr, npr->CurrentLayout)) < 0) {
  1818.         ShowError(retval,fullname);
  1819.         Close(fp);
  1820.         DeletePro(CurrentPro);
  1821.         CurrentPro = NULL;
  1822.         return NULL;
  1823.     }
  1824.     UpdateTitleBar(npr,GetAppStr(MSG_LOADING_WINMSG)); /* User feedback that a file is loading */
  1825.     BlockInput(CurrentPro->CurrentLayout->Window,TRUE);
  1826.  
  1827.     /* Do the loading. */        
  1828.     if (!(buf = AllocMem(LOADBUFFERSIZE, MEMF_ANY))) {
  1829.         Close(fp);
  1830.         SetProMode(npr,MODE_NORMAL);
  1831.         FreeInput(CurrentPro->CurrentLayout->Window);
  1832.         return NULL;
  1833.     }
  1834.  
  1835.     while (LoadRecord(fp,buf,npr,npr->CurrentRec)) {
  1836.         if (!AddRecord(&npr->CurrentRec)) {
  1837.             /* out of memory */
  1838.             EasyLocRequest(npr->CurrentLayout->Window, &ES_MemWarn, NULL, NULL);
  1839.             break;
  1840.         }
  1841.         npr->CurrentRec = npr->CurrentRec->Next;
  1842.         npr->RecSum++;
  1843.         npr->RecNum++;
  1844.     }
  1845.     Close(fp);
  1846.     FreeMem(buf,LOADBUFFERSIZE);
  1847.     KillRecord(npr); /* Handles everything except updates */
  1848.     JumpList(npr,-npr->RecNum); /* Start at top of file */
  1849.     SetProMode(npr,MODE_NORMAL);
  1850.     FreeInput(CurrentPro->CurrentLayout->Window);
  1851.     return npr;
  1852. }
  1853.  
  1854. BOOL HandleArgs(int argc, char *argv[])
  1855. {
  1856.     /* Handles incoming arguments and open files. Opens only one file for now */
  1857.     /* Handles ToolTypes and also works from CLI */
  1858.     /* Uses AmigaDOS ReadArgs which has template support from CLI */
  1859.  
  1860.     struct WBStartup *argmsg;
  1861.     struct WBArg *wb_arg;
  1862.     struct Pro *npr = NULL;
  1863.     char argdir[FMSIZE];    /* See dos.h */
  1864.  
  1865.     if (argc == 0) {    /* Running from WB  */
  1866.  
  1867.         /* Get filename and drawername of icon to load */
  1868.         argmsg = (struct WBStartup *)argv;
  1869.         wb_arg = argmsg->sm_ArgList;        /* head of the arg list */
  1870.  
  1871.         if (argmsg->sm_NumArgs > 1) {        /* File(s) exists, load first only */
  1872.             wb_arg++;    /* Skip over main program to first file */
  1873.             if (NULL != wb_arg->wa_Lock) {
  1874.                 /* locks supported, change to the proper directory */
  1875.                 NameFromLock(wb_arg->wa_Lock,argdir,sizeof(argdir)); /* Path */
  1876.                 npr=LoadPro(argdir,wb_arg->wa_Name);
  1877.             }
  1878.             /* else do nothing as that filesystem doesn't support locks */
  1879.         }
  1880.     }
  1881.     else { /* Running from CLI */
  1882.         /* Handle CLI args */
  1883.         if (MyArgArray[FILES]) {    /* There are at least one file to load */
  1884.             /* Get argdir */
  1885.             stcgfp(argdir,*(char **)MyArgArray[FILES]);
  1886.             npr=LoadPro(argdir,FilePart(*(UBYTE **)MyArgArray[FILES]));
  1887.         }
  1888.     }
  1889.     if (!CurrentPro) ByeBye();
  1890.     /* If no project was loaded, open empty win */
  1891.     if (!npr) if (OpenLayWin(CurrentPro, CurrentPro->CurrentLayout) < 0) ByeBye();
  1892.     UpdateTitleBar(CurrentPro, NULL);
  1893.     return TRUE;
  1894. }
  1895.  
  1896.  
  1897. void InitSerial(void)
  1898. {
  1899.     /* Set up serial device */
  1900.     /* Needs to be done AFTER the ToolTypes has been set by HandleArgs(); */
  1901.     if (!(SerialMP = CreatePort(0,0))) ByeBye();
  1902.     if (!(SerialIO = (struct IOExtSer *)
  1903.      CreateExtIO(SerialMP, sizeof(struct IOExtSer))))
  1904.         ByeBye();
  1905.  
  1906.     SerialIO->io_SerFlags = SERF_SHARED; // Turn on shared mode
  1907.  
  1908.     if (OpenDevice((char *)MyArgArray[DEVICE],*(UBYTE *)MyArgArray[UNIT],
  1909.      (struct IORequest *)SerialIO,0)) {
  1910.         EasyLocRequest(CurrentPro->CurrentLayout->Window,
  1911.          &ES_DialFail, NULL, (char *)MyArgArray[DEVICE],
  1912.          *(UBYTE *)MyArgArray[UNIT]);
  1913.         CloseSerial();
  1914.     }
  1915. }
  1916.  
  1917. int DoDial(char *phonenumber)
  1918. {
  1919.     char ds[800];
  1920.     char *dialstring = ds;
  1921.     extern void __asm DialDTMF(register __a0 char *phonenumber,
  1922.                                         register __d0 unsigned int speed);
  1923.     extern void __asm DialCCITT5(register __a0 char *phonenumber,
  1924.                                         register __d0 unsigned int speed);
  1925.     
  1926.     if (!IsPhoneNumber(phonenumber)) {
  1927.         DisplayBeep(Scr);
  1928.         return RC_WARN;
  1929.     }
  1930.     /* Fix the eventual areacode stripping */
  1931.     if(!Strnicmp(phonenumber, (char *)MyArgArray[AREACODE],
  1932.      strlen((char *)MyArgArray[AREACODE])))
  1933.          phonenumber += strlen((char *)MyArgArray[AREACODE]);
  1934.  
  1935.     sprintf(dialstring,"%s%s%s\r",
  1936.      (char *)MyArgArray[DIALPREFIX],
  1937.      phonenumber,
  1938.      (char *)MyArgArray[DIALPOSTFIX]);
  1939.  
  1940.     if (MyArgArray[TONEDIAL]) {
  1941.         if (MyArgArray[CCITT5])
  1942.             DialCCITT5(phonenumber, *(UBYTE *)MyArgArray[TONEDIALSPEED]);
  1943.         else DialDTMF(phonenumber, *(UBYTE *)MyArgArray[TONEDIALSPEED]);
  1944.         return RC_OK;
  1945.     }
  1946.  
  1947.     /* Init serial device if not initialized before */
  1948.     if (!SerialMP) InitSerial();
  1949.     if (!SerialMP) return RC_ERROR;     
  1950.     SerialIO->IOSer.io_Command = CMD_WRITE;
  1951.     SerialIO->IOSer.io_Length = -1;    // Null terminated string
  1952.     SerialIO->IOSer.io_Data = dialstring;
  1953.     DoIO((struct IORequest *)SerialIO);    // Send data
  1954.     return RC_OK;
  1955. }
  1956.  
  1957.  
  1958. void DoSelect(struct Pro *Pr)
  1959. {
  1960.     /* Select records from a ListView with fields */
  1961.     struct Rec *rec;
  1962.     Select *s;
  1963.     BOOL again = TRUE;
  1964.  
  1965.     struct VisFldInfo *vf = GetVisFldInfo(CurrentPro->CurrentLayout, LastGad);
  1966.     s = Pr->CurrentLayout->Browser;
  1967.     if (!s) return; /* safety */
  1968.  
  1969.     UpdateRecord(Pr);
  1970.  
  1971.     /* Sort on the selected field first? */
  1972.     if (DB_Msg.Qualifier & IXSYM_SHIFTMASK) DoSort(Pr, vf->Offset);
  1973.  
  1974.     if (!FixSelectSize(s, Pr->RecSum)) return;        /* For speed */
  1975.  
  1976.     /* Seek first record */
  1977.     for (rec = Pr->CurrentRec; rec->Prev; rec = rec->Prev);
  1978.  
  1979.     BlockInput(Pr->CurrentLayout->Window,TRUE);     /* First a sleep clock */
  1980.  
  1981.     /* Fill the Select object */
  1982.     if (vf->Gadget->GadgetID == STRING_KIND)     /* For sake of speed, CodeToText does this also */
  1983.         for (; rec; rec = rec->Next) AddStringLast(s, GetFld(rec, vf->Offset));
  1984.  
  1985.     else     /* Cycle- and checkbox gadgets */
  1986.         for (; rec; rec = rec->Next) AddStringLast(s, CodeToText(vf, GetFld(rec, vf->Offset)));
  1987.  
  1988.     s->SelIndex = Pr->RecNum;
  1989.  
  1990.     OpenSelect(s, Pr->CurrentLayout->Window, vf->Name, GetAppStr(MSG_BROWSE_MODE_SCRMSG));
  1991.     while (again) {
  1992.         WaitPort(s->SelWnd->UserPort);
  1993.         switch(HandleSelectIDCMP(s)) {
  1994.             case SEL_SELECT :
  1995.                 JumpList(Pr, s->SelIndex - Pr->RecNum);
  1996.                 UpdateDragBar(Pr);
  1997.                 UpdateWindow(Pr);
  1998.                 break;
  1999.             case SEL_OK :
  2000.             case SEL_CANCEL :
  2001.                 again = FALSE;
  2002.                 break;
  2003.             case SEL_HELP :
  2004.                 EasyLocRequest(NULL, &ES_BrowseHelp, NULL, NULL);
  2005.                 break;
  2006.         }
  2007.     }
  2008.     FreeInput(Pr->CurrentLayout->Window);
  2009.     CloseSelect(s);
  2010.     RemoveAllStrings(s);
  2011. }
  2012.  
  2013.  
  2014. /*
  2015.  * Some more security functions
  2016.  */
  2017.  
  2018. char *stripLF(char *s)
  2019. {
  2020.     char *start;
  2021.     for (start = s; *s; s++) if (*s == '\n') *s = '\0';
  2022.     return start;
  2023. }
  2024.  
  2025. BOOL rightKey(BPTR fp)
  2026.     /* Security is turned off as the source is released.
  2027.      * I only ensure that registered users get their name displayed correctly.
  2028.      */
  2029. {
  2030. //    char correctPassWord[12];
  2031.     char userName[50];
  2032.     char userPassWord[50];
  2033.     char idBuf[10];
  2034.     
  2035.     if (FGets(fp, userName, 40) &&
  2036.          FGets(fp, idBuf, 10) &&
  2037.          FGets(fp, userPassWord, 40)) {
  2038.  
  2039.         stripLF(userName);
  2040.         stripLF(idBuf);
  2041.         stripLF(userPassWord);
  2042.         
  2043.         strcpy(UserName, userName);
  2044.         UserID = atoi(idBuf);
  2045.  
  2046.         return TRUE;
  2047.     }
  2048. }
  2049.  
  2050. BOOL checkKeyFile(void)
  2051. {
  2052.     /* Security is turned off as the source is released.
  2053.      * I only ensure that registered users get their name displayed correctly.
  2054.      */
  2055.  
  2056.     BPTR fp;
  2057.  
  2058.     if (((fp = Open("PROGDIR:db.key", MODE_OLDFILE)) ||
  2059.          (fp = Open("l:db.key", MODE_OLDFILE)) ||
  2060.          (fp = Open("s:db.key", MODE_OLDFILE))) &&
  2061.          rightKey(fp)) {
  2062.         PassWordOk = TRUE;
  2063.         Close(fp);
  2064.         return TRUE;
  2065.     }
  2066.     if (fp) Close(fp);
  2067.     return FALSE;
  2068. }
  2069.  
  2070. /**********************************************************************/
  2071. /*                                Init                                */
  2072. /**********************************************************************/
  2073.  
  2074. void Init(int argc, char *argv[])
  2075. {
  2076.     /* First open alla libraries (SAS C 6.5 handles this automatically) */
  2077.  
  2078.     UBYTE *tooltype;
  2079.     BPTR lock;
  2080.     
  2081.     if ((IntuitionBase = (struct IntuitionBase *)
  2082.         OpenLibrary("intuition.library",37)) == NULL) ByeBye();
  2083.  
  2084.     if ((GfxBase = (struct GfxBase *)
  2085.         OpenLibrary("graphics.library",37)) == NULL) ByeBye();
  2086.  
  2087.         /* For commodities tooltypes, and icon creation */
  2088.     if ((IconBase = OpenLibrary("icon.library",37)) == NULL) ByeBye();
  2089.  
  2090.     if ((CxBase = OpenLibrary("commodities.library",37)) == NULL) ByeBye();
  2091.     if ((AslBase = OpenLibrary("asl.library",37)) == NULL) ByeBye();
  2092.     if ((GadToolsBase = OpenLibrary("gadtools.library",37)) == NULL) ByeBye();
  2093.     if (!(UtilityBase = OpenLibrary("utility.library",37))) ByeBye();
  2094.     if (!(WorkbenchBase = OpenLibrary("workbench.library", 37))) ByeBye();
  2095.     if (!(IFFParseBase = OpenLibrary("iffparse.library", 37))) ByeBye();
  2096.     if (TextFieldBase = OpenLibrary(TEXTFIELD_NAME, TEXTFIELD_VER)) {
  2097.         TextFieldClass = TEXTFIELD_GetClass();
  2098.     }
  2099.     RexxSysBase = OpenLibrary(RXSNAME,0L);
  2100.  
  2101.     /* Do the argument check, and possible fail now */
  2102.     if(argc == 0)    { /* WB */
  2103.  
  2104.         /* First parse icon's ToolTypes */
  2105.         TTypes = ArgArrayInit(argc, argv);
  2106.         if (tooltype = FindToolType(TTypes,"DEVICE"))
  2107.             MyArgArray[DEVICE] = (LONG)tooltype;
  2108.         if (tooltype = FindToolType(TTypes,"UNIT"))
  2109.             *(UBYTE *)MyArgArray[UNIT] = atoi(tooltype);
  2110.         if (tooltype = FindToolType(TTypes,"DIALPREFIX"))
  2111.             MyArgArray[DIALPREFIX] = (LONG)tooltype;
  2112.         if (tooltype = FindToolType(TTypes,"DIALPOSTFIX"))
  2113.             MyArgArray[DIALPOSTFIX] = (LONG)tooltype;
  2114.         if (tooltype = FindToolType(TTypes,"AREACODE"))
  2115.             MyArgArray[AREACODE] = (LONG)tooltype;
  2116.         if (tooltype = FindToolType(TTypes,"PUBSCREEN"))
  2117.             MyArgArray[PUBSCREEN] = (LONG)tooltype;
  2118.         if (tooltype = FindToolType(TTypes,"FONTNAME"))
  2119.             MyArgArray[FONTNAME] = (LONG)tooltype;
  2120.         if (tooltype = FindToolType(TTypes,"FONTSIZE"))
  2121.             *(int *)MyArgArray[FONTSIZE] = atoi(tooltype);
  2122.         if (tooltype = FindToolType(TTypes,"NOICONS"))
  2123.             MyArgArray[NOICONS] = TRUE;
  2124.         if (tooltype = FindToolType(TTypes,"NOSPEEDRENDER"))
  2125.             MyArgArray[NOSPEEDRENDER] = TRUE;
  2126.         if (tooltype = FindToolType(TTypes,"NORETURNSTEP"))
  2127.             MyArgArray[NORETURNSTEP] = TRUE;
  2128.         if (tooltype = FindToolType(TTypes,"NOSERIAL"))
  2129.             MyArgArray[NOSERIAL] = TRUE;
  2130.         if (tooltype = FindToolType(TTypes,"HORIZBAR"))
  2131.             MyArgArray[HORIZBAR] = TRUE;
  2132.         if (tooltype = FindToolType(TTypes,"ESCQUIT"))
  2133.             MyArgArray[ESCQUIT] = TRUE;
  2134.         if (tooltype = FindToolType(TTypes,"TONEDIAL"))
  2135.             MyArgArray[TONEDIAL] = TRUE;
  2136.         if (tooltype = FindToolType(TTypes,"TONEDIALSPEED"))
  2137.             *(UBYTE *)MyArgArray[TONEDIALSPEED] = atoi(tooltype);
  2138.         if (tooltype = FindToolType(TTypes,"CCITT5"))
  2139.             MyArgArray[CCITT5] = TRUE;
  2140.         if (tooltype = FindToolType(TTypes,"MAKEBACKUP"))
  2141.             MyArgArray[MAKEBACKUP] = TRUE;
  2142.         if (tooltype = FindToolType(TTypes,"LOCALESORT"))
  2143.             MyArgArray[LOCALESORT] = TRUE;
  2144.         if (tooltype = FindToolType(TTypes,"HIGHLABEL"))
  2145.             MyArgArray[HIGHLABEL] = TRUE;
  2146.         if (tooltype = FindToolType(TTypes,"NOBORDER"))
  2147.             MyArgArray[NOBORDER] = TRUE;
  2148.     }
  2149.     else    {    /* CLI */
  2150.         if (!(MyRDArgs = ReadArgs(MyTemplate,MyArgArray,NULL))) ByeBye();
  2151.     }
  2152.     
  2153.     checkKeyFile();    /* Security */
  2154.  
  2155.     if (LocaleBase = OpenLibrary("locale.library",38)) {
  2156.         LocaleInfo.li_LocaleBase = LocaleBase;
  2157.         LocaleInfo.li_Catalog    = OpenCatalog(NULL,"db.catalog",
  2158.          OC_Version, 3, TAG_DONE);
  2159.         if (MyArgArray[LOCALESORT] && (MyLocale = OpenLocale(NULL))) {        
  2160.             /* Nothing here yet */
  2161.         }
  2162.     }
  2163.  
  2164.     /* For the Clipboard */
  2165.     if (!(Iff0 = AllocIFF())) ByeBye();
  2166.     if (!(Iff0->iff_Stream = (ULONG) OpenClipboard(0))) ByeBye();
  2167.     InitIFFasClip(Iff0);
  2168.  
  2169.     if (!(Iff1 = AllocIFF())) ByeBye();
  2170.     if (!(Iff1->iff_Stream = (ULONG) OpenClipboard(1))) ByeBye();
  2171.     InitIFFasClip(Iff1);
  2172.     
  2173.     /* Get programname and path for correct 'default tool' in icons */
  2174.     if (lock = GetProgramDir()) NameFromLock(lock, ProgramDirAndName,FMSIZE);
  2175.     AddPart(ProgramDirAndName,"db",FMSIZE);
  2176.     DataIcon.do_DefaultTool = ProgramDirAndName;
  2177.  
  2178.     if (SetupScreen()) ByeBye(); /* GadToolBox */
  2179.     if ((AWPort = CreateMsgPort()) == NULL) ByeBye();    /* AppWindow */
  2180.     if (RexxSysBase) if ((MyRexxPort = SetupRexxPort("DB")) == NULL) ByeBye();
  2181.  
  2182.     /* Get the users custom font */
  2183.     if (*(int *)MyArgArray[FONTSIZE] != -1) {    /* User wants a custom font */
  2184.         if (!(DiskfontBase = OpenLibrary("diskfont.library", 37))) ByeBye();
  2185.         UserTextAttr.ta_Name = (STRPTR)MyArgArray[FONTNAME];
  2186.         UserTextAttr.ta_YSize = *(int *)MyArgArray[FONTSIZE];
  2187.         UserTextFont = OpenDiskFont(&UserTextAttr);
  2188.     }
  2189.  
  2190.     /* Create one project and layout */
  2191.     if (!(CurrentPro = NewPro())) ByeBye();
  2192.     if (!NewLayout(CurrentPro)) ByeBye();
  2193.  
  2194.     HandleArgs(argc, argv); /* Read arguments (CLI/WB) and open window and file */
  2195.  
  2196. }
  2197.  
  2198. /**********************************************************************/
  2199. /*            Eventhandlers that GadToolBox calls directly            */
  2200. /**********************************************************************/
  2201.  
  2202. void VisFldSelected(struct Gadget *gad)
  2203. {
  2204.     CurrentPro->Modified |= RECMODIFIED;
  2205.     /* Update the Rexx current field offset now */
  2206.     CurrentPro->CurrentFldOffset = GetVisFldInfo(CurrentPro->CurrentLayout, gad)->Offset;
  2207. }
  2208.  
  2209.  
  2210. void DragGadgetSelected(void)
  2211. {
  2212.     switch (CurrentPro->Mode) {
  2213.     case MODE_NORMAL:    
  2214.         UpdateRecord(CurrentPro);
  2215.         JumpList(CurrentPro,DB_Msg.Code - CurrentPro->RecNum);
  2216.         UpdateDragBar(CurrentPro);    /* This "snaps" the dragbar correctly */
  2217.         UpdateWindow(CurrentPro);
  2218.         break;
  2219.     case MODE_FIND:
  2220.     case MODE_SORT:
  2221.         break;
  2222.     }
  2223. }
  2224.  
  2225.  
  2226. void DoKill(BOOL ask)
  2227. {
  2228.     /* If ask is FALSE then no questions will be asked, (used by DB_CUT) */ 
  2229.     struct Layout *lay = CurrentPro->CurrentLayout;
  2230.     struct VisFldInfo *vf=lay->FirstVisFldInfo;
  2231.     BOOL empty = TRUE;
  2232.  
  2233.     switch (CurrentPro->Mode) {
  2234.     case MODE_NORMAL:
  2235.         for (; vf; vf = vf->Next) if (strlen(ReadVisFld(CurrentPro, vf))) empty = FALSE;
  2236.         
  2237.         if (!empty) if (DisplayWarnings && ask)
  2238.             if (!EasyLocRequest(CurrentPro->CurrentLayout->Window,
  2239.              &ES_KillWarn, NULL, NULL)) break;
  2240.  
  2241.         if (KillRecord(CurrentPro) == TRUE) {
  2242.             UpdateDragBar(CurrentPro);
  2243.             UpdateWindow(CurrentPro);
  2244.             CurrentPro->Modified |= PROMODIFIED;
  2245.         }
  2246.         else DisplayBeep(Scr);
  2247.         break;
  2248.     case MODE_FIND:
  2249.         /* Just clear the fields */
  2250.         ClearRecord(CurrentPro->FindRec);
  2251.         UpdateGadgets(CurrentPro);
  2252.         break;
  2253.     case MODE_SORT:
  2254.         ClearRecord(CurrentPro->SortRec); /* InitSortRecord(CurrentPro); */
  2255.         UpdateGadgets(CurrentPro);
  2256.         break;
  2257.     }
  2258.  
  2259. }
  2260.  
  2261. int DB_KILL( void )
  2262. {
  2263.     /* routine when (sub)item "Kill" is selected. */
  2264.     DoKill(TRUE);
  2265.     return 0;
  2266. }
  2267.  
  2268. int DB_NEW( void )
  2269. {
  2270.     /* routine when (sub)item "New" is selected. */
  2271.     UpdateRecord(CurrentPro);
  2272.     if    (CurrentPro->Modified & PROMODIFIED)  /* File modified */  
  2273.         if    (!EasyLocRequest(CurrentPro->CurrentLayout->Window, &ES_NewWarn, NULL, NULL)) return 0;
  2274.  
  2275.     if (ClearPro(CurrentPro) == FALSE) ByeBye();
  2276.     strcpy(CurrentPro->Name,GetAppStr(MSG_UNTITLED_PRO));
  2277.     /* We save the current drawer as the user will probably want that */
  2278.     UpdateDragBar(CurrentPro);
  2279.     UpdateWindow(CurrentPro);
  2280.  
  2281.     return 0;
  2282. }
  2283.  
  2284. int DB_OPEN( void )
  2285. {
  2286.     /* routine when (sub)item "Open..." is selected. */
  2287.    struct FileRequester *fr;
  2288.  
  2289.     /* NewPro will be called which in turn calls SetProMode so we don't have to */
  2290.  
  2291.     /* By supplying the dimension tags to AllocAslRequest, PD programs like */
  2292.     /* SetASLDim may modify the size to the users preference */
  2293.    fr = AllocAslRequest(ASL_FileRequest, frtags);
  2294.  
  2295.     if (AslRequestTags(fr,ASLFR_Window,CurrentPro->CurrentLayout->Window,
  2296.      ASLFR_SleepWindow, TRUE,
  2297.      ASLFR_TitleText,GetAppStr(MSG_OPEN_ASLREQ_TITLE),
  2298.      ASLFR_InitialDrawer, CurrentPro->Drawer,
  2299.      ASLFR_InitialFile, CurrentPro->Name,
  2300.      TAG_DONE)) LoadPro(fr->fr_Drawer,fr->fr_File);
  2301.     
  2302.     FreeAslRequest(fr);
  2303.     if (!CurrentPro) ByeBye();
  2304.     return 1;    /* Old window closed, GadToolBox must ignore extra menuevents */
  2305. }
  2306.  
  2307. int DB_SAVEAS( void )
  2308. {
  2309.     /* routine when (sub)item "Save as..." is selected. */
  2310.     Save(CurrentPro,SAVE_PRO);
  2311.     return 0;
  2312. }
  2313.  
  2314. int DB_SAVE( void )
  2315. {
  2316.     /* routine when (sub)item "Save" is selected. */
  2317.      {
  2318.         if (Stricmp(CurrentPro->Name,GetAppStr(MSG_UNTITLED_PRO))) /* File saved before */
  2319.             SavePro(CurrentPro,CurrentPro->Drawer,CurrentPro->Name,SAVE_PRO, FALSE);
  2320.         else DB_SAVEAS();
  2321.     }
  2322.     return 0;
  2323. }
  2324.  
  2325. int DB_OUTPUT_VIEW( void )
  2326. {
  2327.     /* routine when (sub)item "Output view..." is selected. */
  2328.     Save(CurrentPro,SAVE_VIEW);
  2329.     return 0;
  2330. }
  2331.  
  2332. int DB_OUTPUT_VIEW_WN( void )
  2333. {
  2334.     /* routine when (sub)item "Output view with names..." is selected. */
  2335.     Save(CurrentPro,SAVE_VIEW_WN);
  2336.     return 0;
  2337. }
  2338.  
  2339. int DB_OUTPUT_TAB_ASCII( void )
  2340. {
  2341.     /* routine when (sub)item "Output Tab ASCII..." is selected. */
  2342.     Save(CurrentPro,SAVE_TAB_ASCII);
  2343.     return 0;
  2344. }
  2345.  
  2346. int DB_OUTPUT_COMMA_ASCII( void )
  2347. {
  2348.     /* routine when (sub)item "Output Comma ASCII..." is selected. */
  2349.     Save(CurrentPro,SAVE_COMMA_ASCII);
  2350.     return 0;
  2351. }
  2352.  
  2353. int DB_ABOUT( void )
  2354. {
  2355.     /* routine when (sub)item "About..." is selected. */
  2356.     if (!EasyLocRequest(CurrentPro->CurrentLayout->Window, &ES_About, NULL, 
  2357.      &Version[9], MyRexxPortName, UserName, UserID))
  2358.         if (!EasyLocRequest(CurrentPro->CurrentLayout->Window, &ES_MoreAbout, NULL, NULL))
  2359.             EasyLocRequest(CurrentPro->CurrentLayout->Window, &ES_MH_RFF, NULL, NULL);
  2360.  
  2361.     return 0;
  2362. }
  2363.  
  2364. int DB_QUIT( void )
  2365. {
  2366.     /* routine when (sub)item "Quit" is selected. */
  2367.     HandleQuit(CurrentPro);
  2368.     return 0;
  2369. }
  2370.  
  2371. int DB_COPY( void )
  2372. {
  2373.     /* routine when (sub)item "Copy" is selected. */
  2374.     UpdateRecord(CurrentPro);
  2375.     if (!CopyToClipboard(CurrentPro)) DisplayBeep(Scr);
  2376.     return 0;
  2377. }
  2378.  
  2379. int DB_CUT( void )
  2380. {
  2381.     /* routine when (sub)item "Cut" is selected. */
  2382.     DB_COPY();
  2383.     DoKill(FALSE);
  2384.     return 0;
  2385. }
  2386.  
  2387. int DB_PASTE( void )
  2388. {
  2389.     /* routine when (sub)item "Paste" is selected. */
  2390.     struct Rec *rp, *crp;
  2391.  
  2392.     switch (CurrentPro->Mode) {
  2393.     case MODE_NORMAL:    
  2394.             if (!(rp = NewRecord())) {
  2395.                 EasyLocRequest(CurrentPro->CurrentLayout->Window, &ES_MemWarn, NULL, NULL);
  2396.                 break;
  2397.             }
  2398.             if (!PasteFromClipboard(CurrentPro, rp)) {
  2399.                 DeleteRecord(&rp);
  2400.                 break;
  2401.             }
  2402.             /* Everything ok, now link it */
  2403.             crp = CurrentPro->CurrentRec;
  2404.             rp->Next = crp->Next;                    /* Curr  New->Next */
  2405.             crp->Next = rp;                            /* Curr->New  Next */
  2406.             rp->Prev = crp;                            /* Curr<-New  Next */
  2407.             if (rp->Next) rp->Next->Prev = rp;    /* Curr  New<-Next */
  2408.  
  2409.             UpdateRecord(CurrentPro);
  2410.             CurrentPro->CurrentRec = CurrentPro->CurrentRec->Next;
  2411.             CurrentPro->RecSum++;
  2412.             CurrentPro->RecNum++;
  2413.             UpdateDragBar(CurrentPro);
  2414.             UpdateWindow(CurrentPro);
  2415.             CurrentPro->Modified |= PROMODIFIED;
  2416.             break;
  2417.     case MODE_FIND:
  2418.         PasteFromClipboard(CurrentPro, CurrentPro->FindRec);
  2419.         UpdateGadgets(CurrentPro);
  2420.         break;
  2421.     case MODE_SORT:
  2422.         PasteFromClipboard(CurrentPro, CurrentPro->SortRec);
  2423.         UpdateGadgets(CurrentPro);
  2424.         break;
  2425.     }
  2426.     return 0;
  2427. }
  2428.  
  2429. __inline static BOOL OkStrGad(struct Gadget *g)    /* Duplicate from dbGUI.c */
  2430. {
  2431.     return (BOOL)(g->Flags & GFLG_TABCYCLE && !(g->Flags & GFLG_DISABLED));
  2432. }
  2433.  
  2434. int DB_ADD( void )
  2435. {
  2436.     struct VisFldInfo *vf;
  2437.     /* routine when (sub)item "Add" is selected. */
  2438.     switch (CurrentPro->Mode) {
  2439.     case MODE_NORMAL:
  2440.         if (AddRecord(&CurrentPro->CurrentRec)) {
  2441.             UpdateRecord(CurrentPro);
  2442.             CurrentPro->CurrentRec = CurrentPro->CurrentRec->Next;
  2443.             CurrentPro->RecSum++;
  2444.             CurrentPro->RecNum++;
  2445.             UpdateDragBar(CurrentPro);
  2446.             UpdateWindow(CurrentPro);
  2447.  
  2448.             for (vf = CurrentPro->CurrentLayout->FirstVisFldInfo; vf; vf = vf->Next) {
  2449.                 if (OkStrGad(vf->Gadget)) {
  2450.                     LastGad = vf->Gadget;
  2451.                     VisFldSelected(vf->Gadget);
  2452.                     ActivateGadget(vf->Gadget, CurrentPro->CurrentLayout->Window, NULL);
  2453.                     break;
  2454.                 }
  2455.             }
  2456.         }
  2457.         else EasyLocRequest(CurrentPro->CurrentLayout->Window, &ES_MemWarn, NULL, NULL);
  2458.         break;
  2459.     }
  2460.     return 0;
  2461. }
  2462.  
  2463. int LayIndex(struct Layout *first, struct Layout *current)
  2464. {
  2465.     int i;
  2466.     for (i=0; first && first != current; first = first->NextLayout, i++);
  2467.     return i;
  2468. }
  2469.  
  2470. int ChangeView(struct Layout *lay)
  2471. {
  2472.     /* This new version is a "hack". If there are problems, use older versions */
  2473.  
  2474.     /* If lay is NULL, use the menu instead (ARexx reason) */
  2475.     /* routine when one of the "View" items are selected. */
  2476.     /* We check if the menuitem really is checked first. */
  2477.     /* (User may play around with both mousebuttons, activating */
  2478.     /* menuitems without checking them.) */
  2479.  
  2480.     struct MenuItem *m;
  2481.     struct Layout *oldlay;
  2482.     int retval, viewnum;
  2483.     WORD ww, wh;
  2484.  
  2485.     oldlay = CurrentPro->CurrentLayout;
  2486.     if (!lay) {
  2487.         m = ItemAddress(CurrentPro->Menu, DB_Msg.Code);
  2488.         if (!(m->Flags & CHECKED)) return 0;
  2489.         viewnum = ITEMNUM(DB_Msg.Code);
  2490.         for (lay = CurrentPro->FirstLayout; viewnum; viewnum--, lay = lay->NextLayout);
  2491.     }
  2492.     else {
  2493.         m = ItemAddress(CurrentPro->Menu, FULLMENUNUM(2, LayIndex(CurrentPro->FirstLayout, oldlay), NOSUB));
  2494.         m->Flags &= ~CHECKED;    /* Delete old checkmark */
  2495.         m = ItemAddress(CurrentPro->Menu, FULLMENUNUM(2, LayIndex(CurrentPro->FirstLayout, lay), NOSUB));
  2496.         m->Flags |= CHECKED;    /* Set new checkmark */
  2497.     }
  2498.  
  2499.     UpdateRecord(CurrentPro);
  2500.     if (!lay || (lay==oldlay)) return 0;
  2501.  
  2502.     DeleteAllGadgets(oldlay, USE_MODE);
  2503.     
  2504.     CurrentPro->CurrentLayout = lay;
  2505.     lay->Window = oldlay->Window; /* We use the same window now */
  2506.     lay->AppWin = oldlay->AppWin;
  2507.     oldlay->Window = NULL;
  2508.     oldlay->AppWin = NULL;
  2509.  
  2510.     if ((retval = CalcAllPos(CurrentPro, CurrentPro->CurrentLayout, &ww, &wh)) < 0) {
  2511.         ShowError(retval,NULL);
  2512.         /* Try to fall back to the old layout */
  2513.         CurrentPro->CurrentLayout = oldlay;
  2514.         oldlay->Window = lay->Window; /* We use the same window now */
  2515.         oldlay->AppWin = lay->AppWin; /* We use the same window now */
  2516.         lay->Window = NULL;
  2517.         lay->AppWin = NULL;
  2518.  
  2519.         /* Correct the checkmark so it indicates this window */
  2520.         
  2521.         m->Flags &= ~CHECKED;    /* Delete old checkmark */
  2522.         m = ItemAddress(CurrentPro->Menu, FULLMENUNUM(2, LayIndex(CurrentPro->FirstLayout, oldlay), NOSUB));
  2523.         m->Flags |= CHECKED;    /* Set new checkmark */
  2524.  
  2525.         if ((retval = CalcAllPos(CurrentPro, CurrentPro->CurrentLayout, &ww, &wh)) < 0) {
  2526.             ShowError(retval,NULL);
  2527.             ByeBye();
  2528.         }
  2529.     }
  2530.     CreateAllGadgets(CurrentPro, CurrentPro->CurrentLayout, ww, wh, USE_MODE);
  2531.     AttachAllGadgets(CurrentPro->CurrentLayout, ww, wh, USE_MODE);
  2532.     UpdateWindow(CurrentPro);
  2533.     UpdateDragBar(CurrentPro);
  2534.  
  2535.     return 0;
  2536. }
  2537.  
  2538. int DB_VIEW() {
  2539.     return ChangeView(NULL);
  2540. }
  2541.  
  2542. /*
  2543. int DB_VIEW( void )
  2544. {
  2545.     /* routine when one of the "View" items are selected. */
  2546.     /* We check if the menuitem really is checked first. */
  2547.     /* (User may play around with both mousebuttons, activating */
  2548.     /* menuitems without checking them.) */
  2549.  
  2550.     struct MenuItem *m;
  2551.     struct Layout *lay, *oldlay;
  2552.     int i,pronum,retval;
  2553.  
  2554.     oldlay = CurrentPro->CurrentLayout;
  2555.     m = ItemAddress(CurrentPro->Menu, DB_Msg.Code);
  2556.     if (!(m->Flags & CHECKED)) return 0;
  2557.     
  2558.     UpdateRecord(CurrentPro);
  2559.  
  2560.     pronum = ITEMNUM(DB_Msg.Code);
  2561.     for (lay=CurrentPro->FirstLayout,i=0; lay && (i<pronum); lay=lay->NextLayout, i++);
  2562.     if (!lay || (lay==oldlay)) return 0;
  2563.     
  2564.     CloseLayWin(CurrentPro, oldlay);
  2565.     CurrentPro->CurrentLayout = lay;
  2566.     if ((retval = OpenLayWin(CurrentPro, CurrentPro->CurrentLayout)) < 0) {
  2567.         ShowError(retval,NULL);
  2568.         /* Try to fall back to the old layout */
  2569.         CurrentPro->CurrentLayout = oldlay;
  2570.  
  2571.         /* Correct the checkmark so it indicates this window */
  2572.         for (lay=CurrentPro->FirstLayout,i=0; lay != oldlay; lay=lay->NextLayout, i++);
  2573.         
  2574.         m->Flags &= ~CHECKED;    /* Delete old checkmark */
  2575.         m = ItemAddress(CurrentPro->Menu, FULLMENUNUM(2,i,NOSUB));
  2576.         m->Flags |= CHECKED;    /* Set new checkmark */
  2577.  
  2578.         if ((retval = OpenLayWin(CurrentPro, CurrentPro->CurrentLayout)) < 0) {
  2579.             ShowError(retval,NULL);
  2580.             ByeBye();
  2581.         }
  2582.     }
  2583.     UpdateWindow(CurrentPro);
  2584.     UpdateDragBar(CurrentPro);
  2585.  
  2586.     return 1;    /* The old window is closed, so don't access more items */
  2587. }
  2588.  
  2589. */
  2590.  
  2591. int DB_FIND( void )
  2592. {
  2593.     /* routine when (sub)item "Find..." is selected. */
  2594. //    UpdateRecord(CurrentPro);    /* We are going to leave this record */
  2595.     SetProMode(CurrentPro,MODE_FIND);
  2596.     return 0;
  2597. }
  2598.  
  2599. int DB_FINDNEXT( void )
  2600. {
  2601.     /* routine when (sub)item "Find next" is selected. */
  2602.     if (CurrentPro->Mode != MODE_SORT) 
  2603.      FindRecord(CurrentPro,CurrentPro->RecNum+1,1);
  2604.     return 0;
  2605. }
  2606.  
  2607. int DB_SORT( void )
  2608. {
  2609.  
  2610.     /* routine when (sub)item "Sort" is selected. */
  2611. //    UpdateRecord(CurrentPro);    /* We are going to leave this record */
  2612.     SetProMode(CurrentPro,MODE_SORT);
  2613.     return 0;
  2614. }
  2615.  
  2616. int DB_DIAL( void )
  2617. {
  2618.     /* routine when (sub)item "Dial" is selected. */
  2619.     DoDial(ReadVisFld(CurrentPro, GetVisFldInfo(CurrentPro->CurrentLayout, LastGad)));
  2620.     return 0;
  2621. }
  2622.  
  2623. int DB_BROWSE( void )
  2624. {
  2625.     /* routine when (sub)item "Browse..." is selected. */
  2626.     if (LastGad) DoSelect(CurrentPro);
  2627.     else DisplayBeep(Scr);
  2628.     return 0;
  2629. }
  2630.  
  2631. int DB_WARNINGS( void )
  2632. {
  2633.     /* routine when (sub)item "Display warnings" is selected. */
  2634.  
  2635.     struct MenuItem *m;
  2636.     m = ItemAddress(CurrentPro->CurrentLayout->Window->MenuStrip, DB_Msg.Code);
  2637.     if (m->Flags & CHECKED) DisplayWarnings = TRUE;
  2638.     else DisplayWarnings = FALSE;
  2639.  
  2640.     return 0;
  2641. }
  2642.  
  2643. int DB_AZ( void )
  2644. {
  2645.     /* routine when (sub)item "A-Z" is selected. */
  2646.     /* We check if the menuitem really is checked first. */
  2647.     /* (User may play around with both mousebuttons on the menus, activating */
  2648.     /* menuitems without checking them.) */
  2649.     struct MenuItem *m;
  2650.     m = ItemAddress(CurrentPro->CurrentLayout->Window->MenuStrip, DB_Msg.Code);
  2651.     if (m->Flags & CHECKED) SI.SortDir = SORT_DIR_AZ;
  2652.     return 0;
  2653. }
  2654.  
  2655. int DB_ZA( void )
  2656. {
  2657.     /* routine when (sub)item "Z-A" is selected. */
  2658.     /* We check if the menuitem really is checked first. */
  2659.     /* (User may play around with both mousebuttons on the menus, activating */
  2660.     /* menuitems without checking them.) */
  2661.     struct MenuItem *m;
  2662.     m = ItemAddress(CurrentPro->CurrentLayout->Window->MenuStrip, DB_Msg.Code);
  2663.     if (m->Flags & CHECKED) SI.SortDir = SORT_DIR_ZA;
  2664.     return 0;
  2665. }
  2666.  
  2667. /*
  2668. int DB_SAVESETTINGS( void )
  2669. {
  2670.     /* routine when (sub)item "Save settings..." is selected. */
  2671.     return 0;
  2672. }
  2673. */
  2674.  
  2675. int DB_FIELD_DEFINITION( void )
  2676. {
  2677.     /* routine when (sub)item "Field definition" is selected. */
  2678.     return 0;
  2679. }
  2680.  
  2681. int DB_VIEW_DESIGN( void )
  2682. {
  2683.     /* routine when (sub)item "View design" is selected. */
  2684.     UpdateRecord(CurrentPro);
  2685.     Design(CurrentPro, CurrentPro->CurrentLayout);
  2686.     return 1; /* Window has been closed and a new has been opened */
  2687. }
  2688.  
  2689. int DB_EXECUTE_AREXX( void )
  2690. {
  2691.     /* routine when (sub)item "Execute ARexx script..." is selected. */
  2692.    struct FileRequester *fr;
  2693.     char fullname[FMSIZE];
  2694.     BOOL error = FALSE;
  2695.  
  2696.     if (!MyRexxPort) {
  2697.         DisplayBeep(Scr);
  2698.         return 0;
  2699.     }
  2700.  
  2701.     /* By supplying the dimension tags to AllocAslRequest, PD programs like */
  2702.     /* SetASLDim may modify the size to the users preference */
  2703.    fr = AllocAslRequest(ASL_FileRequest, frtags);
  2704.  
  2705.     if (AslRequestTags(fr,ASLFR_Window,CurrentPro->CurrentLayout->Window,
  2706.      ASLFR_SleepWindow, TRUE,
  2707.      ASLFR_TitleText,GetAppStr(MSG_EXECUTE_AREXX_ASLREQ_TITLE),
  2708.      ASLFR_InitialDrawer, CurrentPro->ARexxDrawer,
  2709.      ASLFR_InitialFile, CurrentPro->ARexxName,
  2710.      TAG_DONE)) {
  2711.         strcpy(fullname, fr->fr_Drawer);
  2712.         if (!AddPart(fullname, fr->fr_File, FMSIZE-1)) error = TRUE; /* incorrect filename */
  2713.     }
  2714.     else error = TRUE;
  2715.  
  2716.     strcpy(CurrentPro->ARexxDrawer, fr->fr_Drawer);
  2717.     strcpy(CurrentPro->ARexxName,fr->fr_File);
  2718.  
  2719.     FreeAslRequest(fr);
  2720.  
  2721.     if (!error) SendRexxCommand(fullname);    
  2722.     return 0;
  2723. }
  2724.  
  2725.  
  2726. void DoARexxMenu(int num)
  2727. {
  2728.     /* Execute an ARexx script on the menu. */
  2729.     int i;
  2730.     struct RxInfo *ri;
  2731.     struct RFFTag *tag;
  2732.  
  2733.     for (ri=CurrentPro->FirstRxInfo,i=0; ri && (i<num); ri=ri->Next, i++);
  2734.  
  2735.     if (ri && (tag = FindTag(&ri->RxTags, RXSTRING)))
  2736.         SendRexxStrCommand(tag->Data);
  2737.     else if (ri && (tag = FindTag(&ri->RxTags, RXFILE)))
  2738.         SendRexxCommand(tag->Data);
  2739. }
  2740.  
  2741. int DB_AREXX( void )
  2742. {
  2743.     /* routine when an item in the ARexx menu is selected. */
  2744.     int num;
  2745.  
  2746.     num = ITEMNUM(DB_Msg.Code) - 1;
  2747.     DoARexxMenu(num);
  2748.     return 0;
  2749. }
  2750.  
  2751. int DB_NewSize( void )
  2752. {
  2753.     /* routine for "IDCMP_NEWSIZE". */
  2754.     if (MyArgArray[NOBORDER]) return 0;
  2755.  
  2756.     SpeedRenderOff(CurrentPro->CurrentLayout);
  2757.     if (CurrentPro->CurrentLayout->FirstVisFldInfo)
  2758.     RefreshGList(CurrentPro->CurrentLayout->FirstVisFldInfo->Gadget, CurrentPro->CurrentLayout->Window, NULL, -1);
  2759.     if (!(SpeedRenderOn(CurrentPro->CurrentLayout))) ByeBye();
  2760.  
  2761.     return 0;
  2762. }
  2763.  
  2764. int DB_CloseWindow( void )
  2765. {
  2766.     /* routine for "IDCMP_CLOSEWINDOW". */
  2767.     switch (CurrentPro->Mode) {
  2768.         case MODE_NORMAL:
  2769.             HandleQuit(CurrentPro);
  2770.             break;
  2771.         case MODE_FIND: /* Abort find mode */
  2772.         case MODE_SORT: /* Abort sort mode */
  2773. //            UpdateRecord(CurrentPro);
  2774.             SetProMode(CurrentPro,MODE_NORMAL);
  2775.             break;
  2776.     }
  2777.     return 0;
  2778. }
  2779.  
  2780. int DB_MenuHelp( void )
  2781. {
  2782.     /* routine for "IDCMP_MENUHELP". */
  2783.     struct EasyStruct *HelpText = &ES_MH_NoHelp;
  2784.     USHORT menuNum, itemNum, subNum;
  2785.  
  2786.     menuNum = MENUNUM(DB_Msg.Code);
  2787.     itemNum = ITEMNUM(DB_Msg.Code);
  2788.     subNum  = SUBNUM(DB_Msg.Code);
  2789.  
  2790.     switch (menuNum) {
  2791.     case 0:      /* Project Menu */
  2792.         switch (itemNum) {
  2793.         case NOITEM: break;
  2794.         case 0:
  2795.             HelpText = &ES_MH_New;
  2796.             break;
  2797.         case 1:
  2798.         case 3:
  2799.         case 4: HelpText = &ES_MH_RFF; break;
  2800.         case 5:
  2801.             switch (subNum) {
  2802.             case NOSUB: break;
  2803.             case 0: HelpText = &ES_MH_Output_View; break;
  2804.             case 1: HelpText = &ES_MH_Output_View_WN; break;
  2805.             case 2: HelpText = &ES_MH_tab_ASCII; break;
  2806.             case 3: HelpText = &ES_MH_comma_ASCII; break;
  2807.             }
  2808.             break;
  2809.         }
  2810.         break;
  2811.  
  2812.     case 1:      /* Edit Menu */
  2813.         switch (itemNum) {
  2814.         case NOITEM: break;
  2815.         case 0:
  2816.         case 1:
  2817.         case 2: HelpText = &ES_MH_Clip; break;
  2818.         case 6: HelpText = &ES_MH_Kill; break;
  2819.         }
  2820.         break;
  2821.     case 2:         /* View Menu */
  2822.         break;
  2823.     case 3:      /* Action Menu */
  2824.         switch (itemNum) {
  2825.         case NOITEM: break;
  2826.         case 0:
  2827.         case 1: HelpText = &ES_FindHelp; break;
  2828.         case 3: HelpText = &ES_SortHelp; break;
  2829.         case 4: HelpText = &ES_DialHelp; break;
  2830.         case 5: HelpText = &ES_BrowseHelp; break;
  2831.         }
  2832.         break;
  2833.  
  2834.     case 4:      /* Settings Menu */
  2835.         switch (itemNum) {
  2836.         case NOITEM: break;
  2837.         case 0: HelpText = &ES_MH_Warnings; break;
  2838.         case 1:
  2839.             switch (subNum) {
  2840.             case NOSUB: HelpText = &ES_MH_SortDir; break;
  2841.             case 0: HelpText = &ES_MH_SortDir; break;
  2842.             case 1: HelpText = &ES_MH_SortDir; break;
  2843.             }
  2844.             break;
  2845.         case 3: HelpText = &ES_MH_Field_Definition; break;
  2846.         case 4: HelpText = &ES_MH_View_Design; break;
  2847.         }
  2848.         break;
  2849.     case 5:        /* ARexx menu */
  2850.         HelpText = &ES_MH_ARexx; break;
  2851.         break;
  2852.  
  2853.     case NOMENU: /* No menu selected, can happen with IDCMP_MENUHELP */
  2854.         break;
  2855.     }
  2856.     EasyLocRequest(CurrentPro->CurrentLayout->Window, HelpText, NULL, NULL);
  2857.     return 0;
  2858. }
  2859.  
  2860.  
  2861. int DB_SpecialAction(BOOL async)
  2862. {
  2863.     /* Routine called when user doubleclicks a stringgadget or hits LAMIGA+Key */
  2864.  
  2865.     LONG rxfiletagID, rxstrtagID;
  2866.     struct RFFTag *rxtag;
  2867.     BOOL success;
  2868.  
  2869.     if (!MyRexxPort || (CurrentPro->Mode != MODE_NORMAL)) return 0;
  2870.  
  2871.     if (!async) {    /* ie also use the AUTORX tags */
  2872.         rxfiletagID = AUTORXFILE;
  2873.         rxstrtagID = AUTORXSTRING;
  2874.     }
  2875.     else {
  2876.         rxfiletagID = RXFILE;
  2877.         rxstrtagID = RXSTRING;
  2878.     }
  2879.  
  2880.     if (rxtag = SearchTags(CurrentPro, NULL, NULL, rxstrtagID, rxfiletagID))
  2881.         if (rxtag->ID == rxstrtagID) success = SendRexxStrCommand(rxtag->Data);
  2882.         else success = SendRexxCommand(rxtag->Data);
  2883.  
  2884.     else if (async) 
  2885.         DoSelect(CurrentPro); /* Select records from a ListView with fields */
  2886.  
  2887.     if (async) return 0;
  2888.     else if (success) {
  2889.         do WaitPort(MyRexxPort);
  2890.         while (!HandleRexxMessage(MyRexxPort));
  2891.     }
  2892.     return 0;
  2893. }
  2894.  
  2895.  
  2896. int DB_VanillaKey( void )
  2897. {
  2898.     /* routine for "IDCMP_VANILLAKEY". */
  2899.  
  2900.     struct VisFldInfo *vf;
  2901.     char shortcut, *cursor;
  2902.  
  2903.  
  2904.     switch (DB_Msg.Code) {
  2905.  
  2906.         case '\r' :
  2907.             switch (CurrentPro->Mode) {
  2908.             case MODE_FIND:    /* Start find */
  2909.                 FindRecord(CurrentPro,0,1);
  2910.                 break;
  2911.             case MODE_SORT:    /* Start sort */
  2912.                 DoSort(CurrentPro, NORMAL_SORT);
  2913.                 break;
  2914.             case MODE_NORMAL:    /* Find next */
  2915.                 if (DB_Msg.Qualifier & IXSYM_SHIFTMASK) {
  2916.                     FindRecord(CurrentPro,CurrentPro->RecNum-1,-1);
  2917.                 } else FindRecord(CurrentPro,CurrentPro->RecNum+1,1);
  2918.                 break;
  2919.             }
  2920.             break;
  2921.  
  2922.         case VANILLA_ESC :
  2923.             switch (CurrentPro->Mode) {
  2924.                 case MODE_NORMAL:
  2925.                     if (MyArgArray[ESCQUIT]) HandleQuit(CurrentPro);
  2926.                     break;
  2927.                 case MODE_FIND: /* Abort find mode */
  2928.                 case MODE_SORT: /* Abort sort mode */
  2929. //                    UpdateRecord(CurrentPro);
  2930.                     SetProMode(CurrentPro,MODE_NORMAL);
  2931.                     break;
  2932.             }
  2933.             break;
  2934.  
  2935.         case VANILLA_DEL :
  2936.             break;
  2937.  
  2938.         case '\t' :
  2939.             if (CurrentPro->CurrentLayout->FirstVisFldInfo)
  2940.                 ActivateGadget(LastGad, CurrentPro->CurrentLayout->Window, NULL);
  2941.             break;
  2942.  
  2943.         case ' ' :    /* A fast way to switch to search mode and clear the fields */
  2944. //            UpdateRecord(CurrentPro);
  2945.             SetProMode(CurrentPro,MODE_FIND);
  2946.             DoKill(TRUE);
  2947.             break;
  2948.  
  2949.         default :         /* Key-activation of gadgets or SpecialAction() */
  2950.             for (vf = CurrentPro->CurrentLayout->FirstVisFldInfo; vf; vf = vf->Next) {
  2951.                 for (shortcut = '\0', cursor = vf->Name; *cursor; cursor++) {
  2952.                     if (*cursor == '_') {
  2953.                         shortcut = *(cursor+1);
  2954.                         break;
  2955.                     }
  2956.                 }
  2957.  
  2958.                 if (ToUpper(DB_Msg.Code) == ToUpper(shortcut)) {
  2959.                     if (DB_Msg.Qualifier & IEQUALIFIER_LCOMMAND) {
  2960.                         LastGad = vf->Gadget;
  2961.                         CurrentPro->CurrentFldOffset = vf->Offset;
  2962.                         DB_SpecialAction(TRUE);
  2963.                     }
  2964.                     else MyActivateGadget(vf, CurrentPro->CurrentLayout->Window);
  2965.                     break;
  2966.                 }
  2967.             }
  2968.             break;
  2969.     }
  2970.     return 0;
  2971. }
  2972.  
  2973. int DB_RawKey( void )
  2974. {
  2975.     /* routine for "IDCMP_RAWKEY". */
  2976.  
  2977.     /* dirty fix for HORIZBAR */
  2978.     if (MyArgArray[HORIZBAR]) {
  2979.         switch (DB_Msg.Code) {
  2980.             case RAW_LEFT : DB_Msg.Code = RAW_UP; break;
  2981.             case RAW_RIGHT : DB_Msg.Code = RAW_DOWN; break;
  2982.         }
  2983.     }    
  2984.     switch (DB_Msg.Code) {
  2985.  
  2986.         case RAW_UP :
  2987.             switch (CurrentPro->Mode) {
  2988.             case MODE_NORMAL:
  2989.                 if (CurrentPro->RecNum > 0) {
  2990.                     UpdateRecord(CurrentPro);
  2991.                     if (DB_Msg.Qualifier & IXSYM_SHIFTMASK) {
  2992.                         JumpList(CurrentPro,-CurrentPro->RecNum);
  2993.                     }
  2994.                     else JumpList(CurrentPro, -1);
  2995.                     UpdateDragBar(CurrentPro);
  2996.                     UpdateWindow(CurrentPro);
  2997.                 }
  2998.                 if (ReactivateGad)
  2999.                  ActivateGadget(LastGad, CurrentPro->CurrentLayout->Window, NULL);
  3000.                 break;
  3001.             }
  3002.             break;
  3003.  
  3004.         case RAW_DOWN:
  3005.             switch (CurrentPro->Mode) {
  3006.             case MODE_NORMAL:
  3007.                 if (CurrentPro->RecNum < (CurrentPro->RecSum-1)) {
  3008.                     UpdateRecord(CurrentPro);
  3009.                     if (DB_Msg.Qualifier & IXSYM_SHIFTMASK) {
  3010.                         JumpList(CurrentPro,CurrentPro->RecSum-CurrentPro->RecNum-1);
  3011.                     }
  3012.                     else JumpList(CurrentPro, 1);
  3013.                     UpdateDragBar(CurrentPro);
  3014.                     UpdateWindow(CurrentPro);
  3015.                 }
  3016.                 if (ReactivateGad)
  3017.                  ActivateGadget(LastGad, CurrentPro->CurrentLayout->Window, NULL);
  3018.                 break;
  3019.             }
  3020.             break;
  3021.  
  3022.         case RAW_TAB:
  3023.             ActivateGadget(LastGad, CurrentPro->CurrentLayout->Window, NULL);
  3024.             break;
  3025.         
  3026.         case RAW_HELP:
  3027.             switch (CurrentPro->Mode) {
  3028.             case MODE_NORMAL:
  3029.                 EasyLocRequest(CurrentPro->CurrentLayout->Window, &ES_NormalHelp, NULL, NULL);
  3030.                 break;
  3031.             case MODE_FIND:
  3032.                 EasyLocRequest(CurrentPro->CurrentLayout->Window, &ES_FindHelp, NULL, NULL);
  3033.                 break;
  3034.             case MODE_SORT:
  3035.                 EasyLocRequest(CurrentPro->CurrentLayout->Window, &ES_SortHelp, NULL, NULL);
  3036.                 break;
  3037.             }
  3038.     }
  3039.     if (DB_Msg.Code >= RAW_F1 && DB_Msg.Code <= RAW_F10)
  3040.         DoARexxMenu(DB_Msg.Code - RAW_F1 + 1);
  3041.     return 0;
  3042. }
  3043.  
  3044.  
  3045. int DB_MouseButtons( void )
  3046. {
  3047.     /* routine for "IDCMP_MOUSEBUTTONS". */
  3048.     return 0;
  3049. }
  3050.  
  3051.  
  3052. /**********************************************************************/
  3053. /*        Eventhandlers that GadToolBox won't supply code for         */
  3054. /**********************************************************************/
  3055.  
  3056. int DB_MouseMove( void )
  3057. {
  3058.     /* Dragregeln rapporterar sitt läge i DB_Msg.Code */
  3059.     switch (CurrentPro->Mode) {
  3060.     case MODE_NORMAL:
  3061.         UpdateRecord(CurrentPro);
  3062.         JumpList(CurrentPro,DB_Msg.Code-CurrentPro->RecNum);
  3063.         UpdateWindow(CurrentPro);
  3064.         break;
  3065.     case MODE_FIND:
  3066.         break;
  3067.     }
  3068.     return 0;
  3069. }
  3070.  
  3071. void HandleAppWindow(void)
  3072. /* This only loads one of possibly many shift-dropped icon files */
  3073. {
  3074.     struct AppMessage *AppMsg;
  3075.     struct WBArg *wb_arg;
  3076.     char argdir[FMSIZE];
  3077.  
  3078.     while (AppMsg = (struct AppMessage *) GetMsg(AWPort)) {
  3079.         wb_arg = AppMsg->am_ArgList;
  3080.         if (AppMsg->am_NumArgs > 0) {        /* At least one file */
  3081.             if (wb_arg->wa_Lock) {
  3082.                 /* locks supported, change to the proper directory */
  3083.                 NameFromLock(wb_arg->wa_Lock,argdir,sizeof(argdir)); /* Path */
  3084.                 LoadPro(argdir,wb_arg->wa_Name);
  3085.             }    
  3086.         }
  3087.         ReplyMsg((struct Message *) AppMsg);
  3088.         if (!CurrentPro) ByeBye();
  3089.     }
  3090.     /* It's nice to have the window activated also */
  3091.     ActivateWindow(CurrentPro->CurrentLayout->Window);
  3092. }
  3093.  
  3094. /**********************************************************************/
  3095. /*                                main                                */
  3096. /**********************************************************************/
  3097.  
  3098. void main(int argc, char *argv[])
  3099. {
  3100.     ULONG appwinsig, myrexxportsig=0, signals;
  3101.  
  3102.     Init(argc, argv); /* Open libraries and windows.. */
  3103.  
  3104.     appwinsig = 1L << AWPort->mp_SigBit;
  3105.     if (MyRexxPort) myrexxportsig = 1L << MyRexxPort->mp_SigBit;
  3106.  
  3107.     /* Handle IDCMP events */
  3108.     for (;;) {
  3109.         /* GadToolBox won't wait */
  3110.         signals = Wait(WinSig | appwinsig | myrexxportsig);
  3111.  
  3112.         if (signals & WinSig) {
  3113.             /* This function in turn calls almost all functions.. */
  3114.             /* Note IDCMP_MOUSEMOVE case has to be added, se top of code */
  3115.             HandleDB_IDCMP(CurrentPro->CurrentLayout);
  3116.  
  3117.             switch ( DB_Msg.Class ) {
  3118.                 case    IDCMP_REFRESHWINDOW:
  3119.                     SpeedRenderOff(CurrentPro->CurrentLayout);
  3120.                     UpdateGadgets(CurrentPro);
  3121.                     if (!(SpeedRenderOn(CurrentPro->CurrentLayout))) ByeBye();
  3122.                     break;
  3123.             }
  3124.         }
  3125.         if (signals & appwinsig) {
  3126.             HandleAppWindow();
  3127.         }
  3128.         if (signals & myrexxportsig)
  3129.             HandleRexxMessage(MyRexxPort);
  3130.     }
  3131. }
  3132.