home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic 4 Unleashed / Visual_Basic_4_Unleashed_SAMS_Publishing_1995.iso / repease / rep_rep.c < prev    next >
C/C++ Source or Header  |  1995-08-09  |  74KB  |  1,877 lines

  1. /*==============================================================================
  2.    REP_REP.C
  3.    Report Ease: Report Executer Routines.
  4.  
  5.    ReportEase Plus
  6.    Sub Systems, Inc.
  7.    ReportEase Plus, Copyright (c) 1993, Sub Systems, Inc. All Rights Reserved.
  8.    159 Main Street, #8C, Stoneham,  MA 02180 
  9.    (617) 438-8901.
  10.  
  11.    Software License Agreement  (1993)              
  12.    ----------------------------------
  13.    This license agreement allows the purchaser the right to modify the 
  14.    source code to incorporate in their application.
  15.    The target application must not be distributed as a standalone report writer
  16.    or a mail merge product.
  17.    Sub Systems, Inc. reserves the right to prosecute anybody found to be 
  18.    making illegal copies of the executable software or compiling the source
  19.    code for the purpose of selling there after.
  20.  
  21. ===============================================================================*/
  22. #include "windows.h"
  23.  
  24. #if defined (_WIN32)
  25.    #if !defined(WIN32)
  26.      #define WIN32
  27.    #endif
  28. #endif
  29. #if !defined(WIN32) 
  30.   #include "print.h"
  31. #endif
  32.  
  33. #include "stdio.h"
  34. #include "stdlib.h"
  35. #include "ctype.h"
  36. #include "fcntl.h"
  37. #include "io.h"
  38. #include "sys\types.h"
  39. #include "sys\stat.h"
  40. #include "string.h"
  41. #include "dos.h"
  42. #include "math.h"
  43. #include "setjmp.h"
  44.  
  45. #include "rep.h"
  46.  
  47. #define  PREFIX extern
  48. #include "rep1.h"
  49.  
  50. extern BOOL ReportEaseActive;    // TRUE when report ease has been called 
  51.  
  52. /******************************************************************************
  53.     RepInit:
  54.     This routine is called by the user application to initialize a report
  55.     run.  The parameters are passed using the StrRep structure.
  56.     The routine returns a 0 value if the report is successfully initialized.
  57.     Otherwise it returns an error code (see ERR_ in the rew.h file).
  58.  
  59.     This routine uses the input structure parameter (RepArg) to pass the 
  60.     field information to the application routine.  It returns the pointer
  61.     to two arrays:
  62.  
  63.     1.  field: Huge pointer to the field table.  This table contains field information
  64.         about each field used by the form.  The elements of a field
  65.         is defined using the StrField structure.  Your application will need
  66.         to fill in the field data before calling the RepRec routine.
  67.         
  68.         The number of fields in this table is given by the TotalFields variable 
  69.         within the StrRep structure.
  70.           
  71.     2.  SortField: Huge pointer to the sort field table.  This table contains field information
  72.         about each sort field used by the form.  The elements of a field
  73.         is defined using the StrField structure.  Your application should
  74.         sort the records as specified by these fields.
  75.         
  76.         The number of fields in this table is given by the TotalSortFields variable 
  77.         within the StrRep structure.
  78.           
  79.  
  80. *******************************************************************************/     
  81. int WINAPI _export RepInit(struct StrRep far *ArgPtr) 
  82. {
  83.    LPSTR SaveCharPtr;
  84.    int  j,i,select,len,result,HorzWidth,PrtResX,PrtResY;
  85.    int   CompExp[NAME_WIDTH+2],LastSym,FieldIndex,fld,CurField;
  86.    int   SecItem,FirstY,LastY,WrapItem,LastItem,AdjX,AdjY;
  87.    struct StrItem TempItem;
  88.    POINT pt;
  89.  
  90.    // prepare to return an error code
  91.    #if defined (WIN32)
  92.       if (setjmp(FrAbort)==-1) return ErrorCode; // Fatal error return location 
  93.    #else
  94.       if (Catch((LPCATCHBUF)&FrAbort)==-1) return ErrorCode; // Fatal error return location 
  95.    #endif
  96.  
  97.    // check if ReportEase alread active
  98.    if (ReportEaseActive) {
  99.        MessageBox(hFrParentWnd,"Report Ease Already Active!",NULL,MB_OK);
  100.        return ERR_DUPLICATE;
  101.    }
  102.  
  103.    SessionType='R';                     // Report Run session 
  104.    ReportStage=IN_INIT;                 // in initialization 
  105.    RepArg=*ArgPtr;                      // store the argument pointer 
  106.    
  107.    //****************** check if the input file exists ****************
  108.    if (access(RepArg.file,6)==-1) {
  109.       AbortFr("Form File Not Found!",ERR_NO_FILE);
  110.    }
  111.  
  112.    //* Transfer the some input parameter variables to the global area *
  113.    strcpy(FrFileName,ArgPtr->file);    // current report file name 
  114.    FrShowHorBar=TRUE;                  // show horizontal scroll bar 
  115.    FrShowVerBar=TRUE;                  // show vertical scroll bar 
  116.  
  117.    //hFrInst=ArgPtr->hInst;           // uncomment for STATIC linking
  118.    //hFrPrevInst=ArgPtr->hPrevInst;   // uncomment for STATIC linking
  119.  
  120.    hFrWnd=NULL;                        // windows not opened yet 
  121.    hFrParentWnd=ArgPtr->hParentWnd;    // Handle to the parent window 
  122.  
  123.    //***************** Select the output device **********************
  124.    if (ArgPtr->device=='A') {          // ask user for the output device 
  125.       select=CallDialogBox("DeviceParam",DeviceParam,0);
  126.       if (select<0) return ERR_NO_DEVICE;
  127.       if (select==0) ArgPtr->device='S';
  128.       else           ArgPtr->device='P';
  129.    }
  130.  
  131.    if (ArgPtr->device=='S') UseScreen=TRUE;
  132.    else  {
  133.        UseScreen=FALSE;
  134.        FrShowHorBar=FALSE;             // show horizontal scroll bar 
  135.        FrShowVerBar=FALSE;             // show vertical scroll bar 
  136.    }
  137.  
  138.    //***************** Other initialization and file input 
  139.    if (0!=(result=InitFr(RepArg.style,RepArg.x,RepArg.y,RepArg.width,RepArg.height))) return result;
  140.    if (UseScreen) {
  141.       FormHdr.RulerType=RULER_OFF;     // turnoff the ruler
  142.       GetWinDimension();               // recalculate the window dimensions
  143.    }
  144.  
  145.    AllocRepMem();                      // allocate/reallocate arrays 
  146.  
  147.    //****************** accept the dialog fields ***************************
  148.    if (!AcceptDlgField()) {
  149.       ReportStatus=REP_ABORT;          // user cancellation 
  150.       RepExit();                       
  151.       return ERR_SUSPEND;
  152.    }
  153.  
  154.    //****************** initialize the temporary fields ***************************
  155.    for (i=0;i<MAX_TEMP_FIELDS;i++) {
  156.       InitField(&TempField[i]);
  157.       TempField[i].InUse=FALSE;
  158.    }
  159.  
  160.    //***************** Stuff the sort fields *******************************
  161.    for(i=0;i<TotalBreakFields;i++) {      // allocate space for the character sort fields 
  162.       FieldIndex=BreakField[i].SortField; // index into the field table 
  163.       SaveCharPtr=SortField[i].CharData;  // this field already allocated 
  164.       SortField[i]=field[FieldIndex];
  165.       SortField[i].CharData=SaveCharPtr;
  166.    }
  167.  
  168.    //***************** Assign the constant string and dialog fields **********
  169.    for (fld=0;fld<TotalFields;fld++) {
  170.       if (field[fld].type==TYPE_TEXT) field[fld].CharData[0]=0;// initialize 
  171.  
  172.       if (field[fld].source==SRC_CONST) {
  173.           if (field[fld].type==TYPE_TEXT) {
  174.               lstrcpy(field[fld].CharData,&field[fld].name[1]); // exclude the initial quote 
  175.               len=lstrlen(field[fld].CharData);
  176.               if (len>0) field[fld].CharData[len-1]=0;         // exclude the ending quotes 
  177.           }
  178.       }
  179.       else if (field[fld].source==SRC_DLG) {                   // assign fields 
  180.           if (field[fld].type==TYPE_TEXT) {
  181.              lstrcpy(field[fld].CharData,DlgField[field[fld].SysIdx].CharData);
  182.           }
  183.           else {
  184.              field[fld].NumData=DlgField[field[fld].SysIdx].NumData;
  185.              field[fld].DblData=DlgField[field[fld].SysIdx].DblData;
  186.           }
  187.       }
  188.    }
  189.  
  190.    //***************** compile the report selection criteria ****************
  191.    LastSym=CompileExp(FormHdr.SelExp,CompExp);// compile the expression 
  192.  
  193.    if (LastSym!=END_OF_EXP) {                 // error encountered 
  194.       AbortFr("Invalid Report Selection Expression!",ERR_BAD_EXP);
  195.    }
  196.    i=0;
  197.    while(CompExp[i]!=END_OF_EXP) {            // transfer to the structure 
  198.       FormHdr.SelExp[i]=CompExp[i];
  199.       i++;
  200.    }
  201.    FormHdr.SelExp[i]=CompExp[i];
  202.  
  203.    //***************** compile the field expressions *********************
  204.    for (j=0;j<TotalFields;j++) {
  205.       if (field[j].source==SRC_CALC) {
  206.          LastSym=CompileExp(field[j].CalcExp,CompExp);// compile the expression 
  207.  
  208.          if (LastSym!=END_OF_EXP) {       // error encountered 
  209.             AbortFr("Invalid Field Calculation Expression!",ERR_BAD_EXP);
  210.          }
  211.          i=0;
  212.          while(CompExp[i]!=END_OF_EXP) {  // transfer to the structure 
  213.             field[j].CalcExp[i]=CompExp[i];
  214.             i++;
  215.          }
  216.          field[j].CalcExp[i]=CompExp[i];
  217.       }
  218.    }
  219.  
  220.    //***************** compile the section selection expressions *********************
  221.    for (j=0;j<MAX_SECTIONS;j++) {
  222.       if (section[j].InUse) {
  223.          LastSym=CompileExp(section[j].SelExp,CompExp);// compile the expression 
  224.  
  225.          if (LastSym!=END_OF_EXP) {       // error encountered 
  226.             AbortFr("Invalid Section Selection Expression!",ERR_BAD_EXP);
  227.          }
  228.          i=0;
  229.          while(CompExp[i]!=END_OF_EXP) {  // transfer to the structure 
  230.             section[j].SelExp[i]=CompExp[i];
  231.             i++;
  232.          }
  233.          section[j].SelExp[i]=CompExp[i];
  234.       }
  235.    }
  236.  
  237.    //***************** Initialize the user fields ****************************
  238.    for (fld=0;fld<TotalFields;fld++) {
  239.       SaveCharPtr=UserField[fld].CharData; // this field already allocated 
  240.       UserField[fld]=field[fld];
  241.       UserField[fld].CharData=SaveCharPtr;
  242.       if (field[fld].type==TYPE_TEXT) lstrcpy(UserField[fld].CharData,field[fld].CharData);
  243.    }
  244.  
  245.  
  246.    //********************* initialize the section and section items ***********
  247.    for (i=0;i<MAX_SECTIONS;i++) {             // initialize the section pointers 
  248.       if (!section[i].InUse) continue;
  249.  
  250.       SecItem=section[i].ScrItem;             // section position in the item table
  251.       item[SecItem].y=item[SecItem].y+FormHdr.SecBannerHeight;
  252.       item[SecItem].height=item[SecItem].height-FormHdr.SecBannerHeight;
  253.       section[i].FirstItem=SecItem;
  254.       section[i].ItemCount=1;                 // include the section item
  255.       
  256.       // calculate first and last Y position of items within the section
  257.       FirstY=LastY=-1;                        // initialize
  258.       for (j=section[i].FirstItem+1;j<TotalItems;j++) {
  259.          if (item[j].section!=i) break;       // next section begins
  260.          section[i].ItemCount++;
  261.          
  262.          if (item[j].type==GROUP) continue;   // ignore group items
  263.          if (FirstY==-1) FirstY=item[j].y;    // find the first item position
  264.          else if (item[j].y<FirstY) FirstY=item[j].y;
  265.  
  266.          if (item[j].y+item[j].height>LastY) LastY=item[j].y+item[j].height;
  267.       
  268.          // initialize the field variables
  269.          if (item[j].type==FIELD) {
  270.             CurField=item[j].field;
  271.             field[CurField].section=UserField[CurField].section=i;
  272.             if (i<SEC_FTR_LVL9) field[CurField].SumType=UserField[CurField].SumType=SUM_NONE;
  273.          }
  274.       }
  275.       
  276.       // adjust the item Y positions within the section
  277.       if (!(section[i].flags&SFLAG_TRIM_BEFORE)) FirstY=item[SecItem].y;
  278.       if (!(section[i].flags&SFLAG_TRIM_AFTER))  LastY=item[SecItem].y+item[SecItem].height;
  279.       
  280.       if (FirstY==-1 || LastY==-1) {
  281.          section[i].ItemCount=0;
  282.          section[i].height=0;
  283.       }
  284.       else {
  285.          section[i].height=LastY-FirstY;
  286.          for (j=section[i].FirstItem;j<TotalItems;j++) {
  287.             if (item[j].section!=i) break;       // next section begins
  288.             item[j].y-=FirstY;                   // position relative to the section beginning
  289.          }
  290.  
  291.          // set the section item to begin at relative zero
  292.          j=section[i].FirstItem;
  293.          item[j].y=0;                            // set the section beginning to zero
  294.          item[j].height=LastY-FirstY+1;
  295.       }
  296.       
  297.       // move the wrap field at the last position
  298.       if (i==SEC_DETAIL1 && section[i].ItemCount>0) {
  299.          WrapItem=-1;
  300.          LastItem=section[i].FirstItem+section[i].ItemCount-1;
  301.          for (j=section[i].FirstItem;j<=LastItem;j++) {
  302.             if (item[j].type==GROUP || item[j].type==SECTION) continue;   // ignore group items
  303.             
  304.             if (WrapItem!=-1) {     // check any item after the wrap item
  305.                if (item[j].y>=item[WrapItem].y+item[WrapItem].height-DESC_MARGIN) WrapItem=-1;  // discard this wrap item
  306.             }
  307.             
  308.             if (item[j].type!=FIELD) continue;
  309.             CurField=item[j].field;
  310.             if (field[CurField].type==TYPE_TEXT 
  311.              && field[CurField].flags&(FLAG_WRAP|FLAG_WORD_WRAP)) WrapItem=j;
  312.          }
  313.          if (WrapItem!=-1 && WrapItem!=LastItem) { // reloate the wrap item
  314.             HugeMove(&(item[WrapItem]),&TempItem,sizeof(struct StrItem));
  315.             HugeMove(&(item[LastItem]),&(item[WrapItem]),sizeof(struct StrItem));
  316.             HugeMove(&TempItem,&(item[LastItem]),sizeof(struct StrItem));
  317.             WrapItem=LastItem;
  318.          }
  319.          LastWrapItem=WrapItem;
  320.       }
  321.  
  322.    }
  323.    
  324.  
  325.    //***************** other initialization **********************************
  326.    GetSystemDateTime();    // get the system date and time
  327.  
  328.    // initialize month array 
  329.    MonthName[0]="Jan";MonthName[1]="Feb";MonthName[2]="Mar";
  330.    MonthName[3]="Apr";MonthName[4]="May";MonthName[5]="Jun";
  331.    MonthName[6]="Jul";MonthName[7]="Aug";MonthName[8]="Sep";
  332.    MonthName[9]="Oct";MonthName[10]="Nov";MonthName[11]="Dec";
  333.    
  334.    RecCount=0;                            // First rec to be read by the application 
  335.    PageCount=1;                           // first page 
  336.    ScrPage=0;                             // screen page being displayed
  337.    CurX=0;                                // current displacement toward x direction
  338.    CurHeight=0;                           // current Y displacement
  339.    CurCol=0;                              // current column for multiple column sections
  340.    TrialMode=FALSE;                       // trial mode prints trial records 
  341.    hMetaFile=NULL;                        // current screen page in memory meta file
  342.    PageAdvanced=FALSE;                    // set after page is advanced 
  343.    AdvancingPage=FALSE;                   // set during page advance 
  344.    ReportStatus=REP_RESUMED;
  345.  
  346.    //*************** initialize the page variables *******************
  347.    LeftMargin=(int)((FormHdr.LeftMargin)*UNITS_PER_INCH);  // margins logical in units 
  348.    RightMargin=(int)((FormHdr.RightMargin)*UNITS_PER_INCH); 
  349.    TopMargin=(int)((FormHdr.TopMargin)*UNITS_PER_INCH);
  350.    BottomMargin=(int)((FormHdr.BottomMargin)*UNITS_PER_INCH);
  351.  
  352.    PrintWidth=(int)(PrintWidthInches*UNITS_PER_INCH);   // width of the printed area   
  353.  
  354.    // adjust left and top margin for the hidden areas
  355.    Escape(hPrtDC,GETPRINTINGOFFSET,0,NULL,&pt);  // actual offset where printing begins
  356.    PrtResX=GetDeviceCaps(hPrtDC,LOGPIXELSX);     // number of pixels per inch of X direction 
  357.    PrtResY=GetDeviceCaps(hPrtDC,LOGPIXELSY);     // number of pixels per inch of Y direction 
  358.    AdjX=MulDiv(pt.x,UNITS_PER_INCH,PrtResX);     // printing area begin position
  359.    AdjY=MulDiv(pt.y,UNITS_PER_INCH,PrtResY);
  360.  
  361.    LeftMargin-=AdjX;                             // margin relative to printing area
  362.    TopMargin-=AdjY;
  363.    for (i=0;i<TotalItems;i++) item[i].x-=AdjX;   // x relative to printing area
  364.  
  365.    PageHeight=(int)(PrintHeightInches*UNITS_PER_INCH)+TopMargin;  // height of the printed page   
  366.    if (section[SEC_FTR_PAGE].InUse) PrintHeight=PageHeight-section[SEC_FTR_PAGE].height;
  367.    else                             PrintHeight=PageHeight;
  368.  
  369.    if (PrintHeight<=0) {
  370.       MessageBox(hFrWnd,"Page Too Small!",NULL,MB_OK);
  371.       return ERR_PRINTER;
  372.    }
  373.    
  374.  
  375.    //******************** set additional window characteristics ****************
  376.    if (UseScreen) {
  377.       //******************** set the left margin on the screen ****************
  378.       FrWinOrgX=FrWinOrgY=0;
  379.       FrSetViewWindow();        // set the logical window origin 
  380.  
  381.       //******************* set scroll bars **********************************
  382.       HorzWidth=PrintWidth-FrWinWidth;
  383.       if (HorzWidth>0) {
  384.          HorScrollPos=HOR_SCROLL_MIN+(int)((long)FrWinOrgX*(HOR_SCROLL_MAX-HOR_SCROLL_MIN)/HorzWidth);
  385.          if (HorScrollPos>HOR_SCROLL_MAX) HorScrollPos=HOR_SCROLL_MAX;
  386.          SetScrollPos(hFrWnd,SB_HORZ,HorScrollPos,TRUE);
  387.       }
  388.       SetScrollPos(hFrWnd,SB_VERT,VER_SCROLL_MIN,TRUE);
  389.       
  390.       //****************** Create a new meta file **********************
  391.       if (NULL==(hMetaDC=CreateMetaFile(NULL))) AbortFr("Error creating metafile",ERR_NO_FILE);
  392.       ShowScrRepStatus();                             // show screen reporting status
  393.       RepInitMenu(hFrMenu);                           // initialize the menu bar
  394.    }
  395.    
  396.    //***************** Initialize the system fields ****************************
  397.    for (fld=0;fld<TotalFields;fld++) {
  398.       if (field[fld].source==SRC_SYS) {
  399.          StuffSysField(&field[fld]);
  400.          StuffSysField(&UserField[fld]);
  401.       }
  402.    }
  403.  
  404.    //***************** stuff the return fields*******************************
  405.    RepArg.field=UserField;               // field to be filled by the user application 
  406.    RepArg.TotalFields=TotalFields;
  407.    RepArg.SortField=SortField;
  408.    RepArg.TotalSortFields=TotalBreakFields;
  409.    lstrcpy(RepArg.DataSetName,FormHdr.DataSetName);
  410.  
  411.    (*ArgPtr)=RepArg;                      // return the updated structure 
  412.  
  413.    return 0;
  414. }
  415.  
  416. /******************************************************************************
  417.     RepRec:
  418.     This routine is called by the user application to print each record.
  419.     The field data for the record must be passed using the 'field' array
  420.     as returned by the RepInit routine.  
  421.     
  422.     Your application should fill in the data for only the fields of SOURCE 
  423.     type equal to SCR_APPL.  The data in other fields must not be modified in 
  424.     any way.  
  425.     
  426.     Only the following elements in the field structure can be used to pass data:
  427.  
  428.        CharData  (char far *) to pass the character string data.
  429.                  The character data being copied to the CharData pointer
  430.                  should not be larger than the 'width' as specified in 
  431.                  the field structure.  This variable (width) holds the character
  432.                  field width as specified by your application during the
  433.                  form edit process.
  434.  
  435.        NumData   (long) to pass numeric, logical and date data.
  436.                  (date should be passed either as YYMMDD or YYYYMMDD format).
  437.  
  438.        DblData   (double) to pass float numeric data.
  439.  
  440.     No other element of field structure should be modified.
  441. *******************************************************************************/     
  442. int WINAPI _export RepRec() 
  443. {
  444.     int sec,BreakSort;
  445.     struct StrField TempField,huge *SaveField=NULL;
  446.     int LastSym;
  447.     int fld;
  448.  
  449.    // prepare to return an error code
  450.    #if defined (WIN32)
  451.       if (setjmp(FrAbort)==-1) {            // Fatal error return location 
  452.    #else
  453.       if (Catch((LPCATCHBUF)&FrAbort)==-1) { // Fatal error return location 
  454.    #endif
  455.         if (SaveField!=NULL) {
  456.            field=SaveField;
  457.            SaveField=NULL;
  458.         }
  459.         return ErrorCode;
  460.     }
  461.  
  462.     ReportStage=IN_RECORDS;                    // processing records 
  463.  
  464.     //******************** Apply record selection criteria ******************
  465.     EvaluateSystemFields();                    // update system fields 
  466.  
  467.     if (FormHdr.SelExp[0]!=END_OF_EXP) {
  468.         SaveField=field;                       // activate user fields 
  469.         field=UserField;
  470.         
  471.         LastSym=RunExp(FormHdr.SelExp,&TempField,TRUE); // run the expression and return the output in the field 
  472.         
  473.         field=SaveField;                       // activate the original field 
  474.         SaveField=NULL;
  475.  
  476.         if (LastSym!=END_OF_EXP || TempField.type!=TYPE_LOGICAL)  { // error encountered 
  477.            MessageBox(hFrWnd,"Error In Record Filter",NULL,MB_OK);
  478.            return ERR_BAD_EXP;
  479.         }
  480.         if (!(TempField.NumData)) return 0;// record not selected   
  481.     }
  482.  
  483.     //************ calculate the break fields *********
  484.     SaveField=field;                       // activate user fields 
  485.     field=UserField;
  486.     CalculateBreakFields();
  487.     field=SaveField;                       // activate the original field 
  488.     SaveField=NULL;
  489.  
  490.     
  491.     //******************** Initialize for the first record *******************
  492.     if (RecCount==0) InitFirstRec();
  493.  
  494.     //************************ Check for sort breaks ***********************
  495.     BreakSort=PrintSortFooters();
  496.  
  497.     //**************** copy the user field to the global field ***************
  498.     for (fld=0;fld<TotalFields;fld++) {
  499.         if (field[fld].type==TYPE_TEXT)     lstrcpy(field[fld].CharData,UserField[fld].CharData);
  500.         else if (field[fld].type==TYPE_DBL) field[fld].DblData=UserField[fld].DblData;
  501.         else                                field[fld].NumData=UserField[fld].NumData;
  502.     }
  503.  
  504.     //******************* Evaluate the calculation fields ******************
  505.     CalculateFields(0,MAX_SECTIONS-1);     // calculate all fields for all section 
  506.     
  507.     //************************* Print sort headers **************************
  508.     PrintSortHeaders(BreakSort);
  509.     
  510.     //************************* Print the detail sections **********************
  511.     for (sec=SEC_DETAIL1;sec<=SEC_DETAIL9;sec++) PrintSection(sec);
  512.  
  513.     //************************* Do totals ************************************
  514.     for (fld=0;fld<TotalFields;fld++) {
  515.         field[fld].count++;
  516.  
  517.         if (field[fld].SumType==SUM_MAX) {
  518.            if (field[fld].DblData>field[fld].HoldDbl) field[fld].HoldDbl=field[fld].DblData;
  519.            if (field[fld].NumData>field[fld].HoldNum) field[fld].HoldNum=field[fld].NumData;
  520.         }
  521.         else if (field[fld].SumType==SUM_MIN) {
  522.            if (field[fld].DblData<field[fld].HoldDbl) field[fld].HoldDbl=field[fld].DblData;
  523.            if (field[fld].NumData<field[fld].HoldNum) field[fld].HoldNum=field[fld].NumData;
  524.         }
  525.         else {
  526.            field[fld].HoldDbl+=field[fld].DblData;
  527.            field[fld].HoldNum+=field[fld].NumData;
  528.         }
  529.  
  530.     }
  531.     
  532.     if (UseScreen) {
  533.        // show progress
  534.        if ( (RecCount<50 && RecCount%5==0) || RecCount%10==0) ShowScrRepStatus();               // show print progress
  535.        ProcessUserCommands();            // process any pending messages
  536.     }
  537.  
  538.     RecCount++;                          // increment number of records printed 
  539.  
  540.     return 0;
  541. }
  542.  
  543. /*****************************************************************************
  544.     RepExit:
  545. *****************************************************************************/
  546. int WINAPI _export RepExit()
  547. {
  548.     int CurSort,CurSec,FooterSec;
  549.  
  550.    // prepare to return an error code
  551.    #if defined (WIN32)
  552.       if (setjmp(FrAbort)==-1) return ErrorCode; // Fatal error return location 
  553.    #else
  554.       if (Catch((LPCATCHBUF)&FrAbort)==-1) return ErrorCode; // Fatal error return location 
  555.    #endif
  556.  
  557.     if (ReportStatus!=REP_ABORT && RecCount>0) {
  558.         ReportStage=IN_TOTALS;                  // printing totals 
  559.  
  560.         //******************** calculate the footer fields ********************
  561.         CalculateFields(SEC_FTR_LVL9,SEC_FTR_REP);
  562.         
  563.         //******************** print sort footers ******************************
  564.         for (CurSort=(TotalBreakFields-1);CurSort>=0;CurSort--) {
  565.             CurSec=BreakField[CurSort].section;
  566.             FooterSec=SEC_FTR_LVL1-(CurSec-SEC_HDR_LVL1);
  567.             PrintSection(FooterSec);                // print section footer 
  568.         }
  569.  
  570.         PrintSection(SEC_FTR_REP);                  // print the report footers 
  571.  
  572.         CurHeight=PrintHeight;                      // print last page footer 
  573.         PageAdvanced=AdvancingPage=TRUE;
  574.         PrintSection(SEC_FTR_PAGE);
  575.     }
  576.  
  577.     if (ReportStatus!=REP_ABORT) {
  578.         if (UseScreen) {
  579.            ReportStage=IN_EXIT;
  580.            TransferMetaFile();                      // transfer the last metafile page to disk
  581.            RepInitMenu(hFrMenu);                    // redisplay the menu 
  582.            PaintRepScr();                           // show screen 
  583.         }
  584.         else {
  585.            ReportStage=IN_EXIT;
  586.            Escape(hFrDC,NEWFRAME,0,0L,0L);
  587.         }
  588.     }
  589.  
  590.     if (UseScreen && ReportStatus!=REP_ABORT) 
  591.           return 0;                       // do cleanup later
  592.     else  return RepCleanup();            // do cleanup now
  593. }
  594.  
  595. /*****************************************************************************
  596.     RepCleanup:
  597.     Release the report resources
  598. *****************************************************************************/
  599. int RepCleanup()
  600. {
  601.     int i;
  602.     char string[85];
  603.     int fld;
  604.     HMETAFILE hMeta;
  605.  
  606.     //******* release printer window resources *********
  607.     if (!UseScreen) {
  608.         if (RecCount>0) {
  609.             PrintProc(hFrDC,0);                     // show the last status
  610.             Escape(hFrDC,ENDDOC,0,0L,0L);           // end of print job 
  611.             if (hFrWnd) EnableWindow(hFrWnd,TRUE);  // activate the parent window 
  612.             DestroyWindow(hAbortWnd);               // destroy the abort window 
  613.             FreeProcInstance(lpProc);               // free the process instances 
  614.             FreeProcInstance(lpAbortDlg);
  615.         }
  616.         if (ReportStatus!=REP_ABORT) {
  617.            wsprintf(string,"%ld Record(s) Printed",RecCount);
  618.            MessageBox(hFrWnd,string,"Report Over",MB_ICONSTOP);
  619.         }
  620.     }
  621.  
  622.     //*********************** Do cleanup ***********************************
  623.     // free up space taken by the character fields 
  624.     for(fld=0;fld<TotalFields;fld++) {      // allocate space for the character fields 
  625.        if (field[fld].type==TYPE_TEXT && field[fld].CharData!=NULL)         OurFree(field[fld].CharData);
  626.        if (UserField[fld].type==TYPE_TEXT && UserField[fld].CharData!=NULL) OurFree(UserField[fld].CharData);
  627.     }
  628.  
  629.     for(i=0;i<TotalBreakFields;i++) { // allocate space for the character fields 
  630.        if (SortField[i].type==TYPE_TEXT) OurFree(SortField[i].CharData);
  631.     }
  632.  
  633.     //*********** free up addtional global memory blocks ****
  634.     GlobalUnlock(hSortField);
  635.     GlobalFree(hSortField);
  636.  
  637.     GlobalUnlock(hUserField);
  638.     GlobalFree(hUserField);
  639.  
  640.     //*********** free up screen arrays *******************************
  641.     if (UseScreen) {
  642.         GlobalUnlock(hPageLoc);
  643.         GlobalFree(hPageLoc);
  644.  
  645.         OurFree(FileBuf);      // free the file buffer
  646.  
  647.         // close the last metafile device context and delete the memory metafile
  648.         if (hMetaDC && NULL!=(hMeta=CloseMetaFile(hMetaDC))) DeleteMetaFile(hMeta);
  649.  
  650.         unlink(MetaFile);      // delete meta files
  651.         unlink(TempMetaFile);  // delete temporary meta file
  652.         unlink(ScrMetaFile);   // delete screen meta file
  653.         unlink(PrtMetaFile);   // delete selective print file
  654.     }
  655.  
  656.     FrModified=FALSE;
  657.     CloseFr();
  658.  
  659.     return 0;
  660. }
  661.  
  662. /******************************************************************************
  663.     PrintSortFooters:
  664.     Check if sort break has taken places. If so, write the old sort footers.
  665. *******************************************************************************/     
  666. PrintSortFooters()
  667. {
  668.     int CurSort,CurSec,BreakSort,FooterSec;
  669.     int CurField;
  670.  
  671.  
  672.     for (CurSort=0;CurSort<TotalBreakFields;CurSort++) {
  673.         CurField=BreakField[CurSort].CompField;
  674.         
  675.         if (field[CurField].type==TYPE_TEXT && 
  676.               lstrcmp(UserField[CurField].CharData,field[CurField].CharData)!=0) break;
  677.         else if (field[CurField].type==TYPE_DBL && 
  678.               UserField[CurField].DblData!=field[CurField].DblData) break;
  679.         else if (UserField[CurField].NumData!=field[CurField].NumData) break;
  680.     }
  681.     
  682.     if (CurSort==TotalBreakFields) return CurSort;  // no sort breaks 
  683.  
  684.  
  685.     BreakSort=CurSort;
  686.  
  687.     //******************** calculate the footer fields ********************
  688.     CalculateFields(SEC_FTR_LVL9,SEC_FTR_REP);
  689.  
  690.     //***************** write sort section footers ************************
  691.     for (CurSort=(TotalBreakFields-1);CurSort>=BreakSort;CurSort--) {
  692.         CurSec=BreakField[CurSort].section;
  693.         FooterSec=SEC_FTR_LVL1-(CurSec-SEC_HDR_LVL1);
  694.         PrintSection(FooterSec);                 // print section footer 
  695.     }
  696.  
  697.     return BreakSort;
  698. }
  699.  
  700. /******************************************************************************
  701.     PrintSortHeaders:
  702.     This routine prints sort headers for all levels below the specified level.
  703. *******************************************************************************/     
  704. PrintSortHeaders(int BreakSort)
  705. {
  706.     int CurSort,CurSec,FooterSec;
  707.     int fld;
  708.  
  709.     if (BreakSort>=TotalBreakFields) return TRUE;   // no sort breaks 
  710.  
  711.     //***************** write sort section headers ***************************
  712.     for (CurSort=BreakSort;CurSort<TotalBreakFields;CurSort++) {
  713.         CurSec=BreakField[CurSort].section;
  714.         PrintSection(CurSec);              // print section headers 
  715.         
  716.         FooterSec=SEC_FTR_LVL1-(CurSec-SEC_HDR_LVL1);
  717.         
  718.         for(fld=0;fld<TotalFields;fld++) { // clear accumulaters 
  719.            if (field[fld].InUse && field[fld].section==FooterSec) {
  720.                if (!(FLAG_RETAIN&field[fld].flags)) {
  721.                   field[fld].HoldNum=0;
  722.                   field[fld].HoldDbl=0;
  723.                   field[fld].count=0;
  724.                   if (field[fld].SumType==SUM_MIN || field[fld].SumType==SUM_MAX) {
  725.                      field[fld].HoldNum=field[fld].NumData;
  726.                      field[fld].HoldDbl=field[fld].DblData;
  727.                   }
  728.                }
  729.            }
  730.         }
  731.     }    
  732.  
  733.     return TRUE;
  734. }
  735.  
  736. /*****************************************************************************
  737.     EvaluateSystemFields:
  738.     Evaludate system fields
  739. *****************************************************************************/
  740. EvaluateSystemFields()
  741. {
  742.     int fld;
  743.  
  744.     // evaluate system fields ********
  745.     for (fld=0;fld<TotalFields;fld++) {
  746.        if (field[fld].source==SRC_SYS) {
  747.           StuffSysField(&UserField[fld]);
  748.        }
  749.     }
  750.     return TRUE;
  751. }
  752.  
  753. /*****************************************************************************
  754.     CalculateFields:
  755.     Do calculation and assin systems fields 
  756. *****************************************************************************/
  757. CalculateFields(int FirstSec,int LastSec)
  758. {
  759.     int fld,LastSym;
  760.     struct StrField TempField;
  761.  
  762.  
  763.     // evaluate calculated fields ****
  764.     for (fld=0;fld<TotalFields;fld++) {
  765.        if (field[fld].source==SRC_CALC && field[fld].section>=FirstSec && field[fld].section<=LastSec) {
  766.           
  767.           LastSym=RunExp(field[fld].CalcExp,&TempField,TRUE); // run the expression and return the output in the field 
  768.           if (LastSym!=END_OF_EXP)  {      // error encountered 
  769.              wsprintf(msg,"Error In Calculation Field: %s",(LPSTR)(field[fld].name));
  770.              AbortFr(msg,ERR_BAD_EXP);
  771.           }
  772.  
  773.           if (field[fld].type==TYPE_TEXT && field[fld].CharData!=NULL) {
  774.              OurFree(field[fld].CharData);
  775.              field[fld].CharData=NULL;
  776.           }
  777.  
  778.           if      (TempField.type==TYPE_TEXT)  field[fld].CharData=TempField.CharData;
  779.           else if (TempField.type==TYPE_DBL)   field[fld].DblData=TempField.DblData;
  780.           else                                 field[fld].NumData=TempField.NumData;
  781.        }
  782.     }
  783.     
  784.     return TRUE;
  785.  
  786. /*****************************************************************************
  787.     CalculateSecExp:
  788.     Calculate the section selection expression.
  789. *****************************************************************************/
  790. CalculateSecExp(int CurSec)
  791. {
  792.     int LastSym;
  793.     struct StrField TempField;
  794.  
  795.     if (section[CurSec].InUse) {
  796.        if (section[CurSec].SelExp[0]==END_OF_EXP) section[CurSec].selected=TRUE;
  797.        else {
  798.            LastSym=RunExp(section[CurSec].SelExp,&TempField,TRUE); // run the expression and return the output in the field 
  799.            if (LastSym!=END_OF_EXP)  {      // error encountered 
  800.               AbortFr("Error In Section Filter",ERR_BAD_EXP);
  801.            }
  802.            section[CurSec].selected=(int)TempField.NumData;
  803.        }
  804.     }
  805.     else   section[CurSec].selected=FALSE;
  806.  
  807.     return section[CurSec].selected;
  808. }
  809.  
  810. /*****************************************************************************
  811.     CalculateBreakFields:
  812.     Calculation fields used for break comparison
  813. *****************************************************************************/
  814. CalculateBreakFields()
  815. {
  816.     int fld,LastSym;
  817.     struct StrField TempField;
  818.     int i;
  819.  
  820.     for (i=0;i<TotalBreakFields;i++) {
  821.        fld=BreakField[i].CompField;
  822.        if (field[fld].source==SRC_CALC) {
  823.           LastSym=RunExp(field[fld].CalcExp,&TempField,TRUE); // run the expression and return the output in the field 
  824.           if (LastSym!=END_OF_EXP)  {      // error encountered 
  825.              wsprintf(msg,"Error In Break Calculation Field: %s",(LPSTR)(field[fld].name));
  826.              AbortFr(msg,ERR_BAD_EXP);
  827.           }
  828.  
  829.           if (field[fld].type==TYPE_TEXT && field[fld].CharData!=NULL) {
  830.              OurFree(field[fld].CharData);
  831.              field[fld].CharData=NULL;
  832.           }
  833.  
  834.           if      (TempField.type==TYPE_TEXT)  field[fld].CharData=TempField.CharData;
  835.           else if (TempField.type==TYPE_DBL)   field[fld].DblData=TempField.DblData;
  836.           else                                 field[fld].NumData=TempField.NumData;
  837.        }
  838.     }
  839.     
  840.     return TRUE;
  841.  
  842. /*****************************************************************************
  843.     InitFirstRec:
  844.     Do initialization for the first record.
  845. *****************************************************************************/
  846. InitFirstRec()
  847. {
  848.     int i,CurSec;
  849.     int fld;
  850.  
  851.     //***************** copy from user fields ***************************
  852.     for (fld=0;fld<TotalFields;fld++) {
  853.           if (field[fld].type==TYPE_TEXT)     lstrcpy(field[fld].CharData,UserField[fld].CharData);
  854.           else if (field[fld].type==TYPE_DBL) field[fld].DblData=UserField[fld].DblData;
  855.           else                                field[fld].NumData=UserField[fld].NumData;
  856.     }
  857.  
  858.     CalculateFields(0,MAX_SECTIONS-1);   // do calculation for the first record 
  859.     
  860.     //***************** initialize the output device ***************************
  861.     ReportStatus=REP_RESUMED;            // report in progress 
  862.     if (UseScreen) {                     // show the blank screen 
  863.        RepInitMenu(hFrMenu);             // initialize the menu items 
  864.        CurHeight=TopMargin;
  865.     }
  866.     else {
  867.        lpAbortDlg = MakeProcInstance((FARPROC)PrintAbortParam, hFrInst);
  868.        hAbortWnd=CreateDialog(hFrInst,"PrintAbortParam",hFrWnd,(DLGPROC)lpAbortDlg);
  869.        ShowWindow(hAbortWnd,SW_NORMAL);
  870.  
  871.        lpProc = MakeProcInstance((FARPROC)PrintProc, hFrInst);
  872.        SetAbortProc(hFrDC,(ABORTPROC)lpProc);
  873.  
  874.        if (Escape(hFrDC,STARTDOC,strlen(FormHdr.name),FormHdr.name,NULL)<0) {
  875.            AbortFr("Unable to Start the Print Job",ERR_PRINTER);
  876.        }
  877.        
  878.        UpdateWindow(hAbortWnd);
  879.        if (hFrWnd) EnableWindow(hFrWnd,FALSE);  // disable the main window 
  880.  
  881.        FrWinWidth=PrintWidth+LeftMargin+RightMargin; // to enable use of display routines for printing 
  882.  
  883.     }
  884.     
  885.     CurHeight=TopMargin;                        // start printing from the top page
  886.  
  887.     if (RFLAG_TRIAL&FormHdr.flags && !UseScreen) PrintTrial();  // print trial run 
  888.  
  889.     PageAdvanced=TRUE;                   // suppress page advance 
  890.     PrintSection(SEC_HDR_PAGE);          // print page header 
  891.  
  892.     PageAdvanced=TRUE;                   // suppress page advance 
  893.     PrintSection(SEC_HDR_REP);           // print the report header 
  894.  
  895.     for (i=0;i<TotalBreakFields;i++) {   // print group headers 
  896.        CurSec=BreakField[i].section;
  897.        PageAdvanced=TRUE;                // suppress page advance 
  898.        PrintSection(CurSec);
  899.     }
  900.  
  901.     PageAdvanced=TRUE;
  902.  
  903.     return TRUE;
  904. }
  905.  
  906. /*****************************************************************************
  907.     PrintSection:
  908.     This routine prints lines for a specified section.  The routine will
  909.     apply the current record data to the fields found in the section.
  910. *****************************************************************************/
  911. PrintSection(int CurSec)
  912. {
  913.     int   FromItem,ToItem,CurItem;
  914.  
  915.     if (!(section[CurSec].InUse)) return FALSE; // this section not used 
  916.     if (!(CalculateSecExp(CurSec))) return FALSE; // this section not selected 
  917.  
  918.     FromItem=section[CurSec].FirstItem;
  919.     ToItem=FromItem+section[CurSec].ItemCount-1;
  920.  
  921.     if (ToItem<FromItem) return FALSE;
  922.  
  923.     // force to first column when not in the first detail section
  924.     if (CurSec!=SEC_DETAIL1 && CurCol!=0) {
  925.        CurCol=0;
  926.        CurHeight=LastY;                         // update the current y location
  927.     }
  928.  
  929.     // Check for page advance
  930.     if (CurCol==0) {
  931.        if      (SFLAG_PAGE_BEF&(section[CurSec].flags))       AdvancePage(CurSec);
  932.        else if (CurHeight+section[CurSec].height>PrintHeight) AdvancePage(CurSec);
  933.        LastY=CurHeight;                        // track last Y position used for printing
  934.     }
  935.     CurX=CurCol*(item[section[CurSec].ScrItem].width);             // x displacement
  936.     
  937.     // clear the height adjusment field
  938.     for (CurItem=FromItem;CurItem<=ToItem;CurItem++) item[CurItem].HeightAdj=0;
  939.  
  940.     // Print each item
  941.     for (CurItem=FromItem;CurItem<=ToItem;CurItem++) {     // process each line 
  942.         if (item[CurItem].type==GROUP) continue;
  943.         if (item[CurItem].section!=CurSec) continue;
  944.  
  945.         if (UseScreen) PrintItem(hMetaDC,CurItem);
  946.         else           PrintItem(hFrDC,CurItem);
  947.  
  948.         PageAdvanced=FALSE;                                 // new page is dirtied now
  949.     }
  950.  
  951.     // Update printed page height and horizontal column position
  952.     if (CurSec==SEC_DETAIL1) {
  953.        CurCol++;
  954.        if (CurCol>=section[CurSec].columns) {
  955.           if (SFLAG_TRIM_AFTER&(section[CurSec].flags)) CurHeight=LastY;
  956.           else                                          CurHeight+=section[CurSec].height;
  957.           if (CurHeight<LastY) CurHeight=LastY;
  958.  
  959.           CurCol=0;
  960.           if (section[CurSec].columns==1 && SFLAG_PAGE_AFT&(section[CurSec].flags)) CurHeight=PrintHeight+1; // force page break for the next section
  961.        }
  962.     }
  963.     else {
  964.        if (SFLAG_TRIM_AFTER&(section[CurSec].flags)) CurHeight=LastY;
  965.        else                                          CurHeight+=section[CurSec].height;
  966.        if (CurHeight<LastY) CurHeight=LastY;
  967.        
  968.        if (SFLAG_PAGE_AFT&(section[CurSec].flags)) AdvancePage(MAX_SECTIONS);
  969.        CurCol=0;                                            // other sections are single column
  970.     }
  971.  
  972.     return TRUE;
  973. }
  974.  
  975. /*****************************************************************************
  976.     PrintItem:
  977.     Print the specified item at the specified device context.  The item is
  978.     printed relative to the current Y position
  979. *****************************************************************************/
  980. PrintItem(HDC hDC,int CurItem)
  981. {
  982.  
  983.     RECT rect;
  984.     HPEN hPen;
  985.     HBRUSH hBrush;
  986.  
  987.     // build the rectangle
  988.     rect.left=item[CurItem].x+CurX;
  989.     rect.right=item[CurItem].x+CurX+item[CurItem].width;
  990.     rect.top=CurHeight+item[CurItem].y+item[CurItem].HeightAdj;
  991.     rect.bottom=rect.top+item[CurItem].height;
  992.  
  993.     // fill rectangle if needed
  994.     if (item[CurItem].flags&OFLAG_FILL) { // fill rectangle
  995.        if (NULL!=(hBrush=CreateBrushIndirect(&(item[CurItem].brush)))) {
  996.           FillRect(hDC,&rect,hBrush);
  997.           DeleteObject(hBrush);           // delete the temporary brush
  998.        }
  999.     }
  1000.  
  1001.     // draw the bounding rectangle
  1002.     if (item[CurItem].OutlineSelect) {// draw rectangle
  1003.        if (NULL!=(hPen=CreatePen(item[CurItem].OutlineStyle,item[CurItem].OutlineWidth,item[CurItem].OutlineColor))) {
  1004.           SelectObject(hDC,hPen);
  1005.           FrDrawOutline(hDC,&rect,item[CurItem].OutlineSelect);
  1006.           SelectObject(hDC,GetStockObject(BLACK_PEN));
  1007.           DeleteObject(hPen);             // delete the temporary pen
  1008.        }
  1009.     }
  1010.  
  1011.     // draw the item interior
  1012.     if (item[CurItem].type==LABEL)        PrintLabel(hDC,CurItem);
  1013.     else if (item[CurItem].type==FIELD)   PrintField(hDC,CurItem);
  1014.     else if (item[CurItem].type==LINE)    PrintLine(hDC,CurItem);
  1015.     else if (item[CurItem].type==PICT)    PrintPicture(hDC,CurItem);
  1016.  
  1017.     return TRUE;
  1018. }
  1019.  
  1020. /******************************************************************************
  1021.     PrintLabel:
  1022.     Print a label to the specified device context
  1023. *******************************************************************************/
  1024. int PrintLabel(HDC hDC, int CurItem)
  1025. {
  1026.     RECT rect;
  1027.     int  LabelWidth,LabelHeight,LabelLen,x,y,flags,font;
  1028.  
  1029.     // build the bounding rectangle
  1030.     rect.left=item[CurItem].x+CurX;
  1031.     rect.right=item[CurItem].x+CurX+item[CurItem].width;
  1032.     rect.top=item[CurItem].y+CurHeight+item[CurItem].HeightAdj;
  1033.     rect.bottom=rect.top+item[CurItem].height;
  1034.  
  1035.     // Get label dimension
  1036.     font=item[CurItem].font;
  1037.     LabelWidth=GetLabelLen(item[CurItem].label,font);
  1038.     LabelHeight=FrFont[font].height;
  1039.     LabelLen=lstrlen(item[CurItem].label);
  1040.  
  1041.     // Get the label position
  1042.     flags=item[CurItem].flags;
  1043.     if      (flags&OFLAG_HLEFT)  x=rect.left+DESC_MARGIN;
  1044.     else if (flags&OFLAG_HRIGHT) x=rect.left+(item[CurItem].width-LabelWidth)-DESC_MARGIN;
  1045.     else {
  1046.        x=rect.left+(item[CurItem].width-LabelWidth)/2; // center
  1047.        if (x<(rect.left+DESC_MARGIN)) x=rect.left+DESC_MARGIN;
  1048.     }
  1049.     if      (flags&OFLAG_VTOP)   y=rect.top;
  1050.     else if (flags&OFLAG_VBOTTOM)y=rect.top+(item[CurItem].height-LabelHeight);
  1051.     else                         y=rect.top+(item[CurItem].height-LabelHeight)/2; // center
  1052.     
  1053.  
  1054.     // Draw the label
  1055.     SetFont(hDC,(BYTE)font);
  1056.     SetTextColor(hDC,item[CurItem].TextColor);
  1057.     SetBkMode(hDC,TRANSPARENT);
  1058.     if (LabelLen>0) TextOut(hDC,x,y,item[CurItem].label,LabelLen);
  1059.  
  1060.     // update the last Y position
  1061.     if (CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj>LastY) 
  1062.        LastY=CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj;
  1063.     
  1064.     return TRUE;
  1065. }
  1066.  
  1067. /******************************************************************************
  1068.     PrintField:
  1069.     Format and print the current field
  1070. *******************************************************************************/
  1071. PrintField(HDC hDC, int CurItem)
  1072. {
  1073.     RECT rect;
  1074.     int i,j,x,y,count,CurField,LabelLen,LabelWidth,LabelHeight,font,flags,
  1075.         SuffixWidth,PosSuffixLen,NegSuffixLen;
  1076.     LPSTR ptr;
  1077.     char string[NAME_WIDTH+1];
  1078.  
  1079.     CurField=item[CurItem].field;    // field associated with the item
  1080.  
  1081.     font=item[CurItem].font;
  1082.  
  1083.     // build the bounding rectangle
  1084.     rect.left=item[CurItem].x+CurX;
  1085.     rect.right=item[CurItem].x+CurX+item[CurItem].width;
  1086.     rect.top=item[CurItem].y+CurHeight+item[CurItem].HeightAdj;
  1087.     rect.bottom=rect.top+item[CurItem].height;
  1088.  
  1089.     // print picture type field
  1090.     if (field[CurField].type==TYPE_PICT) {
  1091.        if (RepArg.DrawPicture) (RepArg.DrawPicture)(hDC,(int)field[CurField].NumData,field[CurField].FileId,field[CurField].FieldId,&rect);
  1092.        return TRUE; 
  1093.     }
  1094.  
  1095.     // print word wrapped field
  1096.     if (field[CurField].type==TYPE_TEXT 
  1097.      && field[CurField].flags&(FLAG_WRAP|FLAG_WORD_WRAP)) return PrintWrapField(hDC,CurItem);
  1098.     
  1099.  
  1100.     // get the formatted data
  1101.     FormatFieldData(&field[CurField],item[CurItem].label);
  1102.     if (field[CurField].type==TYPE_TEXT) {
  1103.        ptr=field[CurField].CharData;    // pointer to the formatted data
  1104.        TruncateText(ptr,item[CurItem].width,font);   // truncate text to fit within the label
  1105.     }
  1106.     else  ptr=item[CurItem].label;
  1107.     LabelLen=lstrlen(ptr);
  1108.  
  1109.     // special numeric field format processing
  1110.     if (field[CurField].type==TYPE_NUM || field[CurField].type==TYPE_DBL) {
  1111.         // check negative sign suffix
  1112.         SuffixWidth=0;
  1113.         NegSuffixLen=lstrlen(field[CurField].NegSignSuffix);
  1114.         if (NegSuffixLen>0 && LabelLen>NegSuffixLen 
  1115.          && lstrstr(&ptr[LabelLen-NegSuffixLen],field[CurField].NegSignSuffix)!=NULL)
  1116.             SuffixWidth=GetLabelLen(field[CurField].NegSignSuffix,font);
  1117.  
  1118.         // check positive sign suffix
  1119.         PosSuffixLen=lstrlen(field[CurField].PosSignSuffix);
  1120.         if (SuffixWidth==0 && PosSuffixLen>0 && LabelLen>PosSuffixLen 
  1121.          && lstrstr(&ptr[LabelLen-PosSuffixLen],field[CurField].PosSignSuffix)!=NULL)
  1122.             SuffixWidth=GetLabelLen(field[CurField].PosSignSuffix,font);
  1123.  
  1124.         // process 'pad with zero' flag
  1125.         if (field[CurField].flags&FLAG_PAD_ZERO) {
  1126.            count=(item[CurItem].width-GetLabelLen(ptr,font)+SuffixWidth)/GetLabelLen("0",font); // number of zeros to insert
  1127.            if (count>0) {
  1128.               for (i=j=0;i<LabelLen;i++,j++) {
  1129.                  // look for first numeric character
  1130.                  if (i==j && (ptr[i]=='.' || ptr[i]==',' || (ptr[i]>='0' && ptr[i]<='9'))) {  // first numeric character found
  1131.                      while (count>0) {
  1132.                         string[j]='0';
  1133.                         j++;
  1134.                         count--;
  1135.                      }
  1136.                  }
  1137.                  string[j]=ptr[i];
  1138.               }
  1139.               string[j]=0;
  1140.               lstrcpy(ptr,string);            // new string
  1141.               LabelLen=lstrlen(ptr);          // new label length
  1142.            }
  1143.         }
  1144.     }
  1145.     else SuffixWidth=0;
  1146.  
  1147.     // Get field dimension
  1148.     LabelWidth=GetLabelLen(ptr,font)-SuffixWidth;
  1149.     LabelHeight=FrFont[font].height;
  1150.  
  1151.     // Get the label position
  1152.     flags=item[CurItem].flags;
  1153.     if      (flags&OFLAG_HLEFT)  x=rect.left+DESC_MARGIN;
  1154.     else if (flags&OFLAG_HRIGHT) x=rect.left+(item[CurItem].width-LabelWidth)-DESC_MARGIN;
  1155.     else {
  1156.          x=rect.left+(item[CurItem].width-LabelWidth)/2; // center
  1157.          if (x<(rect.left+DESC_MARGIN) ) x=rect.left+DESC_MARGIN;
  1158.     }
  1159.     if      (flags&OFLAG_VTOP)   y=rect.top;
  1160.     else if (flags&OFLAG_VBOTTOM)y=rect.top+(item[CurItem].height-LabelHeight);
  1161.     else                         y=rect.top+(item[CurItem].height-LabelHeight)/2; // center
  1162.  
  1163.     
  1164.     // Draw the label
  1165.     SetFont(hDC,(BYTE)font);
  1166.     SetTextColor(hDC,item[CurItem].TextColor);
  1167.     SetBkMode(hDC,TRANSPARENT);
  1168.     if (LabelLen>0) TextOut(hDC,x,y,ptr,LabelLen);
  1169.  
  1170.     // update the last Y position
  1171.     if (CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj>LastY) 
  1172.        LastY=CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj;
  1173.  
  1174.     return TRUE;
  1175. }
  1176.  
  1177. /******************************************************************************
  1178.     PrintWrapField:
  1179.     Format and print a word/wrapped field
  1180. *******************************************************************************/
  1181. PrintWrapField(HDC hDC, int CurItem)
  1182. {
  1183.     RECT rect;
  1184.     int x,y,FirstChar,LastChar,CurField,LabelLen,i,LastItem,CurSec,
  1185.         LabelWidth,LabelHeight,font,flags,FieldHeight,DistanceY;
  1186.     char string[LINE_WIDTH+1];
  1187.     BOOL FlexibleSize,paged=FALSE;
  1188.  
  1189.     CurField=item[CurItem].field;    // field associated with the item
  1190.     FlexibleSize=field[CurField].flags&FLAG_FLEX_SIZE;
  1191.     font=item[CurItem].font;
  1192.     CurSec=item[CurItem].section; 
  1193.     LastItem=section[CurSec].FirstItem+section[CurSec].ItemCount-1;  // Last item in the section
  1194.  
  1195.     // build the bounding rectangle
  1196.     rect.left=item[CurItem].x+CurX;
  1197.     rect.right=item[CurItem].x+CurX+item[CurItem].width;
  1198.     rect.top=item[CurItem].y+CurHeight+item[CurItem].HeightAdj;
  1199.     rect.bottom=rect.top+item[CurItem].height;
  1200.  
  1201.     // get the formatted data
  1202.     FormatFieldData(&field[CurField],item[CurItem].label);
  1203.  
  1204.     // extract lines and print
  1205.     FirstChar=0;
  1206.     y=rect.top;
  1207.     SetFont(hDC,(BYTE)font);
  1208.     SetTextColor(hDC,item[CurItem].TextColor);
  1209.     SetBkMode(hDC,TRANSPARENT);
  1210.  
  1211.     while ((LastChar=ExtractLine(CurItem,string,FirstChar))!=-1) {
  1212.         StrTrim(string);                 // terminate space
  1213.  
  1214.         LabelWidth=GetLabelLen(string,font);
  1215.         LabelHeight=FrFont[font].height;
  1216.         LabelLen=lstrlen(string);
  1217.  
  1218.         // Get the label position
  1219.         flags=item[CurItem].flags;
  1220.         if      (flags&OFLAG_HLEFT)  x=rect.left+DESC_MARGIN;
  1221.         else if (flags&OFLAG_HRIGHT) x=rect.left+(item[CurItem].width-LabelWidth)-DESC_MARGIN;
  1222.         else                         x=rect.left+(item[CurItem].width-LabelWidth)/2; // center
  1223.         
  1224.         // Draw the text field
  1225.         if (LabelLen>0)   TextOut(hDC,x,y,string,LabelLen);
  1226.  
  1227.         y+=LabelHeight;
  1228.         FirstChar=LastChar+1;        // position for the next line
  1229.  
  1230.         // break if wrap rectangle is finished
  1231.         if ((y+LabelHeight>rect.bottom) && !FlexibleSize) break;  // next line can't fit in the item rectangle
  1232.  
  1233.         // break if current page is finished
  1234.         if ((y+LabelHeight>PrintHeight)) {
  1235.            if (CurSec!=SEC_DETAIL1) break;
  1236.  
  1237.            // last break field is allowed to continue to the next page
  1238.            PageAdvanced=FALSE;       // allow page advance now
  1239.            AdvancePage(CurSec);      // advance page
  1240.            y=rect.top=CurHeight;
  1241.            SetFont(hDC,(BYTE)font);  // set fonts again
  1242.            SetTextColor(hDC,item[CurItem].TextColor);
  1243.            SetBkMode(hDC,TRANSPARENT);
  1244.            rect.bottom=rect.top+PrintHeight; // allow full page
  1245.            paged=TRUE;                       // note the page advancement
  1246.         }
  1247.     }
  1248.  
  1249.     // check if Y adjustment for remaining field is needed
  1250.     FieldHeight=y-rect.top;
  1251.     if (FlexibleSize && FieldHeight!=item[CurItem].height) {
  1252.        for (i=CurItem+1;i<=LastItem;i++) {
  1253.           if (item[i].type==SECTION || item[i].type==GROUP) continue;
  1254.           if (item[i].section!=CurSec) continue;
  1255.           if (item[i].y>item[CurItem].y+item[CurItem].height-DESC_MARGIN) {
  1256.              if (paged) {
  1257.                 DistanceY=item[i].y-(item[CurItem].y+item[CurItem].height);  // distance between this item and end of the wrapped current item
  1258.                 item[i].HeightAdj=-item[i].y+FieldHeight+DistanceY;
  1259.              }
  1260.              else       item[i].HeightAdj=item[i].HeightAdj+FieldHeight-item[CurItem].height;
  1261.           }
  1262.        }
  1263.     }
  1264.  
  1265.     // update the last Y position
  1266.     if (y>LastY) LastY=y;
  1267.  
  1268.     return TRUE;
  1269. }
  1270.  
  1271. /******************************************************************************
  1272.     ExtractLine:
  1273.     This routine extract a line that can fit within the specified rectangle
  1274.     width. The extract line is returned using the second argument.  The third
  1275.     argument tells the beginning position within the source string to start
  1276.     using.
  1277.     The routine returns the position of the last character within the source 
  1278.     string.
  1279. *******************************************************************************/
  1280. ExtractLine(int CurItem,LPSTR string,int FirstChar)
  1281. {
  1282.     int i,j,k,font,CurField,DataLen,len,LineWidth;
  1283.     int LastWordSrcIndex,LastWordDstIndex;
  1284.     BOOL WordWrap;
  1285.     LPSTR ptr;
  1286.     char  ParaChar,CurChar;
  1287.     int  far *CharWidth;
  1288.  
  1289.     // initialize variables
  1290.     font=item[CurItem].font;                 // font to print the field
  1291.     CharWidth=FrFont[font].CharWidth;        // character width table
  1292.     CurField=item[CurItem].field;            // current field
  1293.     ptr=field[CurField].CharData;            // field text data pointer
  1294.     DataLen=lstrlen(ptr);                    // text data length
  1295.     ParaChar=field[CurField].ParaChar[0];    // paragraph break character
  1296.     if (field[CurField].flags&FLAG_WORD_WRAP) WordWrap=TRUE;  // Word wrap
  1297.     else                                       WordWrap=FALSE; // character wrap
  1298.  
  1299.     if (FirstChar>=(DataLen-1)) return -1;   // no more characters left
  1300.  
  1301.     // build new string
  1302.     LineWidth=0;                             // unit width of the string
  1303.     j=0;                                     // number of characters in the string
  1304.     i=FirstChar;
  1305.     LastWordSrcIndex=-1;                     // index of the last complete word in the source string
  1306.     LastWordDstIndex=-1;                     // index of the last complete word in the destination string
  1307.  
  1308.     while (TRUE) {
  1309.        if (i==DataLen) break;                // all characters processed
  1310.        if (j>=LINE_WIDTH) break;             // end of buffer
  1311.        
  1312.        CurChar=ptr[i];
  1313.        if (CurChar==ParaChar) {              // paragraph break
  1314.           string[j]=0;                       // terminate the string
  1315.           return i;                          // return the last character index
  1316.        }
  1317.  
  1318.        // translate characters               // cr/lf translation
  1319.        if (CurChar==0xA || CurChar==0xD) {  
  1320.           if (j>0 && string[j-1]==' ') {     // ignore
  1321.              i++;
  1322.              continue;
  1323.           }
  1324.           else CurChar=' ';                  // convert to spaces
  1325.        }
  1326.        else if (CurChar==0x9) {              // translate tab
  1327.           for (k=0;k<TAB_CHAR_LEN-1;k++) {   // expand to multiple spaces
  1328.              CurChar=' ';
  1329.              string[j]=CurChar;
  1330.              LineWidth+=CharWidth[(BYTE)CurChar];
  1331.              j++;
  1332.              if (j>=LINE_WIDTH || LineWidth>=item[CurItem].width) {
  1333.                 j--;
  1334.                 i--;
  1335.                 break;
  1336.              }
  1337.           }
  1338.        }
  1339.        
  1340.        // process a regular character
  1341.        string[j]=CurChar;
  1342.        LineWidth+=CharWidth[(BYTE)CurChar];
  1343.        j++;
  1344.        if (j>=LINE_WIDTH || LineWidth>=item[CurItem].width) {
  1345.           j--;
  1346.           i--;
  1347.           break;
  1348.        }
  1349.        i++;                                  // increment the source index
  1350.  
  1351.        // mark the last complete word
  1352.        if (CurChar==' ') {
  1353.           LastWordSrcIndex=i-1;              // index of the last word in the source string
  1354.           LastWordDstIndex=j-1;
  1355.        }
  1356.     }
  1357.  
  1358.     // cutoff at word boundary
  1359.     if (WordWrap && LastWordSrcIndex>0 && LineWidth>=item[CurItem].width) {
  1360.        i=LastWordSrcIndex;
  1361.        j=LastWordDstIndex;
  1362.     }
  1363.  
  1364.     len=j;
  1365.     string[len]=0;                           // terminate the string
  1366.  
  1367.     return i;                                // last character processed
  1368. }
  1369.  
  1370. /******************************************************************************
  1371.     PrintLine:
  1372.     Print a 'line' type item
  1373. *******************************************************************************/
  1374. PrintLine(HDC hDC, int CurItem)
  1375. {
  1376.     int x1,y1,x2,y2;
  1377.     HPEN hPen,hOldPen;
  1378.  
  1379.     // build the line beginning and ending coordinates
  1380.     if (item[CurItem].LineAngle==ANGLE_HORZ) {        // horizontal line
  1381.        x1=item[CurItem].x+CurX;
  1382.        y1=CurHeight+item[CurItem].y+item[CurItem].HeightAdj+item[CurItem].height/2;
  1383.        x2=x1+item[CurItem].width;
  1384.        y2=y1;
  1385.     }
  1386.     else if (item[CurItem].LineAngle==ANGLE_VERT) {   // vertical line
  1387.        x1=item[CurItem].x+CurX+item[CurItem].width/2;
  1388.        y1=CurHeight+item[CurItem].y+item[CurItem].HeightAdj;
  1389.        x2=x1;
  1390.        y2=y1+item[CurItem].height;
  1391.     }
  1392.     else if (item[CurItem].LineAngle==ANGLE_FDIAG) {  // diagonal line
  1393.        x1=item[CurItem].x+CurX;
  1394.        y1=CurHeight+item[CurItem].y+item[CurItem].HeightAdj;
  1395.        x2=x1+item[CurItem].width;
  1396.        y2=y1+item[CurItem].height;
  1397.     }
  1398.     else {                                            // backword diagonal line
  1399.        x1=item[CurItem].x+CurX;
  1400.        y1=CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj;
  1401.        x2=x1+item[CurItem].width;
  1402.        y2=CurHeight+item[CurItem].y;
  1403.     }
  1404.  
  1405.     // create the line pen
  1406.     if (NULL!=(hPen=CreatePen(item[CurItem].LineStyle,item[CurItem].LineWidth,item[CurItem].LineColor))) {
  1407.        hOldPen=SelectObject(hDC,hPen);
  1408.  
  1409.        // draw the line
  1410.        MoveToEx(hDC,x1,y1,NULL);
  1411.        LineTo(hDC,x2,y2);
  1412.  
  1413.        SelectObject(hDC,hOldPen);
  1414.        DeleteObject(hPen);             // delete the temporary pen
  1415.     }
  1416.  
  1417.     // update the last Y position
  1418.     if (CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj>LastY) 
  1419.        LastY=CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj;
  1420.  
  1421.     return TRUE;
  1422. }
  1423.  
  1424. /******************************************************************************
  1425.     PrintPicture:
  1426.     Draw a picture bitmap
  1427. *******************************************************************************/
  1428. PrintPicture(HDC hDC, int CurItem)
  1429. {
  1430.    int pict;
  1431.    LPBITMAPINFO pInfo;
  1432.    LPSTR pImage;
  1433.  
  1434.    pict=item[CurItem].font;             // index into the font structure
  1435.  
  1436.    // print a device independent bitmap
  1437.    if (NULL!=(pImage=GlobalLock(FrFont[pict].hImage)) 
  1438.     && NULL!=(pInfo=(LPBITMAPINFO)GlobalLock(FrFont[pict].hInfo)) ) { 
  1439.        
  1440.        StretchDIBits(hDC,item[CurItem].x+CurX,CurHeight+item[CurItem].y+item[CurItem].HeightAdj,item[CurItem].width,item[CurItem].height,
  1441.          0,0,(int)pInfo->bmiHeader.biWidth,(int)pInfo->bmiHeader.biHeight,pImage,pInfo,DIB_RGB_COLORS,SRCCOPY);
  1442.  
  1443.        GlobalUnlock(FrFont[pict].hImage);
  1444.        GlobalUnlock(FrFont[pict].hInfo);
  1445.    }
  1446.  
  1447.     // update the last Y position
  1448.     if (CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj>LastY) 
  1449.        LastY=CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj;
  1450.  
  1451.    return TRUE;
  1452. }
  1453.  
  1454. /******************************************************************************
  1455.     FormatFieldData:
  1456.     This routine format the specified field to the specified width.  It
  1457.     applies all applicable format to this field and returns the formatted
  1458.     string.
  1459. ******************************************************************************/
  1460. FormatFieldData(struct StrField huge *CurField,char far *string)
  1461. {
  1462.     int i,j,type,SumType,len,negative,DecPlaces,digits,DecFound,temp,
  1463.         ZeroValue,LeftSignLen,RightSignLen,CurrencySymLen;
  1464.     char line[LINE_WIDTH+2],mm[3],dd[3],yy[5];
  1465.     unsigned flags;
  1466.     long NumData;
  1467.     double DblData;
  1468.  
  1469.     type=CurField->type;
  1470.     SumType=CurField->SumType;
  1471.     flags=CurField->flags;
  1472.     DecPlaces=CurField->DecPlaces;
  1473.  
  1474.     NumData=0;
  1475.     DblData=0;
  1476.  
  1477.     if  (SumType==SUM_NONE)  {
  1478.         if (type==TYPE_DBL)   DblData=CurField->DblData;
  1479.         else                  NumData=CurField->NumData;
  1480.     }
  1481.     else if (SumType==SUM_COUNT) {
  1482.         if (type==TYPE_DBL)   DblData=CurField->count;
  1483.         else                  NumData=CurField->count;
  1484.         CurField->count=0;
  1485.     }
  1486.     else if (SumType==SUM_AVERAGE) {
  1487.         if (type==TYPE_DBL)   DblData=CurField->HoldDbl;
  1488.         else                  NumData=CurField->HoldNum;
  1489.         if (CurField->count>0) {
  1490.            if (type==TYPE_DBL)   DblData/=(double)CurField->count;
  1491.            else                  NumData/=(long)CurField->count;
  1492.         }
  1493.         CurField->count=0;
  1494.         CurField->HoldDbl=0;
  1495.         CurField->HoldNum=0;
  1496.     }
  1497.     else {
  1498.         if (type==TYPE_DBL)   DblData=CurField->HoldDbl;
  1499.         else                  NumData=CurField->HoldNum;
  1500.         CurField->HoldDbl=0;
  1501.         CurField->HoldNum=0;
  1502.     }
  1503.  
  1504.     //*************** Format Alpha Fields **********************************
  1505.     if (type==TYPE_TEXT) {
  1506.         
  1507.         string=CurField->CharData;
  1508.         len=strlen(string);
  1509.  
  1510.         if (flags&FLAG_CAPS) strupr(string);
  1511.         else if (flags&FLAG_SMALL) strlwr(string);
  1512.         else if (flags&FLAG_FIRST_CAP) {
  1513.            strlwr(string);
  1514.            for (i=0;i<len;i++) {
  1515.               if (i==0 || string[i-1]==' ') string[i]=toupper((string[i]));
  1516.            } 
  1517.         }
  1518.         
  1519.         if (flags&FLAG_TRIM) rTrim(string);
  1520.     }
  1521.  
  1522.     //**************** Format numeric fields ********************************
  1523.     else if (type==TYPE_NUM || type==TYPE_DBL) {
  1524.         negative=ZeroValue=FALSE;
  1525.         if (type==TYPE_NUM) {
  1526.            if (NumData<0) {
  1527.               negative=TRUE;
  1528.               NumData=-NumData;
  1529.            }
  1530.            if (NumData==0) ZeroValue=TRUE;
  1531.            
  1532.            ltoa(NumData,string,10);
  1533.            if (DecPlaces>0) {               // insert a decimal 
  1534.               len=strlen(string);
  1535.               if (DecPlaces>len) {
  1536.                  lPad(string,DecPlaces+1);
  1537.                  string[0]='.';
  1538.                  i=1;
  1539.                  while (string[i]==' ') {
  1540.                     string[i]='0';
  1541.                     i++;
  1542.                  }
  1543.               }
  1544.               else {
  1545.                  lPad(&string[len-DecPlaces],DecPlaces+1);
  1546.                  string[len-DecPlaces]='.';
  1547.               }
  1548.            }
  1549.         }
  1550.         else {                              // if type is equal to doubld 
  1551.            if (DblData<0) {
  1552.               negative=TRUE;
  1553.               DblData=-DblData;
  1554.            }
  1555.            if (DblData==0) ZeroValue=TRUE;
  1556.            
  1557.            DoubleToStr(DblData,DecPlaces,string);
  1558.         }
  1559.         
  1560.         //********************* insert comma characters *******************
  1561.         if (flags&FLAG_COMMA) {             // insert comma 
  1562.            len=strlen(string);
  1563.            for (digits=0;digits<len;digits++) if (string[digits]=='.') break;
  1564.            if (digits>0) {
  1565.               strcpy(line,string);
  1566.               j=0;
  1567.               DecFound=FALSE;
  1568.               for (i=0;i<len;i++,j++) {
  1569.                   if (DecFound) {           // simply copy the remaining digits 
  1570.                      string[j]=line[i];
  1571.                   }
  1572.                   else {                    // before decimal 
  1573.                      if (line[i]=='.') {
  1574.                         string[j]=line[i];
  1575.                         DecFound=TRUE;
  1576.                      }
  1577.                      else {                 // do we need to insert comma 
  1578.                         temp=digits/3;
  1579.                         if (digits==temp*3 && digits>0 && j>0) {// insert comma 
  1580.                            string[j]=',';
  1581.                            j++;
  1582.                         }
  1583.                         string[j]=line[i];
  1584.                         digits--;
  1585.                      }
  1586.                   }
  1587.               }
  1588.               string[j]=0;
  1589.            }
  1590.         }
  1591.         
  1592.  
  1593.         //******************* apply numeric attributes *******************************
  1594.         len=strlen(string);
  1595.         LeftSignLen=lstrlen(CurField->NegSignPrefix);
  1596.         if (lstrlen(CurField->PosSignPrefix)>LeftSignLen) LeftSignLen=lstrlen(CurField->PosSignPrefix);
  1597.         
  1598.         RightSignLen=lstrlen(CurField->NegSignSuffix);
  1599.         if (lstrlen(CurField->PosSignSuffix)>RightSignLen) RightSignLen=lstrlen(CurField->PosSignSuffix);
  1600.  
  1601.         CurrencySymLen=lstrlen(CurField->CurrencySymbol);
  1602.  
  1603.         //******************* insert the currency symbol ********************
  1604.         if (CurrencySymLen>0) {
  1605.            lPad(string,len+CurrencySymLen);
  1606.            for (i=0;i<CurrencySymLen;i++) string[i]=CurField->CurrencySymbol[i];
  1607.            len+=CurrencySymLen;
  1608.         }
  1609.  
  1610.         //******************* insert the left prefix symbol ********************
  1611.         if (LeftSignLen>0) {
  1612.            lPad(string,len+LeftSignLen);
  1613.            
  1614.            if (negative) {
  1615.               for (i=0;i<lstrlen(CurField->NegSignPrefix);i++) string[i]=CurField->NegSignPrefix[i];
  1616.            }
  1617.            else {
  1618.               for (i=0;i<lstrlen(CurField->PosSignPrefix);i++) string[i]=CurField->PosSignPrefix[i];
  1619.            }
  1620.            len+=LeftSignLen;
  1621.         }
  1622.  
  1623.         //******************* insert the right suffiex symbol ********************
  1624.         if (RightSignLen>0) {
  1625.            rPad(string,len+RightSignLen);
  1626.            
  1627.            if (negative) {
  1628.               for (i=0;i<lstrlen(CurField->NegSignSuffix);i++) string[len+i]=CurField->NegSignSuffix[i];
  1629.            }
  1630.            else {
  1631.               for (i=0;i<lstrlen(CurField->PosSignSuffix);i++) string[len+i]=CurField->PosSignSuffix[i];
  1632.            }
  1633.            len+=RightSignLen;
  1634.            rTrim(string);
  1635.         }
  1636.  
  1637.         //******************** length check *********************************
  1638.         if (flags&FLAG_SUP_ZERO && ZeroValue) string[0]=0;
  1639.     }
  1640.  
  1641.     //**************** Format date fields ***********************************
  1642.  
  1643.     else if (type==TYPE_DATE) {
  1644.         if (NumData<991231L) NumData=19000000L+NumData;
  1645.         ltoa(NumData,line,10);
  1646.  
  1647.         strcpy(dd,&line[6]);
  1648.         line[6]=0;
  1649.         strcpy(mm,&line[4]);
  1650.         line[4]=0;
  1651.         strcpy(yy,line);
  1652.         string[0]=0;
  1653.  
  1654.         switch (CurField->DateFormat) {
  1655.            case DT_MMDDYY:
  1656.                strcat(string,mm);
  1657.                lstrcat(string,CurField->DateDelim);
  1658.                strcat(string,dd);
  1659.                lstrcat(string,CurField->DateDelim);
  1660.                strcat(string,&yy[2]);
  1661.                break;
  1662.            case DT_DDMMYY:
  1663.                strcat(string,dd);
  1664.                lstrcat(string,CurField->DateDelim);
  1665.                strcat(string,mm);
  1666.                lstrcat(string,CurField->DateDelim);
  1667.                strcat(string,&yy[2]);
  1668.                break;
  1669.            case DT_MMDDYYYY:
  1670.                strcat(string,mm);
  1671.                lstrcat(string,CurField->DateDelim);
  1672.                strcat(string,dd);
  1673.                lstrcat(string,CurField->DateDelim);
  1674.                strcat(string,yy);
  1675.                break;
  1676.            case DT_MMMDDYYYY:
  1677.                temp=atoi(mm);
  1678.                if (temp<1) temp=1;
  1679.                if (temp>12) temp=12;
  1680.                strcat(string,MonthName[temp-1]);
  1681.                strcat(string," ");
  1682.                if (dd[0]=='0') strcat(string,&dd[1]);
  1683.                else            strcat(string,dd);
  1684.                strcat(string,", ");
  1685.                strcat(string,yy);
  1686.                break;
  1687.            default:
  1688.                ;
  1689.         }
  1690.     }
  1691.     
  1692.     //**************** Format the logical fields *****************************
  1693.  
  1694.     else if (type==TYPE_LOGICAL) {
  1695.         if (NumData) string[0]=CurField->LogicalSymbols[0];
  1696.         else         string[0]=CurField->LogicalSymbols[1];
  1697.         string[1]=0;
  1698.     }
  1699.  
  1700.     return TRUE;
  1701. }
  1702.  
  1703. /*****************************************************************************
  1704.     AcceptDlgField:
  1705.     Accept the values for the dialog fields from the user.  The fields are
  1706.     accept as specified by the PromptOrder variable.
  1707. *****************************************************************************/
  1708. AcceptDlgField()
  1709. {
  1710.     int fld,idx,FieldTable[MAX_DLGS],ord,TotalDlgFields,FieldFlag;
  1711.     int result;
  1712.     char string[NAME_WIDTH+2];
  1713.  
  1714.     // sort the fields in the prompt order 
  1715.     TotalDlgFields=0;
  1716.     for (ord=0;ord<MAX_DLGS;ord++) {
  1717.        for (fld=0;fld<MAX_DLGS;fld++) {
  1718.           if (DlgField[fld].InUse && DlgField[fld].PromptOrder==ord) {
  1719.              FieldTable[TotalDlgFields]=fld;
  1720.              TotalDlgFields++;
  1721.           }
  1722.        }
  1723.     }
  1724.  
  1725.     if (TotalDlgFields==0) return TRUE;   // dialog fields not used 
  1726.  
  1727.     idx=0;
  1728.  
  1729.     while(TRUE) {                         // accept/validate each field 
  1730.        if (idx>=TotalDlgFields) break;    
  1731.        fld=FieldTable[idx];
  1732.  
  1733.        
  1734.        ACCEPT_DATA:
  1735.  
  1736.        DlgIndex=fld;                      // pass information to the dialog box 
  1737.        FieldFlag=idx;
  1738.        if (idx==(TotalDlgFields-1)) FieldFlag=MAX_DLGS;
  1739.        result=CallDialogBox("DlgInputParam",DlgInputParam,(DWORD)FieldFlag);
  1740.        
  1741.        if (!result) {
  1742.           if (idx<=0) return FALSE;
  1743.           idx--;
  1744.           continue;
  1745.        }
  1746.        
  1747.        //***** convert and validate *****************
  1748.        if      (DlgField[fld].type==TYPE_NUM) DlgField[fld].NumData=atol(DlgField[fld].CharData);
  1749.        else if (DlgField[fld].type==TYPE_DBL) DlgField[fld].DblData=atof(DlgField[fld].CharData);
  1750.        else if (DlgField[fld].type==TYPE_LOGICAL) {
  1751.            strupr(DlgField[fld].CharData);
  1752.            StrTrim(DlgField[fld].CharData);
  1753.            if      (strstr("YES,TRUE,Y,1",DlgField[fld].CharData)) DlgField[fld].NumData=1;
  1754.            else if (strstr("NO,FALSE,N,0",DlgField[fld].CharData)) DlgField[fld].NumData=0;
  1755.            else {
  1756.               MessageBox(hFrWnd,"Valid entries: YES,NO,TRUE,FALSE,Y,N,1,0",NULL,MB_OK);
  1757.               goto ACCEPT_DATA;
  1758.            }
  1759.        }
  1760.        else if (DlgField[fld].type==TYPE_DATE) {
  1761.            if (DlgField[fld].CharData[0]!='\"') {   // enclose in quotes 
  1762.              strcpy(string,"\"");
  1763.              strcat(string,DlgField[fld].CharData);
  1764.              strcat(string,"\"");
  1765.            }
  1766.            else strcpy(string,DlgField[fld].CharData);
  1767.  
  1768.            if (!ValidateDate(string,&(DlgField[fld].NumData)) || DlgField[fld].NumData==-1) {
  1769.              MessageBox(hFrWnd,"Invalid Date Format/Value!",NULL,MB_OK);
  1770.              goto ACCEPT_DATA;
  1771.            }
  1772.        }
  1773.  
  1774.        idx++;
  1775.     }
  1776.  
  1777.     return TRUE;
  1778. }
  1779.  
  1780. /*****************************************************************************
  1781.    AllocRepMem:
  1782.    Allocate memory for:
  1783.    This routine adjusts the memory blocks allocated by the AllocFormMem
  1784.    routine and allocates these new objects:
  1785.    1. Sort Fields
  1786. *****************************************************************************/
  1787. AllocRepMem()
  1788. {
  1789.     int i;
  1790.     int FieldIndex,fld;
  1791.  
  1792.     if (UseScreen) {
  1793.        if ( (NULL==(hPageLoc=GlobalAlloc(GMEM_MOVEABLE,(long)(MAX_SCR_PAGES+1)*sizeof(long)))) 
  1794.           || (NULL==(PageLoc=(long far *)GlobalLock(hPageLoc))) ) {
  1795.           AbortFr("Ran Out of Memory (AllocRepMem)",ERR_NO_MEM);
  1796.        }
  1797.        FileBuf=OurAlloc(BUF_SIZE);        // allocate file buffer
  1798.     } 
  1799.     
  1800.     //**** allocate other object arrays *************************************
  1801.     if (  (NULL==(hUserField=GlobalAlloc(GMEM_MOVEABLE,(long)(TotalFields+1)*sizeof(struct StrField)))) 
  1802.        || (NULL==(UserField=(struct StrField huge *)GlobalLock(hUserField)))  
  1803.        || (NULL==(hSortField=GlobalAlloc(GMEM_MOVEABLE,(long)(TotalBreakFields+1)*sizeof(struct StrField)))) 
  1804.        || (NULL==(SortField=(struct StrField huge *)GlobalLock(hSortField))) ){
  1805.        AbortFr("Ran Out of Memory (AllocRepMem(1))",ERR_NO_MEM);
  1806.     }
  1807.  
  1808.     //***** shrink the field array ******************************************
  1809.     GlobalUnlock(hField);
  1810.     if (  (NULL==(hField=GlobalReAlloc(hField,(long)(TotalFields+1)*sizeof(struct StrField),0))) 
  1811.        || (NULL==(field=(struct StrField huge *)GlobalLock(hField)))  ){
  1812.        AbortFr("Ran Out of Memory (AllocRepMem(2))",ERR_NO_MEM);
  1813.     }
  1814.     
  1815.     for(fld=0;fld<TotalFields;fld++) {    // allocate space for the character fields 
  1816.        UserField[fld].type=field[fld].type;
  1817.        
  1818.        if (field[fld].type==TYPE_TEXT) {
  1819.           
  1820.           //***** update the width for the dialog fields **********
  1821.           if (field[fld].source==SRC_DLG) field[fld].width=DlgField[field[fld].SysIdx].width;
  1822.           
  1823.           if (NULL==(field[fld].CharData=OurAlloc(field[fld].width+2))
  1824.            || NULL==(UserField[fld].CharData=OurAlloc(field[fld].width+2)) ) {
  1825.              AbortFr("Ran Out of Memory(2)",ERR_NO_MEM);
  1826.           }
  1827.        }
  1828.     }
  1829.  
  1830.     for(i=0;i<TotalBreakFields;i++) {      // allocate space for the character sort fields 
  1831.        FieldIndex=BreakField[i].SortField; // index into the field table 
  1832.        SortField[i].type=field[FieldIndex].type;
  1833.  
  1834.        if (field[FieldIndex].type==TYPE_TEXT) {
  1835.           if (NULL==(SortField[i].CharData=OurAlloc(field[FieldIndex].width+2))) {
  1836.              AbortFr("Ran Out of Memory(3)",ERR_NO_MEM);
  1837.           }
  1838.        }
  1839.     }
  1840.  
  1841.     return TRUE;
  1842. }
  1843.  
  1844. /******************************************************************************
  1845.     StuffSysField:
  1846.     Build data for the system fields
  1847. *******************************************************************************/     
  1848. StuffSysField(struct StrField huge *field)
  1849. {
  1850.  
  1851.     switch (field->SysIdx) {
  1852.        case SYS_PAGE:
  1853.           field->NumData=PageCount;
  1854.           if (CurHeight>=PrintHeight) (field->NumData)++;
  1855.           break;
  1856.        case SYS_DATE:
  1857.           field->NumData=SystemDate;
  1858.           break;
  1859.        case SYS_TIME:
  1860.           lstrcpy(field->CharData,SystemTime);
  1861.           break;
  1862.        case SYS_REC_COUNT:
  1863.           field->NumData=RecCount+1;
  1864.           break;
  1865.        case SYS_PARA_BREAK:
  1866.           field->CharData[0]=DEF_PARA_BREAK;
  1867.           field->CharData[1]=0;
  1868.           break;
  1869.        default:  
  1870.           ;
  1871.     }
  1872.  
  1873.     return TRUE;
  1874. }
  1875.