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 >
Wrap
C/C++ Source or Header
|
1995-08-09
|
74KB
|
1,877 lines
/*==============================================================================
REP_REP.C
Report Ease: Report Executer Routines.
ReportEase Plus
Sub Systems, Inc.
ReportEase Plus, Copyright (c) 1993, Sub Systems, Inc. All Rights Reserved.
159 Main Street, #8C, Stoneham, MA 02180
(617) 438-8901.
Software License Agreement (1993)
----------------------------------
This license agreement allows the purchaser the right to modify the
source code to incorporate in their application.
The target application must not be distributed as a standalone report writer
or a mail merge product.
Sub Systems, Inc. reserves the right to prosecute anybody found to be
making illegal copies of the executable software or compiling the source
code for the purpose of selling there after.
===============================================================================*/
#include "windows.h"
#if defined (_WIN32)
#if !defined(WIN32)
#define WIN32
#endif
#endif
#if !defined(WIN32)
#include "print.h"
#endif
#include "stdio.h"
#include "stdlib.h"
#include "ctype.h"
#include "fcntl.h"
#include "io.h"
#include "sys\types.h"
#include "sys\stat.h"
#include "string.h"
#include "dos.h"
#include "math.h"
#include "setjmp.h"
#include "rep.h"
#define PREFIX extern
#include "rep1.h"
extern BOOL ReportEaseActive; // TRUE when report ease has been called
/******************************************************************************
RepInit:
This routine is called by the user application to initialize a report
run. The parameters are passed using the StrRep structure.
The routine returns a 0 value if the report is successfully initialized.
Otherwise it returns an error code (see ERR_ in the rew.h file).
This routine uses the input structure parameter (RepArg) to pass the
field information to the application routine. It returns the pointer
to two arrays:
1. field: Huge pointer to the field table. This table contains field information
about each field used by the form. The elements of a field
is defined using the StrField structure. Your application will need
to fill in the field data before calling the RepRec routine.
The number of fields in this table is given by the TotalFields variable
within the StrRep structure.
2. SortField: Huge pointer to the sort field table. This table contains field information
about each sort field used by the form. The elements of a field
is defined using the StrField structure. Your application should
sort the records as specified by these fields.
The number of fields in this table is given by the TotalSortFields variable
within the StrRep structure.
*******************************************************************************/
int WINAPI _export RepInit(struct StrRep far *ArgPtr)
{
LPSTR SaveCharPtr;
int j,i,select,len,result,HorzWidth,PrtResX,PrtResY;
int CompExp[NAME_WIDTH+2],LastSym,FieldIndex,fld,CurField;
int SecItem,FirstY,LastY,WrapItem,LastItem,AdjX,AdjY;
struct StrItem TempItem;
POINT pt;
// prepare to return an error code
#if defined (WIN32)
if (setjmp(FrAbort)==-1) return ErrorCode; // Fatal error return location
#else
if (Catch((LPCATCHBUF)&FrAbort)==-1) return ErrorCode; // Fatal error return location
#endif
// check if ReportEase alread active
if (ReportEaseActive) {
MessageBox(hFrParentWnd,"Report Ease Already Active!",NULL,MB_OK);
return ERR_DUPLICATE;
}
SessionType='R'; // Report Run session
ReportStage=IN_INIT; // in initialization
RepArg=*ArgPtr; // store the argument pointer
//****************** check if the input file exists ****************
if (access(RepArg.file,6)==-1) {
AbortFr("Form File Not Found!",ERR_NO_FILE);
}
//* Transfer the some input parameter variables to the global area *
strcpy(FrFileName,ArgPtr->file); // current report file name
FrShowHorBar=TRUE; // show horizontal scroll bar
FrShowVerBar=TRUE; // show vertical scroll bar
//hFrInst=ArgPtr->hInst; // uncomment for STATIC linking
//hFrPrevInst=ArgPtr->hPrevInst; // uncomment for STATIC linking
hFrWnd=NULL; // windows not opened yet
hFrParentWnd=ArgPtr->hParentWnd; // Handle to the parent window
//***************** Select the output device **********************
if (ArgPtr->device=='A') { // ask user for the output device
select=CallDialogBox("DeviceParam",DeviceParam,0);
if (select<0) return ERR_NO_DEVICE;
if (select==0) ArgPtr->device='S';
else ArgPtr->device='P';
}
if (ArgPtr->device=='S') UseScreen=TRUE;
else {
UseScreen=FALSE;
FrShowHorBar=FALSE; // show horizontal scroll bar
FrShowVerBar=FALSE; // show vertical scroll bar
}
//***************** Other initialization and file input
if (0!=(result=InitFr(RepArg.style,RepArg.x,RepArg.y,RepArg.width,RepArg.height))) return result;
if (UseScreen) {
FormHdr.RulerType=RULER_OFF; // turnoff the ruler
GetWinDimension(); // recalculate the window dimensions
}
AllocRepMem(); // allocate/reallocate arrays
//****************** accept the dialog fields ***************************
if (!AcceptDlgField()) {
ReportStatus=REP_ABORT; // user cancellation
RepExit();
return ERR_SUSPEND;
}
//****************** initialize the temporary fields ***************************
for (i=0;i<MAX_TEMP_FIELDS;i++) {
InitField(&TempField[i]);
TempField[i].InUse=FALSE;
}
//***************** Stuff the sort fields *******************************
for(i=0;i<TotalBreakFields;i++) { // allocate space for the character sort fields
FieldIndex=BreakField[i].SortField; // index into the field table
SaveCharPtr=SortField[i].CharData; // this field already allocated
SortField[i]=field[FieldIndex];
SortField[i].CharData=SaveCharPtr;
}
//***************** Assign the constant string and dialog fields **********
for (fld=0;fld<TotalFields;fld++) {
if (field[fld].type==TYPE_TEXT) field[fld].CharData[0]=0;// initialize
if (field[fld].source==SRC_CONST) {
if (field[fld].type==TYPE_TEXT) {
lstrcpy(field[fld].CharData,&field[fld].name[1]); // exclude the initial quote
len=lstrlen(field[fld].CharData);
if (len>0) field[fld].CharData[len-1]=0; // exclude the ending quotes
}
}
else if (field[fld].source==SRC_DLG) { // assign fields
if (field[fld].type==TYPE_TEXT) {
lstrcpy(field[fld].CharData,DlgField[field[fld].SysIdx].CharData);
}
else {
field[fld].NumData=DlgField[field[fld].SysIdx].NumData;
field[fld].DblData=DlgField[field[fld].SysIdx].DblData;
}
}
}
//***************** compile the report selection criteria ****************
LastSym=CompileExp(FormHdr.SelExp,CompExp);// compile the expression
if (LastSym!=END_OF_EXP) { // error encountered
AbortFr("Invalid Report Selection Expression!",ERR_BAD_EXP);
}
i=0;
while(CompExp[i]!=END_OF_EXP) { // transfer to the structure
FormHdr.SelExp[i]=CompExp[i];
i++;
}
FormHdr.SelExp[i]=CompExp[i];
//***************** compile the field expressions *********************
for (j=0;j<TotalFields;j++) {
if (field[j].source==SRC_CALC) {
LastSym=CompileExp(field[j].CalcExp,CompExp);// compile the expression
if (LastSym!=END_OF_EXP) { // error encountered
AbortFr("Invalid Field Calculation Expression!",ERR_BAD_EXP);
}
i=0;
while(CompExp[i]!=END_OF_EXP) { // transfer to the structure
field[j].CalcExp[i]=CompExp[i];
i++;
}
field[j].CalcExp[i]=CompExp[i];
}
}
//***************** compile the section selection expressions *********************
for (j=0;j<MAX_SECTIONS;j++) {
if (section[j].InUse) {
LastSym=CompileExp(section[j].SelExp,CompExp);// compile the expression
if (LastSym!=END_OF_EXP) { // error encountered
AbortFr("Invalid Section Selection Expression!",ERR_BAD_EXP);
}
i=0;
while(CompExp[i]!=END_OF_EXP) { // transfer to the structure
section[j].SelExp[i]=CompExp[i];
i++;
}
section[j].SelExp[i]=CompExp[i];
}
}
//***************** Initialize the user fields ****************************
for (fld=0;fld<TotalFields;fld++) {
SaveCharPtr=UserField[fld].CharData; // this field already allocated
UserField[fld]=field[fld];
UserField[fld].CharData=SaveCharPtr;
if (field[fld].type==TYPE_TEXT) lstrcpy(UserField[fld].CharData,field[fld].CharData);
}
//********************* initialize the section and section items ***********
for (i=0;i<MAX_SECTIONS;i++) { // initialize the section pointers
if (!section[i].InUse) continue;
SecItem=section[i].ScrItem; // section position in the item table
item[SecItem].y=item[SecItem].y+FormHdr.SecBannerHeight;
item[SecItem].height=item[SecItem].height-FormHdr.SecBannerHeight;
section[i].FirstItem=SecItem;
section[i].ItemCount=1; // include the section item
// calculate first and last Y position of items within the section
FirstY=LastY=-1; // initialize
for (j=section[i].FirstItem+1;j<TotalItems;j++) {
if (item[j].section!=i) break; // next section begins
section[i].ItemCount++;
if (item[j].type==GROUP) continue; // ignore group items
if (FirstY==-1) FirstY=item[j].y; // find the first item position
else if (item[j].y<FirstY) FirstY=item[j].y;
if (item[j].y+item[j].height>LastY) LastY=item[j].y+item[j].height;
// initialize the field variables
if (item[j].type==FIELD) {
CurField=item[j].field;
field[CurField].section=UserField[CurField].section=i;
if (i<SEC_FTR_LVL9) field[CurField].SumType=UserField[CurField].SumType=SUM_NONE;
}
}
// adjust the item Y positions within the section
if (!(section[i].flags&SFLAG_TRIM_BEFORE)) FirstY=item[SecItem].y;
if (!(section[i].flags&SFLAG_TRIM_AFTER)) LastY=item[SecItem].y+item[SecItem].height;
if (FirstY==-1 || LastY==-1) {
section[i].ItemCount=0;
section[i].height=0;
}
else {
section[i].height=LastY-FirstY;
for (j=section[i].FirstItem;j<TotalItems;j++) {
if (item[j].section!=i) break; // next section begins
item[j].y-=FirstY; // position relative to the section beginning
}
// set the section item to begin at relative zero
j=section[i].FirstItem;
item[j].y=0; // set the section beginning to zero
item[j].height=LastY-FirstY+1;
}
// move the wrap field at the last position
if (i==SEC_DETAIL1 && section[i].ItemCount>0) {
WrapItem=-1;
LastItem=section[i].FirstItem+section[i].ItemCount-1;
for (j=section[i].FirstItem;j<=LastItem;j++) {
if (item[j].type==GROUP || item[j].type==SECTION) continue; // ignore group items
if (WrapItem!=-1) { // check any item after the wrap item
if (item[j].y>=item[WrapItem].y+item[WrapItem].height-DESC_MARGIN) WrapItem=-1; // discard this wrap item
}
if (item[j].type!=FIELD) continue;
CurField=item[j].field;
if (field[CurField].type==TYPE_TEXT
&& field[CurField].flags&(FLAG_WRAP|FLAG_WORD_WRAP)) WrapItem=j;
}
if (WrapItem!=-1 && WrapItem!=LastItem) { // reloate the wrap item
HugeMove(&(item[WrapItem]),&TempItem,sizeof(struct StrItem));
HugeMove(&(item[LastItem]),&(item[WrapItem]),sizeof(struct StrItem));
HugeMove(&TempItem,&(item[LastItem]),sizeof(struct StrItem));
WrapItem=LastItem;
}
LastWrapItem=WrapItem;
}
}
//***************** other initialization **********************************
GetSystemDateTime(); // get the system date and time
// initialize month array
MonthName[0]="Jan";MonthName[1]="Feb";MonthName[2]="Mar";
MonthName[3]="Apr";MonthName[4]="May";MonthName[5]="Jun";
MonthName[6]="Jul";MonthName[7]="Aug";MonthName[8]="Sep";
MonthName[9]="Oct";MonthName[10]="Nov";MonthName[11]="Dec";
RecCount=0; // First rec to be read by the application
PageCount=1; // first page
ScrPage=0; // screen page being displayed
CurX=0; // current displacement toward x direction
CurHeight=0; // current Y displacement
CurCol=0; // current column for multiple column sections
TrialMode=FALSE; // trial mode prints trial records
hMetaFile=NULL; // current screen page in memory meta file
PageAdvanced=FALSE; // set after page is advanced
AdvancingPage=FALSE; // set during page advance
ReportStatus=REP_RESUMED;
//*************** initialize the page variables *******************
LeftMargin=(int)((FormHdr.LeftMargin)*UNITS_PER_INCH); // margins logical in units
RightMargin=(int)((FormHdr.RightMargin)*UNITS_PER_INCH);
TopMargin=(int)((FormHdr.TopMargin)*UNITS_PER_INCH);
BottomMargin=(int)((FormHdr.BottomMargin)*UNITS_PER_INCH);
PrintWidth=(int)(PrintWidthInches*UNITS_PER_INCH); // width of the printed area
// adjust left and top margin for the hidden areas
Escape(hPrtDC,GETPRINTINGOFFSET,0,NULL,&pt); // actual offset where printing begins
PrtResX=GetDeviceCaps(hPrtDC,LOGPIXELSX); // number of pixels per inch of X direction
PrtResY=GetDeviceCaps(hPrtDC,LOGPIXELSY); // number of pixels per inch of Y direction
AdjX=MulDiv(pt.x,UNITS_PER_INCH,PrtResX); // printing area begin position
AdjY=MulDiv(pt.y,UNITS_PER_INCH,PrtResY);
LeftMargin-=AdjX; // margin relative to printing area
TopMargin-=AdjY;
for (i=0;i<TotalItems;i++) item[i].x-=AdjX; // x relative to printing area
PageHeight=(int)(PrintHeightInches*UNITS_PER_INCH)+TopMargin; // height of the printed page
if (section[SEC_FTR_PAGE].InUse) PrintHeight=PageHeight-section[SEC_FTR_PAGE].height;
else PrintHeight=PageHeight;
if (PrintHeight<=0) {
MessageBox(hFrWnd,"Page Too Small!",NULL,MB_OK);
return ERR_PRINTER;
}
//******************** set additional window characteristics ****************
if (UseScreen) {
//******************** set the left margin on the screen ****************
FrWinOrgX=FrWinOrgY=0;
FrSetViewWindow(); // set the logical window origin
//******************* set scroll bars **********************************
HorzWidth=PrintWidth-FrWinWidth;
if (HorzWidth>0) {
HorScrollPos=HOR_SCROLL_MIN+(int)((long)FrWinOrgX*(HOR_SCROLL_MAX-HOR_SCROLL_MIN)/HorzWidth);
if (HorScrollPos>HOR_SCROLL_MAX) HorScrollPos=HOR_SCROLL_MAX;
SetScrollPos(hFrWnd,SB_HORZ,HorScrollPos,TRUE);
}
SetScrollPos(hFrWnd,SB_VERT,VER_SCROLL_MIN,TRUE);
//****************** Create a new meta file **********************
if (NULL==(hMetaDC=CreateMetaFile(NULL))) AbortFr("Error creating metafile",ERR_NO_FILE);
ShowScrRepStatus(); // show screen reporting status
RepInitMenu(hFrMenu); // initialize the menu bar
}
//***************** Initialize the system fields ****************************
for (fld=0;fld<TotalFields;fld++) {
if (field[fld].source==SRC_SYS) {
StuffSysField(&field[fld]);
StuffSysField(&UserField[fld]);
}
}
//***************** stuff the return fields*******************************
RepArg.field=UserField; // field to be filled by the user application
RepArg.TotalFields=TotalFields;
RepArg.SortField=SortField;
RepArg.TotalSortFields=TotalBreakFields;
lstrcpy(RepArg.DataSetName,FormHdr.DataSetName);
(*ArgPtr)=RepArg; // return the updated structure
return 0;
}
/******************************************************************************
RepRec:
This routine is called by the user application to print each record.
The field data for the record must be passed using the 'field' array
as returned by the RepInit routine.
Your application should fill in the data for only the fields of SOURCE
type equal to SCR_APPL. The data in other fields must not be modified in
any way.
Only the following elements in the field structure can be used to pass data:
CharData (char far *) to pass the character string data.
The character data being copied to the CharData pointer
should not be larger than the 'width' as specified in
the field structure. This variable (width) holds the character
field width as specified by your application during the
form edit process.
NumData (long) to pass numeric, logical and date data.
(date should be passed either as YYMMDD or YYYYMMDD format).
DblData (double) to pass float numeric data.
No other element of field structure should be modified.
*******************************************************************************/
int WINAPI _export RepRec()
{
int sec,BreakSort;
struct StrField TempField,huge *SaveField=NULL;
int LastSym;
int fld;
// prepare to return an error code
#if defined (WIN32)
if (setjmp(FrAbort)==-1) { // Fatal error return location
#else
if (Catch((LPCATCHBUF)&FrAbort)==-1) { // Fatal error return location
#endif
if (SaveField!=NULL) {
field=SaveField;
SaveField=NULL;
}
return ErrorCode;
}
ReportStage=IN_RECORDS; // processing records
//******************** Apply record selection criteria ******************
EvaluateSystemFields(); // update system fields
if (FormHdr.SelExp[0]!=END_OF_EXP) {
SaveField=field; // activate user fields
field=UserField;
LastSym=RunExp(FormHdr.SelExp,&TempField,TRUE); // run the expression and return the output in the field
field=SaveField; // activate the original field
SaveField=NULL;
if (LastSym!=END_OF_EXP || TempField.type!=TYPE_LOGICAL) { // error encountered
MessageBox(hFrWnd,"Error In Record Filter",NULL,MB_OK);
return ERR_BAD_EXP;
}
if (!(TempField.NumData)) return 0;// record not selected
}
//************ calculate the break fields *********
SaveField=field; // activate user fields
field=UserField;
CalculateBreakFields();
field=SaveField; // activate the original field
SaveField=NULL;
//******************** Initialize for the first record *******************
if (RecCount==0) InitFirstRec();
//************************ Check for sort breaks ***********************
BreakSort=PrintSortFooters();
//**************** copy the user field to the global field ***************
for (fld=0;fld<TotalFields;fld++) {
if (field[fld].type==TYPE_TEXT) lstrcpy(field[fld].CharData,UserField[fld].CharData);
else if (field[fld].type==TYPE_DBL) field[fld].DblData=UserField[fld].DblData;
else field[fld].NumData=UserField[fld].NumData;
}
//******************* Evaluate the calculation fields ******************
CalculateFields(0,MAX_SECTIONS-1); // calculate all fields for all section
//************************* Print sort headers **************************
PrintSortHeaders(BreakSort);
//************************* Print the detail sections **********************
for (sec=SEC_DETAIL1;sec<=SEC_DETAIL9;sec++) PrintSection(sec);
//************************* Do totals ************************************
for (fld=0;fld<TotalFields;fld++) {
field[fld].count++;
if (field[fld].SumType==SUM_MAX) {
if (field[fld].DblData>field[fld].HoldDbl) field[fld].HoldDbl=field[fld].DblData;
if (field[fld].NumData>field[fld].HoldNum) field[fld].HoldNum=field[fld].NumData;
}
else if (field[fld].SumType==SUM_MIN) {
if (field[fld].DblData<field[fld].HoldDbl) field[fld].HoldDbl=field[fld].DblData;
if (field[fld].NumData<field[fld].HoldNum) field[fld].HoldNum=field[fld].NumData;
}
else {
field[fld].HoldDbl+=field[fld].DblData;
field[fld].HoldNum+=field[fld].NumData;
}
}
if (UseScreen) {
// show progress
if ( (RecCount<50 && RecCount%5==0) || RecCount%10==0) ShowScrRepStatus(); // show print progress
ProcessUserCommands(); // process any pending messages
}
RecCount++; // increment number of records printed
return 0;
}
/*****************************************************************************
RepExit:
*****************************************************************************/
int WINAPI _export RepExit()
{
int CurSort,CurSec,FooterSec;
// prepare to return an error code
#if defined (WIN32)
if (setjmp(FrAbort)==-1) return ErrorCode; // Fatal error return location
#else
if (Catch((LPCATCHBUF)&FrAbort)==-1) return ErrorCode; // Fatal error return location
#endif
if (ReportStatus!=REP_ABORT && RecCount>0) {
ReportStage=IN_TOTALS; // printing totals
//******************** calculate the footer fields ********************
CalculateFields(SEC_FTR_LVL9,SEC_FTR_REP);
//******************** print sort footers ******************************
for (CurSort=(TotalBreakFields-1);CurSort>=0;CurSort--) {
CurSec=BreakField[CurSort].section;
FooterSec=SEC_FTR_LVL1-(CurSec-SEC_HDR_LVL1);
PrintSection(FooterSec); // print section footer
}
PrintSection(SEC_FTR_REP); // print the report footers
CurHeight=PrintHeight; // print last page footer
PageAdvanced=AdvancingPage=TRUE;
PrintSection(SEC_FTR_PAGE);
}
if (ReportStatus!=REP_ABORT) {
if (UseScreen) {
ReportStage=IN_EXIT;
TransferMetaFile(); // transfer the last metafile page to disk
RepInitMenu(hFrMenu); // redisplay the menu
PaintRepScr(); // show screen
}
else {
ReportStage=IN_EXIT;
Escape(hFrDC,NEWFRAME,0,0L,0L);
}
}
if (UseScreen && ReportStatus!=REP_ABORT)
return 0; // do cleanup later
else return RepCleanup(); // do cleanup now
}
/*****************************************************************************
RepCleanup:
Release the report resources
*****************************************************************************/
int RepCleanup()
{
int i;
char string[85];
int fld;
HMETAFILE hMeta;
//******* release printer window resources *********
if (!UseScreen) {
if (RecCount>0) {
PrintProc(hFrDC,0); // show the last status
Escape(hFrDC,ENDDOC,0,0L,0L); // end of print job
if (hFrWnd) EnableWindow(hFrWnd,TRUE); // activate the parent window
DestroyWindow(hAbortWnd); // destroy the abort window
FreeProcInstance(lpProc); // free the process instances
FreeProcInstance(lpAbortDlg);
}
if (ReportStatus!=REP_ABORT) {
wsprintf(string,"%ld Record(s) Printed",RecCount);
MessageBox(hFrWnd,string,"Report Over",MB_ICONSTOP);
}
}
//*********************** Do cleanup ***********************************
// free up space taken by the character fields
for(fld=0;fld<TotalFields;fld++) { // allocate space for the character fields
if (field[fld].type==TYPE_TEXT && field[fld].CharData!=NULL) OurFree(field[fld].CharData);
if (UserField[fld].type==TYPE_TEXT && UserField[fld].CharData!=NULL) OurFree(UserField[fld].CharData);
}
for(i=0;i<TotalBreakFields;i++) { // allocate space for the character fields
if (SortField[i].type==TYPE_TEXT) OurFree(SortField[i].CharData);
}
//*********** free up addtional global memory blocks ****
GlobalUnlock(hSortField);
GlobalFree(hSortField);
GlobalUnlock(hUserField);
GlobalFree(hUserField);
//*********** free up screen arrays *******************************
if (UseScreen) {
GlobalUnlock(hPageLoc);
GlobalFree(hPageLoc);
OurFree(FileBuf); // free the file buffer
// close the last metafile device context and delete the memory metafile
if (hMetaDC && NULL!=(hMeta=CloseMetaFile(hMetaDC))) DeleteMetaFile(hMeta);
unlink(MetaFile); // delete meta files
unlink(TempMetaFile); // delete temporary meta file
unlink(ScrMetaFile); // delete screen meta file
unlink(PrtMetaFile); // delete selective print file
}
FrModified=FALSE;
CloseFr();
return 0;
}
/******************************************************************************
PrintSortFooters:
Check if sort break has taken places. If so, write the old sort footers.
*******************************************************************************/
PrintSortFooters()
{
int CurSort,CurSec,BreakSort,FooterSec;
int CurField;
for (CurSort=0;CurSort<TotalBreakFields;CurSort++) {
CurField=BreakField[CurSort].CompField;
if (field[CurField].type==TYPE_TEXT &&
lstrcmp(UserField[CurField].CharData,field[CurField].CharData)!=0) break;
else if (field[CurField].type==TYPE_DBL &&
UserField[CurField].DblData!=field[CurField].DblData) break;
else if (UserField[CurField].NumData!=field[CurField].NumData) break;
}
if (CurSort==TotalBreakFields) return CurSort; // no sort breaks
BreakSort=CurSort;
//******************** calculate the footer fields ********************
CalculateFields(SEC_FTR_LVL9,SEC_FTR_REP);
//***************** write sort section footers ************************
for (CurSort=(TotalBreakFields-1);CurSort>=BreakSort;CurSort--) {
CurSec=BreakField[CurSort].section;
FooterSec=SEC_FTR_LVL1-(CurSec-SEC_HDR_LVL1);
PrintSection(FooterSec); // print section footer
}
return BreakSort;
}
/******************************************************************************
PrintSortHeaders:
This routine prints sort headers for all levels below the specified level.
*******************************************************************************/
PrintSortHeaders(int BreakSort)
{
int CurSort,CurSec,FooterSec;
int fld;
if (BreakSort>=TotalBreakFields) return TRUE; // no sort breaks
//***************** write sort section headers ***************************
for (CurSort=BreakSort;CurSort<TotalBreakFields;CurSort++) {
CurSec=BreakField[CurSort].section;
PrintSection(CurSec); // print section headers
FooterSec=SEC_FTR_LVL1-(CurSec-SEC_HDR_LVL1);
for(fld=0;fld<TotalFields;fld++) { // clear accumulaters
if (field[fld].InUse && field[fld].section==FooterSec) {
if (!(FLAG_RETAIN&field[fld].flags)) {
field[fld].HoldNum=0;
field[fld].HoldDbl=0;
field[fld].count=0;
if (field[fld].SumType==SUM_MIN || field[fld].SumType==SUM_MAX) {
field[fld].HoldNum=field[fld].NumData;
field[fld].HoldDbl=field[fld].DblData;
}
}
}
}
}
return TRUE;
}
/*****************************************************************************
EvaluateSystemFields:
Evaludate system fields
*****************************************************************************/
EvaluateSystemFields()
{
int fld;
// evaluate system fields ********
for (fld=0;fld<TotalFields;fld++) {
if (field[fld].source==SRC_SYS) {
StuffSysField(&UserField[fld]);
}
}
return TRUE;
}
/*****************************************************************************
CalculateFields:
Do calculation and assin systems fields
*****************************************************************************/
CalculateFields(int FirstSec,int LastSec)
{
int fld,LastSym;
struct StrField TempField;
// evaluate calculated fields ****
for (fld=0;fld<TotalFields;fld++) {
if (field[fld].source==SRC_CALC && field[fld].section>=FirstSec && field[fld].section<=LastSec) {
LastSym=RunExp(field[fld].CalcExp,&TempField,TRUE); // run the expression and return the output in the field
if (LastSym!=END_OF_EXP) { // error encountered
wsprintf(msg,"Error In Calculation Field: %s",(LPSTR)(field[fld].name));
AbortFr(msg,ERR_BAD_EXP);
}
if (field[fld].type==TYPE_TEXT && field[fld].CharData!=NULL) {
OurFree(field[fld].CharData);
field[fld].CharData=NULL;
}
if (TempField.type==TYPE_TEXT) field[fld].CharData=TempField.CharData;
else if (TempField.type==TYPE_DBL) field[fld].DblData=TempField.DblData;
else field[fld].NumData=TempField.NumData;
}
}
return TRUE;
}
/*****************************************************************************
CalculateSecExp:
Calculate the section selection expression.
*****************************************************************************/
CalculateSecExp(int CurSec)
{
int LastSym;
struct StrField TempField;
if (section[CurSec].InUse) {
if (section[CurSec].SelExp[0]==END_OF_EXP) section[CurSec].selected=TRUE;
else {
LastSym=RunExp(section[CurSec].SelExp,&TempField,TRUE); // run the expression and return the output in the field
if (LastSym!=END_OF_EXP) { // error encountered
AbortFr("Error In Section Filter",ERR_BAD_EXP);
}
section[CurSec].selected=(int)TempField.NumData;
}
}
else section[CurSec].selected=FALSE;
return section[CurSec].selected;
}
/*****************************************************************************
CalculateBreakFields:
Calculation fields used for break comparison
*****************************************************************************/
CalculateBreakFields()
{
int fld,LastSym;
struct StrField TempField;
int i;
for (i=0;i<TotalBreakFields;i++) {
fld=BreakField[i].CompField;
if (field[fld].source==SRC_CALC) {
LastSym=RunExp(field[fld].CalcExp,&TempField,TRUE); // run the expression and return the output in the field
if (LastSym!=END_OF_EXP) { // error encountered
wsprintf(msg,"Error In Break Calculation Field: %s",(LPSTR)(field[fld].name));
AbortFr(msg,ERR_BAD_EXP);
}
if (field[fld].type==TYPE_TEXT && field[fld].CharData!=NULL) {
OurFree(field[fld].CharData);
field[fld].CharData=NULL;
}
if (TempField.type==TYPE_TEXT) field[fld].CharData=TempField.CharData;
else if (TempField.type==TYPE_DBL) field[fld].DblData=TempField.DblData;
else field[fld].NumData=TempField.NumData;
}
}
return TRUE;
}
/*****************************************************************************
InitFirstRec:
Do initialization for the first record.
*****************************************************************************/
InitFirstRec()
{
int i,CurSec;
int fld;
//***************** copy from user fields ***************************
for (fld=0;fld<TotalFields;fld++) {
if (field[fld].type==TYPE_TEXT) lstrcpy(field[fld].CharData,UserField[fld].CharData);
else if (field[fld].type==TYPE_DBL) field[fld].DblData=UserField[fld].DblData;
else field[fld].NumData=UserField[fld].NumData;
}
CalculateFields(0,MAX_SECTIONS-1); // do calculation for the first record
//***************** initialize the output device ***************************
ReportStatus=REP_RESUMED; // report in progress
if (UseScreen) { // show the blank screen
RepInitMenu(hFrMenu); // initialize the menu items
CurHeight=TopMargin;
}
else {
lpAbortDlg = MakeProcInstance((FARPROC)PrintAbortParam, hFrInst);
hAbortWnd=CreateDialog(hFrInst,"PrintAbortParam",hFrWnd,(DLGPROC)lpAbortDlg);
ShowWindow(hAbortWnd,SW_NORMAL);
lpProc = MakeProcInstance((FARPROC)PrintProc, hFrInst);
SetAbortProc(hFrDC,(ABORTPROC)lpProc);
if (Escape(hFrDC,STARTDOC,strlen(FormHdr.name),FormHdr.name,NULL)<0) {
AbortFr("Unable to Start the Print Job",ERR_PRINTER);
}
UpdateWindow(hAbortWnd);
if (hFrWnd) EnableWindow(hFrWnd,FALSE); // disable the main window
FrWinWidth=PrintWidth+LeftMargin+RightMargin; // to enable use of display routines for printing
}
CurHeight=TopMargin; // start printing from the top page
if (RFLAG_TRIAL&FormHdr.flags && !UseScreen) PrintTrial(); // print trial run
PageAdvanced=TRUE; // suppress page advance
PrintSection(SEC_HDR_PAGE); // print page header
PageAdvanced=TRUE; // suppress page advance
PrintSection(SEC_HDR_REP); // print the report header
for (i=0;i<TotalBreakFields;i++) { // print group headers
CurSec=BreakField[i].section;
PageAdvanced=TRUE; // suppress page advance
PrintSection(CurSec);
}
PageAdvanced=TRUE;
return TRUE;
}
/*****************************************************************************
PrintSection:
This routine prints lines for a specified section. The routine will
apply the current record data to the fields found in the section.
*****************************************************************************/
PrintSection(int CurSec)
{
int FromItem,ToItem,CurItem;
if (!(section[CurSec].InUse)) return FALSE; // this section not used
if (!(CalculateSecExp(CurSec))) return FALSE; // this section not selected
FromItem=section[CurSec].FirstItem;
ToItem=FromItem+section[CurSec].ItemCount-1;
if (ToItem<FromItem) return FALSE;
// force to first column when not in the first detail section
if (CurSec!=SEC_DETAIL1 && CurCol!=0) {
CurCol=0;
CurHeight=LastY; // update the current y location
}
// Check for page advance
if (CurCol==0) {
if (SFLAG_PAGE_BEF&(section[CurSec].flags)) AdvancePage(CurSec);
else if (CurHeight+section[CurSec].height>PrintHeight) AdvancePage(CurSec);
LastY=CurHeight; // track last Y position used for printing
}
CurX=CurCol*(item[section[CurSec].ScrItem].width); // x displacement
// clear the height adjusment field
for (CurItem=FromItem;CurItem<=ToItem;CurItem++) item[CurItem].HeightAdj=0;
// Print each item
for (CurItem=FromItem;CurItem<=ToItem;CurItem++) { // process each line
if (item[CurItem].type==GROUP) continue;
if (item[CurItem].section!=CurSec) continue;
if (UseScreen) PrintItem(hMetaDC,CurItem);
else PrintItem(hFrDC,CurItem);
PageAdvanced=FALSE; // new page is dirtied now
}
// Update printed page height and horizontal column position
if (CurSec==SEC_DETAIL1) {
CurCol++;
if (CurCol>=section[CurSec].columns) {
if (SFLAG_TRIM_AFTER&(section[CurSec].flags)) CurHeight=LastY;
else CurHeight+=section[CurSec].height;
if (CurHeight<LastY) CurHeight=LastY;
CurCol=0;
if (section[CurSec].columns==1 && SFLAG_PAGE_AFT&(section[CurSec].flags)) CurHeight=PrintHeight+1; // force page break for the next section
}
}
else {
if (SFLAG_TRIM_AFTER&(section[CurSec].flags)) CurHeight=LastY;
else CurHeight+=section[CurSec].height;
if (CurHeight<LastY) CurHeight=LastY;
if (SFLAG_PAGE_AFT&(section[CurSec].flags)) AdvancePage(MAX_SECTIONS);
CurCol=0; // other sections are single column
}
return TRUE;
}
/*****************************************************************************
PrintItem:
Print the specified item at the specified device context. The item is
printed relative to the current Y position
*****************************************************************************/
PrintItem(HDC hDC,int CurItem)
{
RECT rect;
HPEN hPen;
HBRUSH hBrush;
// build the rectangle
rect.left=item[CurItem].x+CurX;
rect.right=item[CurItem].x+CurX+item[CurItem].width;
rect.top=CurHeight+item[CurItem].y+item[CurItem].HeightAdj;
rect.bottom=rect.top+item[CurItem].height;
// fill rectangle if needed
if (item[CurItem].flags&OFLAG_FILL) { // fill rectangle
if (NULL!=(hBrush=CreateBrushIndirect(&(item[CurItem].brush)))) {
FillRect(hDC,&rect,hBrush);
DeleteObject(hBrush); // delete the temporary brush
}
}
// draw the bounding rectangle
if (item[CurItem].OutlineSelect) {// draw rectangle
if (NULL!=(hPen=CreatePen(item[CurItem].OutlineStyle,item[CurItem].OutlineWidth,item[CurItem].OutlineColor))) {
SelectObject(hDC,hPen);
FrDrawOutline(hDC,&rect,item[CurItem].OutlineSelect);
SelectObject(hDC,GetStockObject(BLACK_PEN));
DeleteObject(hPen); // delete the temporary pen
}
}
// draw the item interior
if (item[CurItem].type==LABEL) PrintLabel(hDC,CurItem);
else if (item[CurItem].type==FIELD) PrintField(hDC,CurItem);
else if (item[CurItem].type==LINE) PrintLine(hDC,CurItem);
else if (item[CurItem].type==PICT) PrintPicture(hDC,CurItem);
return TRUE;
}
/******************************************************************************
PrintLabel:
Print a label to the specified device context
*******************************************************************************/
int PrintLabel(HDC hDC, int CurItem)
{
RECT rect;
int LabelWidth,LabelHeight,LabelLen,x,y,flags,font;
// build the bounding rectangle
rect.left=item[CurItem].x+CurX;
rect.right=item[CurItem].x+CurX+item[CurItem].width;
rect.top=item[CurItem].y+CurHeight+item[CurItem].HeightAdj;
rect.bottom=rect.top+item[CurItem].height;
// Get label dimension
font=item[CurItem].font;
LabelWidth=GetLabelLen(item[CurItem].label,font);
LabelHeight=FrFont[font].height;
LabelLen=lstrlen(item[CurItem].label);
// Get the label position
flags=item[CurItem].flags;
if (flags&OFLAG_HLEFT) x=rect.left+DESC_MARGIN;
else if (flags&OFLAG_HRIGHT) x=rect.left+(item[CurItem].width-LabelWidth)-DESC_MARGIN;
else {
x=rect.left+(item[CurItem].width-LabelWidth)/2; // center
if (x<(rect.left+DESC_MARGIN)) x=rect.left+DESC_MARGIN;
}
if (flags&OFLAG_VTOP) y=rect.top;
else if (flags&OFLAG_VBOTTOM)y=rect.top+(item[CurItem].height-LabelHeight);
else y=rect.top+(item[CurItem].height-LabelHeight)/2; // center
// Draw the label
SetFont(hDC,(BYTE)font);
SetTextColor(hDC,item[CurItem].TextColor);
SetBkMode(hDC,TRANSPARENT);
if (LabelLen>0) TextOut(hDC,x,y,item[CurItem].label,LabelLen);
// update the last Y position
if (CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj>LastY)
LastY=CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj;
return TRUE;
}
/******************************************************************************
PrintField:
Format and print the current field
*******************************************************************************/
PrintField(HDC hDC, int CurItem)
{
RECT rect;
int i,j,x,y,count,CurField,LabelLen,LabelWidth,LabelHeight,font,flags,
SuffixWidth,PosSuffixLen,NegSuffixLen;
LPSTR ptr;
char string[NAME_WIDTH+1];
CurField=item[CurItem].field; // field associated with the item
font=item[CurItem].font;
// build the bounding rectangle
rect.left=item[CurItem].x+CurX;
rect.right=item[CurItem].x+CurX+item[CurItem].width;
rect.top=item[CurItem].y+CurHeight+item[CurItem].HeightAdj;
rect.bottom=rect.top+item[CurItem].height;
// print picture type field
if (field[CurField].type==TYPE_PICT) {
if (RepArg.DrawPicture) (RepArg.DrawPicture)(hDC,(int)field[CurField].NumData,field[CurField].FileId,field[CurField].FieldId,&rect);
return TRUE;
}
// print word wrapped field
if (field[CurField].type==TYPE_TEXT
&& field[CurField].flags&(FLAG_WRAP|FLAG_WORD_WRAP)) return PrintWrapField(hDC,CurItem);
// get the formatted data
FormatFieldData(&field[CurField],item[CurItem].label);
if (field[CurField].type==TYPE_TEXT) {
ptr=field[CurField].CharData; // pointer to the formatted data
TruncateText(ptr,item[CurItem].width,font); // truncate text to fit within the label
}
else ptr=item[CurItem].label;
LabelLen=lstrlen(ptr);
// special numeric field format processing
if (field[CurField].type==TYPE_NUM || field[CurField].type==TYPE_DBL) {
// check negative sign suffix
SuffixWidth=0;
NegSuffixLen=lstrlen(field[CurField].NegSignSuffix);
if (NegSuffixLen>0 && LabelLen>NegSuffixLen
&& lstrstr(&ptr[LabelLen-NegSuffixLen],field[CurField].NegSignSuffix)!=NULL)
SuffixWidth=GetLabelLen(field[CurField].NegSignSuffix,font);
// check positive sign suffix
PosSuffixLen=lstrlen(field[CurField].PosSignSuffix);
if (SuffixWidth==0 && PosSuffixLen>0 && LabelLen>PosSuffixLen
&& lstrstr(&ptr[LabelLen-PosSuffixLen],field[CurField].PosSignSuffix)!=NULL)
SuffixWidth=GetLabelLen(field[CurField].PosSignSuffix,font);
// process 'pad with zero' flag
if (field[CurField].flags&FLAG_PAD_ZERO) {
count=(item[CurItem].width-GetLabelLen(ptr,font)+SuffixWidth)/GetLabelLen("0",font); // number of zeros to insert
if (count>0) {
for (i=j=0;i<LabelLen;i++,j++) {
// look for first numeric character
if (i==j && (ptr[i]=='.' || ptr[i]==',' || (ptr[i]>='0' && ptr[i]<='9'))) { // first numeric character found
while (count>0) {
string[j]='0';
j++;
count--;
}
}
string[j]=ptr[i];
}
string[j]=0;
lstrcpy(ptr,string); // new string
LabelLen=lstrlen(ptr); // new label length
}
}
}
else SuffixWidth=0;
// Get field dimension
LabelWidth=GetLabelLen(ptr,font)-SuffixWidth;
LabelHeight=FrFont[font].height;
// Get the label position
flags=item[CurItem].flags;
if (flags&OFLAG_HLEFT) x=rect.left+DESC_MARGIN;
else if (flags&OFLAG_HRIGHT) x=rect.left+(item[CurItem].width-LabelWidth)-DESC_MARGIN;
else {
x=rect.left+(item[CurItem].width-LabelWidth)/2; // center
if (x<(rect.left+DESC_MARGIN) ) x=rect.left+DESC_MARGIN;
}
if (flags&OFLAG_VTOP) y=rect.top;
else if (flags&OFLAG_VBOTTOM)y=rect.top+(item[CurItem].height-LabelHeight);
else y=rect.top+(item[CurItem].height-LabelHeight)/2; // center
// Draw the label
SetFont(hDC,(BYTE)font);
SetTextColor(hDC,item[CurItem].TextColor);
SetBkMode(hDC,TRANSPARENT);
if (LabelLen>0) TextOut(hDC,x,y,ptr,LabelLen);
// update the last Y position
if (CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj>LastY)
LastY=CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj;
return TRUE;
}
/******************************************************************************
PrintWrapField:
Format and print a word/wrapped field
*******************************************************************************/
PrintWrapField(HDC hDC, int CurItem)
{
RECT rect;
int x,y,FirstChar,LastChar,CurField,LabelLen,i,LastItem,CurSec,
LabelWidth,LabelHeight,font,flags,FieldHeight,DistanceY;
char string[LINE_WIDTH+1];
BOOL FlexibleSize,paged=FALSE;
CurField=item[CurItem].field; // field associated with the item
FlexibleSize=field[CurField].flags&FLAG_FLEX_SIZE;
font=item[CurItem].font;
CurSec=item[CurItem].section;
LastItem=section[CurSec].FirstItem+section[CurSec].ItemCount-1; // Last item in the section
// build the bounding rectangle
rect.left=item[CurItem].x+CurX;
rect.right=item[CurItem].x+CurX+item[CurItem].width;
rect.top=item[CurItem].y+CurHeight+item[CurItem].HeightAdj;
rect.bottom=rect.top+item[CurItem].height;
// get the formatted data
FormatFieldData(&field[CurField],item[CurItem].label);
// extract lines and print
FirstChar=0;
y=rect.top;
SetFont(hDC,(BYTE)font);
SetTextColor(hDC,item[CurItem].TextColor);
SetBkMode(hDC,TRANSPARENT);
while ((LastChar=ExtractLine(CurItem,string,FirstChar))!=-1) {
StrTrim(string); // terminate space
LabelWidth=GetLabelLen(string,font);
LabelHeight=FrFont[font].height;
LabelLen=lstrlen(string);
// Get the label position
flags=item[CurItem].flags;
if (flags&OFLAG_HLEFT) x=rect.left+DESC_MARGIN;
else if (flags&OFLAG_HRIGHT) x=rect.left+(item[CurItem].width-LabelWidth)-DESC_MARGIN;
else x=rect.left+(item[CurItem].width-LabelWidth)/2; // center
// Draw the text field
if (LabelLen>0) TextOut(hDC,x,y,string,LabelLen);
y+=LabelHeight;
FirstChar=LastChar+1; // position for the next line
// break if wrap rectangle is finished
if ((y+LabelHeight>rect.bottom) && !FlexibleSize) break; // next line can't fit in the item rectangle
// break if current page is finished
if ((y+LabelHeight>PrintHeight)) {
if (CurSec!=SEC_DETAIL1) break;
// last break field is allowed to continue to the next page
PageAdvanced=FALSE; // allow page advance now
AdvancePage(CurSec); // advance page
y=rect.top=CurHeight;
SetFont(hDC,(BYTE)font); // set fonts again
SetTextColor(hDC,item[CurItem].TextColor);
SetBkMode(hDC,TRANSPARENT);
rect.bottom=rect.top+PrintHeight; // allow full page
paged=TRUE; // note the page advancement
}
}
// check if Y adjustment for remaining field is needed
FieldHeight=y-rect.top;
if (FlexibleSize && FieldHeight!=item[CurItem].height) {
for (i=CurItem+1;i<=LastItem;i++) {
if (item[i].type==SECTION || item[i].type==GROUP) continue;
if (item[i].section!=CurSec) continue;
if (item[i].y>item[CurItem].y+item[CurItem].height-DESC_MARGIN) {
if (paged) {
DistanceY=item[i].y-(item[CurItem].y+item[CurItem].height); // distance between this item and end of the wrapped current item
item[i].HeightAdj=-item[i].y+FieldHeight+DistanceY;
}
else item[i].HeightAdj=item[i].HeightAdj+FieldHeight-item[CurItem].height;
}
}
}
// update the last Y position
if (y>LastY) LastY=y;
return TRUE;
}
/******************************************************************************
ExtractLine:
This routine extract a line that can fit within the specified rectangle
width. The extract line is returned using the second argument. The third
argument tells the beginning position within the source string to start
using.
The routine returns the position of the last character within the source
string.
*******************************************************************************/
ExtractLine(int CurItem,LPSTR string,int FirstChar)
{
int i,j,k,font,CurField,DataLen,len,LineWidth;
int LastWordSrcIndex,LastWordDstIndex;
BOOL WordWrap;
LPSTR ptr;
char ParaChar,CurChar;
int far *CharWidth;
// initialize variables
font=item[CurItem].font; // font to print the field
CharWidth=FrFont[font].CharWidth; // character width table
CurField=item[CurItem].field; // current field
ptr=field[CurField].CharData; // field text data pointer
DataLen=lstrlen(ptr); // text data length
ParaChar=field[CurField].ParaChar[0]; // paragraph break character
if (field[CurField].flags&FLAG_WORD_WRAP) WordWrap=TRUE; // Word wrap
else WordWrap=FALSE; // character wrap
if (FirstChar>=(DataLen-1)) return -1; // no more characters left
// build new string
LineWidth=0; // unit width of the string
j=0; // number of characters in the string
i=FirstChar;
LastWordSrcIndex=-1; // index of the last complete word in the source string
LastWordDstIndex=-1; // index of the last complete word in the destination string
while (TRUE) {
if (i==DataLen) break; // all characters processed
if (j>=LINE_WIDTH) break; // end of buffer
CurChar=ptr[i];
if (CurChar==ParaChar) { // paragraph break
string[j]=0; // terminate the string
return i; // return the last character index
}
// translate characters // cr/lf translation
if (CurChar==0xA || CurChar==0xD) {
if (j>0 && string[j-1]==' ') { // ignore
i++;
continue;
}
else CurChar=' '; // convert to spaces
}
else if (CurChar==0x9) { // translate tab
for (k=0;k<TAB_CHAR_LEN-1;k++) { // expand to multiple spaces
CurChar=' ';
string[j]=CurChar;
LineWidth+=CharWidth[(BYTE)CurChar];
j++;
if (j>=LINE_WIDTH || LineWidth>=item[CurItem].width) {
j--;
i--;
break;
}
}
}
// process a regular character
string[j]=CurChar;
LineWidth+=CharWidth[(BYTE)CurChar];
j++;
if (j>=LINE_WIDTH || LineWidth>=item[CurItem].width) {
j--;
i--;
break;
}
i++; // increment the source index
// mark the last complete word
if (CurChar==' ') {
LastWordSrcIndex=i-1; // index of the last word in the source string
LastWordDstIndex=j-1;
}
}
// cutoff at word boundary
if (WordWrap && LastWordSrcIndex>0 && LineWidth>=item[CurItem].width) {
i=LastWordSrcIndex;
j=LastWordDstIndex;
}
len=j;
string[len]=0; // terminate the string
return i; // last character processed
}
/******************************************************************************
PrintLine:
Print a 'line' type item
*******************************************************************************/
PrintLine(HDC hDC, int CurItem)
{
int x1,y1,x2,y2;
HPEN hPen,hOldPen;
// build the line beginning and ending coordinates
if (item[CurItem].LineAngle==ANGLE_HORZ) { // horizontal line
x1=item[CurItem].x+CurX;
y1=CurHeight+item[CurItem].y+item[CurItem].HeightAdj+item[CurItem].height/2;
x2=x1+item[CurItem].width;
y2=y1;
}
else if (item[CurItem].LineAngle==ANGLE_VERT) { // vertical line
x1=item[CurItem].x+CurX+item[CurItem].width/2;
y1=CurHeight+item[CurItem].y+item[CurItem].HeightAdj;
x2=x1;
y2=y1+item[CurItem].height;
}
else if (item[CurItem].LineAngle==ANGLE_FDIAG) { // diagonal line
x1=item[CurItem].x+CurX;
y1=CurHeight+item[CurItem].y+item[CurItem].HeightAdj;
x2=x1+item[CurItem].width;
y2=y1+item[CurItem].height;
}
else { // backword diagonal line
x1=item[CurItem].x+CurX;
y1=CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj;
x2=x1+item[CurItem].width;
y2=CurHeight+item[CurItem].y;
}
// create the line pen
if (NULL!=(hPen=CreatePen(item[CurItem].LineStyle,item[CurItem].LineWidth,item[CurItem].LineColor))) {
hOldPen=SelectObject(hDC,hPen);
// draw the line
MoveToEx(hDC,x1,y1,NULL);
LineTo(hDC,x2,y2);
SelectObject(hDC,hOldPen);
DeleteObject(hPen); // delete the temporary pen
}
// update the last Y position
if (CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj>LastY)
LastY=CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj;
return TRUE;
}
/******************************************************************************
PrintPicture:
Draw a picture bitmap
*******************************************************************************/
PrintPicture(HDC hDC, int CurItem)
{
int pict;
LPBITMAPINFO pInfo;
LPSTR pImage;
pict=item[CurItem].font; // index into the font structure
// print a device independent bitmap
if (NULL!=(pImage=GlobalLock(FrFont[pict].hImage))
&& NULL!=(pInfo=(LPBITMAPINFO)GlobalLock(FrFont[pict].hInfo)) ) {
StretchDIBits(hDC,item[CurItem].x+CurX,CurHeight+item[CurItem].y+item[CurItem].HeightAdj,item[CurItem].width,item[CurItem].height,
0,0,(int)pInfo->bmiHeader.biWidth,(int)pInfo->bmiHeader.biHeight,pImage,pInfo,DIB_RGB_COLORS,SRCCOPY);
GlobalUnlock(FrFont[pict].hImage);
GlobalUnlock(FrFont[pict].hInfo);
}
// update the last Y position
if (CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj>LastY)
LastY=CurHeight+item[CurItem].y+item[CurItem].height+item[CurItem].HeightAdj;
return TRUE;
}
/******************************************************************************
FormatFieldData:
This routine format the specified field to the specified width. It
applies all applicable format to this field and returns the formatted
string.
******************************************************************************/
FormatFieldData(struct StrField huge *CurField,char far *string)
{
int i,j,type,SumType,len,negative,DecPlaces,digits,DecFound,temp,
ZeroValue,LeftSignLen,RightSignLen,CurrencySymLen;
char line[LINE_WIDTH+2],mm[3],dd[3],yy[5];
unsigned flags;
long NumData;
double DblData;
type=CurField->type;
SumType=CurField->SumType;
flags=CurField->flags;
DecPlaces=CurField->DecPlaces;
NumData=0;
DblData=0;
if (SumType==SUM_NONE) {
if (type==TYPE_DBL) DblData=CurField->DblData;
else NumData=CurField->NumData;
}
else if (SumType==SUM_COUNT) {
if (type==TYPE_DBL) DblData=CurField->count;
else NumData=CurField->count;
CurField->count=0;
}
else if (SumType==SUM_AVERAGE) {
if (type==TYPE_DBL) DblData=CurField->HoldDbl;
else NumData=CurField->HoldNum;
if (CurField->count>0) {
if (type==TYPE_DBL) DblData/=(double)CurField->count;
else NumData/=(long)CurField->count;
}
CurField->count=0;
CurField->HoldDbl=0;
CurField->HoldNum=0;
}
else {
if (type==TYPE_DBL) DblData=CurField->HoldDbl;
else NumData=CurField->HoldNum;
CurField->HoldDbl=0;
CurField->HoldNum=0;
}
//*************** Format Alpha Fields **********************************
if (type==TYPE_TEXT) {
string=CurField->CharData;
len=strlen(string);
if (flags&FLAG_CAPS) strupr(string);
else if (flags&FLAG_SMALL) strlwr(string);
else if (flags&FLAG_FIRST_CAP) {
strlwr(string);
for (i=0;i<len;i++) {
if (i==0 || string[i-1]==' ') string[i]=toupper((string[i]));
}
}
if (flags&FLAG_TRIM) rTrim(string);
}
//**************** Format numeric fields ********************************
else if (type==TYPE_NUM || type==TYPE_DBL) {
negative=ZeroValue=FALSE;
if (type==TYPE_NUM) {
if (NumData<0) {
negative=TRUE;
NumData=-NumData;
}
if (NumData==0) ZeroValue=TRUE;
ltoa(NumData,string,10);
if (DecPlaces>0) { // insert a decimal
len=strlen(string);
if (DecPlaces>len) {
lPad(string,DecPlaces+1);
string[0]='.';
i=1;
while (string[i]==' ') {
string[i]='0';
i++;
}
}
else {
lPad(&string[len-DecPlaces],DecPlaces+1);
string[len-DecPlaces]='.';
}
}
}
else { // if type is equal to doubld
if (DblData<0) {
negative=TRUE;
DblData=-DblData;
}
if (DblData==0) ZeroValue=TRUE;
DoubleToStr(DblData,DecPlaces,string);
}
//********************* insert comma characters *******************
if (flags&FLAG_COMMA) { // insert comma
len=strlen(string);
for (digits=0;digits<len;digits++) if (string[digits]=='.') break;
if (digits>0) {
strcpy(line,string);
j=0;
DecFound=FALSE;
for (i=0;i<len;i++,j++) {
if (DecFound) { // simply copy the remaining digits
string[j]=line[i];
}
else { // before decimal
if (line[i]=='.') {
string[j]=line[i];
DecFound=TRUE;
}
else { // do we need to insert comma
temp=digits/3;
if (digits==temp*3 && digits>0 && j>0) {// insert comma
string[j]=',';
j++;
}
string[j]=line[i];
digits--;
}
}
}
string[j]=0;
}
}
//******************* apply numeric attributes *******************************
len=strlen(string);
LeftSignLen=lstrlen(CurField->NegSignPrefix);
if (lstrlen(CurField->PosSignPrefix)>LeftSignLen) LeftSignLen=lstrlen(CurField->PosSignPrefix);
RightSignLen=lstrlen(CurField->NegSignSuffix);
if (lstrlen(CurField->PosSignSuffix)>RightSignLen) RightSignLen=lstrlen(CurField->PosSignSuffix);
CurrencySymLen=lstrlen(CurField->CurrencySymbol);
//******************* insert the currency symbol ********************
if (CurrencySymLen>0) {
lPad(string,len+CurrencySymLen);
for (i=0;i<CurrencySymLen;i++) string[i]=CurField->CurrencySymbol[i];
len+=CurrencySymLen;
}
//******************* insert the left prefix symbol ********************
if (LeftSignLen>0) {
lPad(string,len+LeftSignLen);
if (negative) {
for (i=0;i<lstrlen(CurField->NegSignPrefix);i++) string[i]=CurField->NegSignPrefix[i];
}
else {
for (i=0;i<lstrlen(CurField->PosSignPrefix);i++) string[i]=CurField->PosSignPrefix[i];
}
len+=LeftSignLen;
}
//******************* insert the right suffiex symbol ********************
if (RightSignLen>0) {
rPad(string,len+RightSignLen);
if (negative) {
for (i=0;i<lstrlen(CurField->NegSignSuffix);i++) string[len+i]=CurField->NegSignSuffix[i];
}
else {
for (i=0;i<lstrlen(CurField->PosSignSuffix);i++) string[len+i]=CurField->PosSignSuffix[i];
}
len+=RightSignLen;
rTrim(string);
}
//******************** length check *********************************
if (flags&FLAG_SUP_ZERO && ZeroValue) string[0]=0;
}
//**************** Format date fields ***********************************
else if (type==TYPE_DATE) {
if (NumData<991231L) NumData=19000000L+NumData;
ltoa(NumData,line,10);
strcpy(dd,&line[6]);
line[6]=0;
strcpy(mm,&line[4]);
line[4]=0;
strcpy(yy,line);
string[0]=0;
switch (CurField->DateFormat) {
case DT_MMDDYY:
strcat(string,mm);
lstrcat(string,CurField->DateDelim);
strcat(string,dd);
lstrcat(string,CurField->DateDelim);
strcat(string,&yy[2]);
break;
case DT_DDMMYY:
strcat(string,dd);
lstrcat(string,CurField->DateDelim);
strcat(string,mm);
lstrcat(string,CurField->DateDelim);
strcat(string,&yy[2]);
break;
case DT_MMDDYYYY:
strcat(string,mm);
lstrcat(string,CurField->DateDelim);
strcat(string,dd);
lstrcat(string,CurField->DateDelim);
strcat(string,yy);
break;
case DT_MMMDDYYYY:
temp=atoi(mm);
if (temp<1) temp=1;
if (temp>12) temp=12;
strcat(string,MonthName[temp-1]);
strcat(string," ");
if (dd[0]=='0') strcat(string,&dd[1]);
else strcat(string,dd);
strcat(string,", ");
strcat(string,yy);
break;
default:
;
}
}
//**************** Format the logical fields *****************************
else if (type==TYPE_LOGICAL) {
if (NumData) string[0]=CurField->LogicalSymbols[0];
else string[0]=CurField->LogicalSymbols[1];
string[1]=0;
}
return TRUE;
}
/*****************************************************************************
AcceptDlgField:
Accept the values for the dialog fields from the user. The fields are
accept as specified by the PromptOrder variable.
*****************************************************************************/
AcceptDlgField()
{
int fld,idx,FieldTable[MAX_DLGS],ord,TotalDlgFields,FieldFlag;
int result;
char string[NAME_WIDTH+2];
// sort the fields in the prompt order
TotalDlgFields=0;
for (ord=0;ord<MAX_DLGS;ord++) {
for (fld=0;fld<MAX_DLGS;fld++) {
if (DlgField[fld].InUse && DlgField[fld].PromptOrder==ord) {
FieldTable[TotalDlgFields]=fld;
TotalDlgFields++;
}
}
}
if (TotalDlgFields==0) return TRUE; // dialog fields not used
idx=0;
while(TRUE) { // accept/validate each field
if (idx>=TotalDlgFields) break;
fld=FieldTable[idx];
ACCEPT_DATA:
DlgIndex=fld; // pass information to the dialog box
FieldFlag=idx;
if (idx==(TotalDlgFields-1)) FieldFlag=MAX_DLGS;
result=CallDialogBox("DlgInputParam",DlgInputParam,(DWORD)FieldFlag);
if (!result) {
if (idx<=0) return FALSE;
idx--;
continue;
}
//***** convert and validate *****************
if (DlgField[fld].type==TYPE_NUM) DlgField[fld].NumData=atol(DlgField[fld].CharData);
else if (DlgField[fld].type==TYPE_DBL) DlgField[fld].DblData=atof(DlgField[fld].CharData);
else if (DlgField[fld].type==TYPE_LOGICAL) {
strupr(DlgField[fld].CharData);
StrTrim(DlgField[fld].CharData);
if (strstr("YES,TRUE,Y,1",DlgField[fld].CharData)) DlgField[fld].NumData=1;
else if (strstr("NO,FALSE,N,0",DlgField[fld].CharData)) DlgField[fld].NumData=0;
else {
MessageBox(hFrWnd,"Valid entries: YES,NO,TRUE,FALSE,Y,N,1,0",NULL,MB_OK);
goto ACCEPT_DATA;
}
}
else if (DlgField[fld].type==TYPE_DATE) {
if (DlgField[fld].CharData[0]!='\"') { // enclose in quotes
strcpy(string,"\"");
strcat(string,DlgField[fld].CharData);
strcat(string,"\"");
}
else strcpy(string,DlgField[fld].CharData);
if (!ValidateDate(string,&(DlgField[fld].NumData)) || DlgField[fld].NumData==-1) {
MessageBox(hFrWnd,"Invalid Date Format/Value!",NULL,MB_OK);
goto ACCEPT_DATA;
}
}
idx++;
}
return TRUE;
}
/*****************************************************************************
AllocRepMem:
Allocate memory for:
This routine adjusts the memory blocks allocated by the AllocFormMem
routine and allocates these new objects:
1. Sort Fields
*****************************************************************************/
AllocRepMem()
{
int i;
int FieldIndex,fld;
if (UseScreen) {
if ( (NULL==(hPageLoc=GlobalAlloc(GMEM_MOVEABLE,(long)(MAX_SCR_PAGES+1)*sizeof(long))))
|| (NULL==(PageLoc=(long far *)GlobalLock(hPageLoc))) ) {
AbortFr("Ran Out of Memory (AllocRepMem)",ERR_NO_MEM);
}
FileBuf=OurAlloc(BUF_SIZE); // allocate file buffer
}
//**** allocate other object arrays *************************************
if ( (NULL==(hUserField=GlobalAlloc(GMEM_MOVEABLE,(long)(TotalFields+1)*sizeof(struct StrField))))
|| (NULL==(UserField=(struct StrField huge *)GlobalLock(hUserField)))
|| (NULL==(hSortField=GlobalAlloc(GMEM_MOVEABLE,(long)(TotalBreakFields+1)*sizeof(struct StrField))))
|| (NULL==(SortField=(struct StrField huge *)GlobalLock(hSortField))) ){
AbortFr("Ran Out of Memory (AllocRepMem(1))",ERR_NO_MEM);
}
//***** shrink the field array ******************************************
GlobalUnlock(hField);
if ( (NULL==(hField=GlobalReAlloc(hField,(long)(TotalFields+1)*sizeof(struct StrField),0)))
|| (NULL==(field=(struct StrField huge *)GlobalLock(hField))) ){
AbortFr("Ran Out of Memory (AllocRepMem(2))",ERR_NO_MEM);
}
for(fld=0;fld<TotalFields;fld++) { // allocate space for the character fields
UserField[fld].type=field[fld].type;
if (field[fld].type==TYPE_TEXT) {
//***** update the width for the dialog fields **********
if (field[fld].source==SRC_DLG) field[fld].width=DlgField[field[fld].SysIdx].width;
if (NULL==(field[fld].CharData=OurAlloc(field[fld].width+2))
|| NULL==(UserField[fld].CharData=OurAlloc(field[fld].width+2)) ) {
AbortFr("Ran Out of Memory(2)",ERR_NO_MEM);
}
}
}
for(i=0;i<TotalBreakFields;i++) { // allocate space for the character sort fields
FieldIndex=BreakField[i].SortField; // index into the field table
SortField[i].type=field[FieldIndex].type;
if (field[FieldIndex].type==TYPE_TEXT) {
if (NULL==(SortField[i].CharData=OurAlloc(field[FieldIndex].width+2))) {
AbortFr("Ran Out of Memory(3)",ERR_NO_MEM);
}
}
}
return TRUE;
}
/******************************************************************************
StuffSysField:
Build data for the system fields
*******************************************************************************/
StuffSysField(struct StrField huge *field)
{
switch (field->SysIdx) {
case SYS_PAGE:
field->NumData=PageCount;
if (CurHeight>=PrintHeight) (field->NumData)++;
break;
case SYS_DATE:
field->NumData=SystemDate;
break;
case SYS_TIME:
lstrcpy(field->CharData,SystemTime);
break;
case SYS_REC_COUNT:
field->NumData=RecCount+1;
break;
case SYS_PARA_BREAK:
field->CharData[0]=DEF_PARA_BREAK;
field->CharData[1]=0;
break;
default:
;
}
return TRUE;
}