home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
tolkit45.zip
/
os2tk45
/
samples
/
os2
/
sort
/
sort.c
next >
Wrap
C/C++ Source or Header
|
1999-05-11
|
57KB
|
1,542 lines
/*=========================================================================*\
* *
* SORT.C - Multi-threaded PM sample. *
* *
* *
* (C) Copyright IBM Corporation 1992. *
* *
* DISCLAIMER OF WARRANTIES. The following [enclosed] code is *
* sample code created by IBM Corporation. This sample code is not *
* part of any standard or IBM product and is provided to you solely *
* for the purpose of assisting you in the development of your *
* applications. The code is provided "AS IS", without *
* warranty of any kind. IBM shall not be liable for any damages *
* arising out of your use of the sample code, even if they have *
* been advised of the possibility of such damages. *
*-------------------------------------------------------------------------*
*
* This program demonstrates the use of many threads by doing
* LISTCNT simultaneous sorts. Each sorting algorithm runs
* from a separate thread, the routine which updates the display
* is run from another thread, and the main thread is used to
* handle the main window's messages. The display thread is
* started when the program begins and is not terminated (allows
* default cleanup to terminate thread) as the display routine
* is used throughout the program's life.
* This code was written to allow easy modification. To change
* the number of simultaneous sorts, change the LISTCNT #define
* and modify the global arrays which control the screen
* drawing color, the sort each thread is to use, and the sort name.
* Note: This program was not intended to infer the relative
* speeds of the various sorting algorithms.
*
*---------------------------------------------------------------
*
* Procedures in this file:
* main() Sets up the PM environment and calls
* the main dialog procedure ClientWndProc
* ClientWndProc() Handles the main window messages
* CalcThread() Generic stub that sets up, executes, and
* terminates each sort in an aux. thread
* DispThread() Updates the display during the sorts
* BubbleSort() Implements a bubble sort
* InsertionSort() Implements an insertion sort
* BatcherSort() Stub that calls recursive Batcher sort
* BatcherSortR() Implements a Batcher sort
* QuickSort() Stub that calls recursive Quick sort
* QuickSortR() Implements a Quick sort
* EnableMenuItem() Activates/deactivates a menu choice
* EntryFldDlgProc() Handles the set number of disks dialog box
* RandomizeData() Randomizes the data arrays for the sorts
* FixSysMenu() Remove Restore, Size, Min, & Max from system menu
*
\*==============================================================*/
/*--------------------------------------------------------------*\
* Include files, macros, defined constants, and externs *
\*--------------------------------------------------------------*/
#define INCL_WIN
#define INCL_WINHEAP
#define INCL_HELP
#define INCL_WINDIALOGS
#define INCL_GPIPRIMITIVES
#define INCL_GPIBITMAPS
#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#include <os2.h>
#include <stdio.h>
#include <string.h>
#include <process.h>
#include <stdlib.h>
#include "sort.h"
#ifdef RAND_MAX
#undef RAND_MAX
#define RAND_MAX 32767
#endif
/*--------------------------------------------------------------*\
* Entry point declarations *
\*--------------------------------------------------------------*/
MRESULT EXPENTRY ClientWndProc (HWND, ULONG, MPARAM, MPARAM);
MRESULT EXPENTRY EntryFldDlgProc(HWND, ULONG, MPARAM, MPARAM);
MRESULT EXPENTRY AboutDlgProc(HWND, ULONG, MPARAM, MPARAM);
LONG MessageBox(HWND, LONG, LONG, BOOL);
VOID APIENTRY ExitProc(ULONG);
BOOL Init(VOID);
INT main(LONG ,CHAR **);
VOID _Optlink CalcThread(PVOID);
VOID _Optlink DispThread(PVOID);
VOID EnableMenuItem(HWND, LONG, BOOL);
VOID RandomizeData(ULONG);
VOID BubbleSort(PCALCPARAM);
VOID BatcherSort(PCALCPARAM);
VOID BatcherSortR(PCALCPARAM, ULONG, ULONG, ULONG, BOOL);
VOID QuickSort(PCALCPARAM);
VOID QuickSortR(PCALCPARAM, LONG, LONG);
VOID InsertionSort(PCALCPARAM);
VOID FixSysMenu(HWND);
VOID InitHelp(VOID);
VOID HelpHelpForHelp(MPARAM);
VOID HelpExtended(MPARAM);
VOID HelpKeys(MPARAM);
VOID HelpIndex(MPARAM);
VOID HelpAbout(MPARAM);
VOID DisplayHelpPanel(LONG);
VOID DestroyHelpInstance(VOID);
HEV hev;
RECTL rcl; /* Rectangle struct for painting */
/*--------------------------------------------------------------*\
* Global variables *
\*--------------------------------------------------------------*/
CHAR szClientClass[40];
USHORT Data[LISTCNT][MAX_ELEMS]; /* Array that contains the data to sort */
/* Global data that defines each of the sort routines */
/* Color of each of the LISTCNT data lists. */
ULONG ulColors[LISTCNT] = { CLR_RED,CLR_BLUE,CLR_DARKGREEN,CLR_CYAN };
/* List of sorts to be executed for each of the LISTCNT threads. */
VOID (*pExecSub[LISTCNT])(PCALCPARAM)={BubbleSort,BatcherSort,QuickSort,
InsertionSort};
/* Ascii names of sorts */
CHAR *szSubNames[LISTCNT]={"Bubble Sort",
"Batcher Sort",
"Quick Sort",
"Insertion Sort"};
HAB hab; /* Anchor block for the process */
HMQ hmq;
BOOL fHelpEnabled; /* flag to determine if help is enabled */
CHAR szUntitled[MESSAGELEN]; /* buffer for "Untitled" string */
HWND hwndFrame, hwndClient;
static CHAR szLibName[HELPLIBRARYNAMELEN];
static CHAR szWindowTitle[HELPLIBRARYNAMELEN];
static HWND hwndHelpInstance;
RECTL rectl;
/****************************************************************\
* Function name: main(LONG sArgc,CHAR **ppArgv)
*
* Parameters: NONE
*
* Returns: Always returns 0
*
* Purpose: Sets up the PM environment, calls the main window proc,
* handles the window's messages then cleans up and exits.
*
* Usage:
\****************************************************************/
INT main(LONG sArgc,CHAR **ppArgv)
{
QMSG qmsg;
CHAR *pszName = "SORT";
ULONG flFrameFlags = FCF_STANDARD;
strncpy(szClientClass,pszName,strlen(pszName) );
/* These PM calls should be error checked */
hab = WinInitialize(0);
hmq = WinCreateMsgQueue(hab, 0);
if(!Init())
{
MessageBox(HWND_DESKTOP,
IDMSG_INITFAILED,
MB_OK | MB_ERROR,
TRUE);
DosExit(EXIT_PROCESS,RETURN_ERROR);
}
hwndFrame = WinCreateStdWindow(HWND_DESKTOP,
WS_VISIBLE,
&flFrameFlags,
szClientClass,
NULL,
0L,
(HMODULE)0,
ID_RESOURCE,
&hwndClient);
if(hwndFrame == NULLHANDLE)
{
MessageBox(HWND_DESKTOP,
IDMSG_MAINWINCREATEFAILED,
MB_OK | MB_ERROR,
TRUE);
DosExit(EXIT_PROCESS,RETURN_ERROR);
}
InitHelp();
while(WinGetMsg(hab,&qmsg,0,0,0)) /* Message loop */
WinDispatchMsg(hab,&qmsg);
/* destroy the help instance */
DestroyHelpInstance();
DosExit(EXIT_PROCESS,RETURN_SUCCESS);
return 0L;
}
/****************************************************************\
* Initialization routine
*---------------------------------------------------------------
*
* Name: Init()
*
* Purpose: Performs initialization functions required before the main
* window can be created.
*
* Usage: Called once before the main window is created.
*
* Method: - installs the routine ExitProc into the DosExitList chain
* - registers all window classes
* - performs any command line processing
*
*
* Returns: TRUE - initialization is successful
* FALSE - initialization failed
\****************************************************************/
BOOL Init(VOID)
{
/* Add ExitProc to the exit list to handle the exit processing. If
* there is an error, then terminate the process since there have
* not been any resources allocated yet */
if(DosExitList(EXLST_ADD, ExitProc))
{
MessageBox(HWND_DESKTOP,
IDMSG_CANNOTLOADEXITLIST,
MB_OK | MB_ERROR,
TRUE);
DosExit(EXIT_PROCESS, RETURN_ERROR);
}
if(DosCreateEventSem(NULL,&hev,DC_SEM_SHARED,FALSE ) )
{
return(FALSE);
}
/* load application name from resource file */
if(!WinLoadString(hab, 0, IDS_APPNAME, MAXNAMEL, szClientClass))
return FALSE;
/* load "untitled" string */
if(!WinLoadString(hab, 0, IDS_UNTITLED, MESSAGELEN, szUntitled))
return FALSE;
/* register the main client window class */
if(!WinRegisterClass(hab,
(PSZ)szClientClass,
(PFNWP)ClientWndProc,
CS_SIZEREDRAW | CS_CLIPCHILDREN,
0))
{
return FALSE;
}
return( TRUE);
} /* Init() */
/****************************************************************\
* Exit list processing procedure
*--------------------------------------------------------------
*
* Name: ExitProc(usTermCode)
*
* Purpose: Cleans up certain resources when the application terminates
*
* Usage: Routine is called by DosExitList when the application exits
*
* Method: Global resources, such as the main window and message queue,
* are destroyed and any system resources used are freed.
*
* Returns: Returns EXLST_EXIT to the DosExitList handler
*
\****************************************************************/
VOID APIENTRY ExitProc(ULONG usTermCode)
{
/* destroy the main window if it exists */
if(WinIsWindow(hab, hwndFrame)) {
WinDestroyWindow(hwndFrame);
}
/*--------------------------------------------------*\
* Any other system resources used *
* (e.g. memory or files) should be freed here *
\*--------------------------------------------------*/
WinDestroyMsgQueue(hmq);
WinTerminate(hab);
DosExitList(EXLST_EXIT, 0L); /* termination complete */
return;
} /* ExitProc() */
/****************************************************************\
* Function name: ClientWndProc()
*
* Parameters: hwnd, msg, mp1, mp2. Standard PM Dialog Proc params.
* No user data is expected in the WM_CREATE.
*
* Returns: Returns with WM_QUIT message
*
* Purpose: Handles all the messages associated with the main window
* and calls the appropriate handling procedures.
*
* Usage : Called only by main()
\****************************************************************/
MRESULT EXPENTRY ClientWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
HPS hps=0; /* Handle for painting */
POINTL ptl; /* Point struct for painting */
static CALCPARAM cp[LISTCNT]; /* Struct passed to sort threads */
static TID tidCalc[LISTCNT]; /* Sort threads IDs */
static CALCPARAM cpDisp; /* Struct passed to disp thread */
static TID tidDisplay; /* Secondary display thread ID */
static USHORT usWindowYCoord=1; /* Holds current client window ht */
static BYTE cThreadCnt = 0; /* Count of sort threads running */
static USHORT cSetSize=MAX_ELEMS; /* User sort set size */
USHORT cnt,cnt2,usID; /* Utility counters */
ULONG ulBlip; /* Holds the marker pos for Paint */
MRESULT sRC;
switch(msg)
{
case WM_CREATE:
RandomizeData(cSetSize); /* Initially randomize data set */
/* Start display thread */
cpDisp.hwnd = hwnd;
cpDisp.Array = &usWindowYCoord;
cpDisp.pcThreadCnt = &cThreadCnt;
cpDisp.pcSetSize = &cSetSize;
if((tidDisplay = _beginthread(DispThread,
#if __IBMC__
NULL,
#endif
STACKSIZE,
(PVOID) &cpDisp)) == (USHORT)-1)
{
WinAlarm(HWND_DESKTOP, WA_ERROR); /* can't start display thread */
DosExit(EXIT_PROCESS,1);
}
/* Up the display priority an arbitrary amount to cause it to
update more rapidly and to give it a higher priority than
the sort threads.*/
DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, 5, tidDisplay);
return (MRESULT)0L;
case WM_SIZE:
WinInvalidateRect(hwnd,NULL,FALSE); /* Force a redraw */
sRC = WinDefWindowProc(hwnd, msg, mp1, mp2);
return sRC;
case WM_PAINT:
hps = WinBeginPaint(hwnd,0,0); /* Get paint handle */
WinQueryWindowRect(hwnd,&rcl);
if(NELEMS < MAX_ELEMS )
{
cSetSize = NELEMS;
}
else
{
cSetSize = MAX_ELEMS;
}
RandomizeData(cSetSize); /* Initially randomize data set */
usWindowYCoord = rcl.yTop;
/* Draw if screen */
/* is big enough */
if( (XOFFSET + (2 * COLUMNOFFSET))< (rcl.xRight-rcl.xLeft) &&
(YOFFSET * ROWCNT) < (rcl.yTop-rcl.yBottom ) )
{
DrawRect(rcl.xLeft,rcl.yBottom, /* White out the screen */
rcl.xRight,rcl.yTop,CLR_WHITE);
DrawLine(XOFFSET, YOFFSET, /* Draw baseline */
rcl.xRight,YOFFSET,CLR_BLACK);
DrawLine(XOFFSET, YOFFSET, /* Draw vertical line */
XOFFSET,rcl.yTop,CLR_BLACK);
for(cnt=0;cnt<LISTCNT;cnt++) /* Draw data points */
{
for(cnt2=0;cnt2<cSetSize;cnt2++)
{
ulBlip = (rcl.yTop-YOFFSET-5) * Data[cnt][cnt2] / RAND_MAX
+ YOFFSET+1;
Draw2Pel(XOFFSET+1 + cnt2, ulBlip, ulColors[cnt]);
}
}
for(cnt=0,cnt2= 0;cnt<COLUMNCNT;cnt++) /* Do bottom legend */
{
if(cnt2 >= ROWCNT )
{
cnt2 = 0;
}
ptl.x = XOFFSET + cnt2++ *COLUMNOFFSET;
/*
*next row after the last column
*/
if(cnt >= (COLUMNCNT / ROWCNT ) )
{
ptl.y = YOFFSET - ( 2 * ROWOFFSET);
}
else
{
ptl.y = YOFFSET - ROWOFFSET;
}
GpiSetColor(hps,ulColors[cnt]);
GpiCharStringAt(hps,&ptl,
(LONG) strlen(szSubNames[cnt]),
szSubNames[cnt]);
}
}
WinEndPaint(hps);
return (MRESULT)0L;
case WM_COMMAND:
switch(SHORT1FROMMP(mp1))
{
case IDM_START:
/*
*clear the drawing semaphore
*/
DosPostEventSem(hev);
/* Try to get stack space */
for(cnt=0;cnt<LISTCNT;cnt++)
{
cp[cnt].hwnd = hwnd; /* Set the static struct */
cp[cnt].fContinueCalc = TRUE;
cp[cnt].pFunc = pExecSub[cnt];
cp[cnt].usID = cnt;
cp[cnt].Array = Data[cnt];
cp[cnt].cArray = cSetSize;
/* Try to start the thread */
if( (tidCalc[cnt] = _beginthread(CalcThread,
#if __IBMC__
NULL,
#endif
STACKSIZE,
(PVOID)&cp[cnt])) == (USHORT)-1)
{
WinAlarm(HWND_DESKTOP, WA_ERROR);
return (MRESULT)0L;
}
if(cThreadCnt++ == 0) /* When the first thread starts */
{
/* Disable Start, Set, and Randomize, enable Stop */
EnableMenuItem(hwnd,IDM_START,FALSE);
EnableMenuItem(hwnd,IDM_SET,FALSE);
EnableMenuItem(hwnd,IDM_RANDOM,FALSE);
EnableMenuItem(hwnd,IDM_STOP,TRUE);
}
}
return (MRESULT)0L;
case IDM_STOP:
for(cnt=0;cnt<LISTCNT;cnt++)
cp[cnt].fContinueCalc = FALSE; /* Notify thread to quit */
return (MRESULT)0L;
case IDM_RANDOM:
RandomizeData(cSetSize); /* Randomize data */
WinInvalidateRect(hwnd,NULL,FALSE); /* Force a redraw */
return (MRESULT)0L;
case IDM_SET:
if(WinDlgBox(HWND_DESKTOP, hwnd, /* Pop up the query/set box */
EntryFldDlgProc,(HMODULE)0,IDD_SETCOUNT,
(VOID FAR *) &cSetSize))
{
WinInvalidateRect(hwnd,NULL,FALSE); /* Force a redraw */
}
return (MRESULT)0L;
case IDM_GENERALHELP:
HelpExtended(mp2);
return (MRESULT)0L;
case IDM_USINGHELP:
HelpHelpForHelp(mp2);
return (MRESULT)0L;
case IDM_TUTORIAL:
HelpKeys(mp2);
return (MRESULT)0L;
case IDM_HELPINDEX:
HelpIndex(mp2);
return (MRESULT)0L;
case IDM_HELPPRODUCTINFO:
HelpAbout(mp2);
return (MRESULT)0L;
default:
sRC = WinDefWindowProc(hwnd, msg, mp1, mp2);
return sRC;
}
break;
case IDM_DONE:
usID = SHORT1FROMMP(mp1); /* Get ID of quit thread */
if(--cThreadCnt == 0) /* If all quit, enable menus */
{
EnableMenuItem(hwnd,IDM_START,TRUE);
EnableMenuItem(hwnd,IDM_SET,TRUE);
EnableMenuItem(hwnd,IDM_RANDOM,TRUE);
EnableMenuItem(hwnd,IDM_STOP,FALSE);
}
return (MRESULT)0L;
case HM_QUERY_KEYS_HELP:
return ((MRESULT)PANEL_KEYSHELP);
case WM_CLOSE:
DosCloseEventSem(hev);
for(cnt=0;cnt<LISTCNT;cnt++)
{
DosKillThread(tidCalc[cnt]);
}
DosKillThread(tidDisplay);
WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
return 0L;
default:
sRC = WinDefWindowProc(hwnd, msg, mp1, mp2);
return sRC;
}
return (MRESULT)0L;
}
/****************************************************************\
* Function name: CalcThread()
*
* Parameters: pcp is a struct which contains the hwnd handle, the
* continue flag which is initially set to TRUE, the ID
* which is the
*
* Returns: VOID
*
* Purpose: This generic stub calls the passed "sort" function with a pointer
* to the data and an item count, then when the sort terminates, it
* cleans up by Posting a done message, then terminating the thread.
*
* Usage : No DosExitCritSec() is called since _endthread()
* clears the critical section when the thread is
* terminated.
*
\****************************************************************/
VOID CalcThread(PVOID pcp)
{
(*((PCALCPARAM)pcp)->pFunc)(pcp); /* Execute recurs routine */
/* Set Crit so the IDM_DONE isn't processed */
/* until this thread has completely terminated */
DosEnterCritSec();
WinPostMsg(((PCALCPARAM)pcp)->hwnd,IDM_DONE,
MPFROMSHORT(((PCALCPARAM)pcp)->usID),NULL);/* Post done */
/*
*set the post count for each thread
*that goes through
*/
DosPostEventSem(hev);
_endthread(); /* Terminate thread and exit crit sec */
return;
}
/****************************************************************\
* Function name: DispThread()
*
* Parameters: pcp is a struct which contains the hwnd handle, the
* count of active threads, the ->Array element points to
* the current height of the window which can be dynamically
* resized by the user, the pcSetSize points to the current
* set size which can be changed by the user only when the
* sort is stopped.
* None of the other pcp members are used.
*
* Returns: VOID
*
* Purpose: This routine is run as a secondary thread to update the screen
* when the sort threads are running. It works by making passes
* through the data lists and redrawing them. A DosSleep(0) is
* called at the end of each pass to help sychronize things a bit.
*
* Usage : Note that this thread is started when the program is
* initialized, and is never terminated. Note that
* fDoUpdate is used in such a way that the screen is
* ALWAYS updated once after all threads have terminated.
* This avoids the possibility of the display not being
* fully accurate when the sorts terminate.
*
\****************************************************************/
VOID DispThread(PVOID pvData )
{
USHORT cnt,cnt2; /* Utility counters */
HPS hps; /* Presentation space handle */
POINTL ptl; /* Used for various drawing macros */
ULONG ulBlip; /* Holds the Y offset for a given data point */
PCALCPARAM pcp; /* after all sort threads terminate */
USHORT *pusYCoord;
ULONG ulPostCount;
pcp = (PCALCPARAM) pvData;
pusYCoord = pcp->Array;
/* Points to location that always */
/* contains current client wind hgt */
hps = WinGetPS( pcp->hwnd);
while(TRUE)
{
/*
*sit and wait on the clearing of the semaphore
*/
DosWaitEventSem(hev,SEM_INDEFINITE_WAIT);
DosQueryEventSem(hev,&ulPostCount);
/*
*wait on all 4 threads + the post used to start
*to post
*/
if(ulPostCount == 5)
{
ulPostCount = 0;
DosResetEventSem(hev,&ulPostCount);
}
for(cnt=0;cnt<*((PCALCPARAM)pcp)->pcSetSize;cnt++)/* Update data set */
{
DrawLine(XOFFSET+1 + cnt,YOFFSET+1, /* Erase vertical column */
XOFFSET+1 + cnt,*pusYCoord, CLR_WHITE);
for(cnt2=0;cnt2<LISTCNT;cnt2++) /* Draw each point */
{
ulBlip = (ULONG) (*pusYCoord-YOFFSET-5)*Data[cnt2][cnt] / RAND_MAX
+ YOFFSET+1;
Draw2Pel(XOFFSET+1 + cnt, ulBlip, ulColors[cnt2]);
}
}
}
/* Note that these 3 lines NEVER get executed, but should the program be
modified to end the thread, this is the appropriate termination code. */
WinReleasePS(hps);
_endthread();
return;
}
/****************************************************************\
* Function name: BubbleSort()
*
* Parameters: pcp is a struct which contains the hwnd handle, a
* pointer to the data array, and a count of the items in
* the data array.
* None of the other pcp members are used.
*
* Returns: VOID
*
* Purpose: Implements a bubble sort which is an O(n^2) algorithm. It
* works by repeatedly going through the data and comparing
* consecutive elements and swapping them if they aren't in
* the correct order. This guarantees that each pass will
* place at least one additional item in its appropriate
* place.
*
* Usage:
\****************************************************************/
VOID BubbleSort(PCALCPARAM pcp)
{
BOOL fModified = FALSE; /* Set whenever a swap is done, if an entire */
/* pass doesn't set the flag, the we're done */
INT cnt;
INT cnt2; /* Counters used for the 2-level loops */
USHORT usTemp; /* Used to hold a data item during a swap */
for(cnt=(ULONG)(pcp->cArray-1);cnt>=0;cnt--) /*Set the max no. of passes*/
{
for(cnt2=0;cnt2<cnt;cnt2++) /* Only sort thru current cnt pass */
{
if(!pcp->fContinueCalc) /* User wishes to terminate the sort */
return;
if(pcp->Array[cnt2]>pcp->Array[cnt2+1]) /* Items need to swap */
{
fModified = TRUE;
usTemp = pcp->Array[cnt2];
pcp->Array[cnt2] = pcp->Array[cnt2+1];
pcp->Array[cnt2+1]= usTemp;
}
}
if(!fModified) /* Nothing changed during the entire pass */
break;
fModified = FALSE; /* Reset the modify flag */
}
return;
}
/****************************************************************\
* Function name: InsertionSort()
*
* Parameters: pcp is a struct which contains the hwnd handle, a
* pointer to the data array, and a count of the items in
* the data array.
* None of the other pcp members are used.
*
* Returns: VOID
*
* Purpose: Implements an insertion sort which is an O(n^2) algorithm.
* This sort works much faster and does not require that much
* additional code to implement. It works by setting a sorted
* list to be just the first element, the working each
* successive item into the already sorted list.
*
* Usage:
\****************************************************************/
VOID InsertionSort(PCALCPARAM pcp)
{
SHORT cnt,cnt2; /* Counters used for the 2-level loops */
USHORT usTemp; /* Used to hold a data item during a swap */
for(cnt=1;cnt<(LONG)pcp->cArray;cnt++) /* Insert each item in turn */
{
if(!pcp->fContinueCalc) /* User wishes to terminate the sort */
return;
usTemp=pcp->Array[cnt]; /* Hold value to insert */
cnt2=(LONG)(cnt-1);
while(pcp->Array[cnt2]>usTemp) /* Move items down to make room */
{
pcp->Array[cnt2+1]=pcp->Array[cnt2];
cnt2--;
if(cnt2<0)
break;
}
pcp->Array[cnt2+1] = usTemp; /* Insert the item */
}
return;
}
/****************************************************************\
* Function name: BatcherSort()
*
* Parameters: pcp is a struct which contains the continue flag,
* a pointer to the data array, and a count of the items in
* the data array.
* None of the other pcp members are used.
*
* Returns: VOID
*
* Purpose: This routine is a stub that calls the recursive Batcher sort
* with the proper initial arguments.
*
* Usage: It passes the pcp, the size of the array to be sorted,
* the offset to start sorting at(0), the number number
* of elements each item is from neighboring elements (1),
* and Half flag to sort the halves (1=YES).
\****************************************************************/
VOID BatcherSort(PCALCPARAM pcp)
{
BatcherSortR(pcp,pcp->cArray,0,1,1);
return;
}
/****************************************************************\
* Function name: BatcherSortR()
*
* Parameters: pcp is a struct which contains the continue flag,
* a pointer to the data array.
* None of the other pcp members are used.
* usArrSize is the number of elements in the current sort set.
* usStart is the offset to the 1st element in the set.
* usSkip is the spacing between consecutive elements.
* fHalves sorts the 2 halves when set, otherwise skips the
* 1st 2 of the 4 sub-sorts.
*
* Returns: VOID
*
* Purpose: Implements Batcher sort which is O(n lg n). The advantage
* of the batcher sort is that the comparisons made do NOT
* depend upon the outcome of previous comparisons. This makes
* it a good algorithm for parallelism. The algorithm works as
* follows: Sort the first half, sort the second half, sort the
* odd elements, sort the even elements, then compare swap
* elements 2/3, 4/5, ...
*
* Usage : There are several adaptations to the algorithm to
* allow it to work with arbitrary sized data sets
* (the original required a power of 2 sized data
* set): if the set size is less than 2, the routine
* returns, the first "half" is always the largest
* possible power of two, and the top value for the
* final compare/swap is adjusted to round up in
* case of an odd data set.
* Another optimization is that involving the fHalves
* flag. This stems from the observation that when
* the odd/even sort recurses, the first and second
* halves are already sorted, thus the first 2
* recursive calls are unnecessary in this case.
*
\****************************************************************/
VOID BatcherSortR(PCALCPARAM pcp, ULONG usArrSize, ULONG usStart,
ULONG usSkip, BOOL fHalves)
{
USHORT cnt,usUpper,usTemp; /* Utility variables */
if(!pcp->fContinueCalc) /* User wishes to terminate the sort */
return;
if(usArrSize<2) /* No sorting needed if <2 items in the set */
return;
if(usArrSize==2) /* Do simple compare/swap if there are 2 elements */
{
if(pcp->Array[usStart]>pcp->Array[usStart+usSkip])
{
usTemp = pcp->Array[usStart];
pcp->Array[usStart] = pcp->Array[usStart+usSkip];
pcp->Array[usStart+usSkip]= usTemp;
}
return;
}
usTemp=1; /* usTemp ends up holding the smallest power */
while(usTemp < usArrSize) /* of 2 that is at least as big as usArrSize */
usTemp *= 2;
if(fHalves) /* If the sort was NOT called by the odd/even recurses */
{
BatcherSortR(pcp,(ULONG)(usTemp/2),usStart,usSkip,(BOOL)1); /* Sort 1st half */
BatcherSortR(pcp,(ULONG)(usArrSize-usTemp/2), /* Sort 2nd half */
(ULONG)(usStart+usTemp/2*usSkip),usSkip,(BOOL)1);
}
BatcherSortR(pcp,(ULONG)(usArrSize-usArrSize/2),usStart,(ULONG)(usSkip*2),(BOOL)0); /* Sort evens */
BatcherSortR(pcp,(ULONG)(usArrSize/2),(ULONG)(usStart+usSkip),(ULONG)(usSkip*2),(BOOL)0); /* Sort odds */
if(!pcp->fContinueCalc) /* User wishes to terminate the sort */
return;
usUpper=(ULONG)(usStart+usSkip+(usArrSize-usArrSize/2-1)*2*usSkip);
for(cnt=usStart+usSkip;cnt<usUpper;cnt+=usSkip*2) /* Do final compares */
{
if(pcp->Array[cnt]>pcp->Array[cnt+usSkip])
{
usTemp = pcp->Array[cnt];
pcp->Array[cnt] = pcp->Array[cnt+usSkip];
pcp->Array[cnt+usSkip]= usTemp;
}
if(!pcp->fContinueCalc) /* User wishes to terminate the sort */
return;
}
return;
}
/****************************************************************\
* Function name: QuickSort()
*
* Parameters: pcp is a struct which contains the continue flag,
* a pointer to the data array, and a count of the items in
* the data array.
* None of the other pcp members are used.
*
* Returns: VOID
*
* Purpose: This routine is a stub that calls the recursive Quick sort
* with the proper initial arguments.
*
* Usage : It passes the pcp (Which contains the array ptr),
* the offset to start sorting at(0), and the offset to
* finish sorting at (Array size-1).
*
\****************************************************************/
VOID QuickSort(PCALCPARAM pcp)
{
QuickSortR(pcp,0,(pcp->cArray-1));
return;
}
/****************************************************************\
* Function name: QuickSortR()
*
* Parameters: pcp is a struct which contains the continue flag,
* a pointer to the data array.
* None of the other pcp members are used.
* sLeft is the offset of the leftmost sort element (smallest).
* sRight is the offset of rightmost sort element (largest).
*
* Returns: VOID
*
* Purpose: Implements Quick sort which is O(n lg n). Quick sort is a
* good all-purpose sorting algorithm and is widely used. This
* implementation works by placing the first element in the list
* into its correct place, by moving all elements smaller to its
* left, and all numbers larger to its right. The Quick sort
* recurses on the smaller side of the properly placed element,
* and loops back through the same routine for the larger side.
*
* NOTE: This routine does not recurse on both sides of the
* partition element. It only recurses on the smaller
* of the two sides. This was done in order to eliminate
* the stack overrun when it tries to sort an already
* sorted list.
*
* Usage:
*
\****************************************************************/
VOID QuickSortR(PCALCPARAM pcp, LONG sLeft, LONG sRight)
{
SHORT sTempLeft = sLeft; /* Holds lower bound on split position */
SHORT sTempRight = sRight; /* Holds upper bound on split position */
SHORT sSplit; /* Used to hold offset of positioned elem */
USHORT usTemp; /* Holds temp element during positioning */
while(TRUE)
{
if(sLeft >= sRight) /* If there is <=1 element, return */
return;
if(!pcp->fContinueCalc) /* User wishes to terminate the sort */
return;
/* Split list, sSplit will contain the split element */
usTemp = pcp->Array[sTempLeft];
while(TRUE) /* Loop thru 2 cases until the split position is found */
{
while(pcp->Array[sTempRight] > usTemp && /* Skip elems on right side */
sTempRight > sLeft) /* that are > the split elem */
sTempRight--;
if(sTempRight<=sTempLeft) /* Left and Right have met, split is found */
{
pcp->Array[sTempLeft]=usTemp; /* Place split elem at proper place */
sSplit = sTempLeft;
break;
}
pcp->Array[sTempLeft++] =
pcp->Array[sTempRight]; /* Move small element to LHS */
while(pcp->Array[sTempLeft] < usTemp && /* Skip elems on left side */
sTempLeft < sRight) /* that are < the split elem */
sTempLeft++;
if(sTempRight<=sTempLeft) /* Left and Right have met, split is found */
{
pcp->Array[sTempRight]=usTemp; /* Place split elem at proper place */
sSplit = sTempRight;
break;
}
pcp->Array[sTempRight--] =
pcp->Array[sTempLeft]; /* Move large element to RHS */
}
if ((sSplit - sLeft) > (sRight - sSplit)) {
/* left half is larger than right half */
QuickSortR(pcp, sSplit+1, sRight); /* Sort the 2nd half of the list */
if(!pcp->fContinueCalc) /* User wishes to terminate sort */
return;
sTempLeft = sLeft; /* Set up to sort the 1st half */
sTempRight = sRight = sSplit - 1;
}
else {
/* right half is larger than left half */
QuickSortR(pcp, sLeft, sSplit-1); /* Sort the 1st half of the list */
if(!pcp->fContinueCalc) /* User wishes to terminate sort */
return;
sTempRight = sRight; /* Set up to sort the 2nd half */
sTempLeft = sLeft = sSplit + 1;
}
}
return;
}
/****************************************************************\
* Function name: EnableMenuItem()
*
* Parameters: hwnd is a handle of the current window.
* sMenuItem is the ID of the item to Enable/Disable.
* fEnable will enable item if TRUE, otherwise disables it.
*
* Returns: VOID
*
* Purpose: This routine handles enabling/disabling of menu items. This
* is done by getting Parent and Menu hwnd handles then sending
* the appropriate message.
*
* Usage:
*
\****************************************************************/
VOID EnableMenuItem(HWND hwnd, LONG sMenuItem, BOOL fEnable)
{
HWND hwndParent = WinQueryWindow(hwnd, QW_PARENT);
HWND hwndMenu = WinWindowFromID(hwndParent, FID_MENU);
WinSendMsg(hwndMenu, MM_SETITEMATTR,
MPFROM2SHORT(sMenuItem, TRUE),
MPFROM2SHORT(MIA_DISABLED, fEnable ? 0 : MIA_DISABLED));
return;
}
/****************************************************************\
* Function name: EntryFldDlgProc()
*
* Parameters: hwnd, msg, mp1, mp2. Standard PM Dialog Proc params.
* A pointer to the current set size is passed in WM_INITDLG.
*
* Returns: Terminates with a TRUE iff a new valid data set size is entered.
*
* Purpose: Handles all the messages associated with the set entry field
* and calls the appropriate handling procedures. The purpose
* of this dialog box is to get a new data set size for the
* sort routines.
*
*
* Usage : If the value entered is valid, the proc will set the
* variable passed in through the WM_INITDLG to the value.
\****************************************************************/
MRESULT EXPENTRY EntryFldDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
SHORT sNewSize=0; /* Holds new set set */
static SHORT *pcSetSize; /* Set to point to user-passed set size */
MRESULT sRC;
switch(msg)
{
case WM_INITDLG:
FixSysMenu(hwnd);
pcSetSize=PVOIDFROMMP(mp2);
WinSendDlgItemMsg(hwnd, IDD_ENTRYFLD,EM_SETTEXTLIMIT, /* Limit len */
MPFROM2SHORT(4,0),NULL);
WinSetDlgItemShort(hwnd, IDD_ENTRYFLD,
*pcSetSize,TRUE);
return (MRESULT)0L; /* Allow normal focus setting */
case WM_COMMAND:
switch(SHORT1FROMMP(mp1))
{
case DID_OK:
WinQueryDlgItemShort(hwnd, IDD_ENTRYFLD,
&sNewSize, TRUE); /* Get the short */
if(sNewSize>0 && sNewSize<=MAX_ELEMS) /* Set new data set size */
{
*pcSetSize = sNewSize;
WinDismissDlg(hwnd,TRUE);
}
else /* Invalid value */
{
MessageBox(hwnd, IDMSG_ERRORSIZE,
MB_OK | MB_ERROR, TRUE);
return (MRESULT)FALSE;
}
return (MRESULT)0L;
case DID_CANCEL:
WinDismissDlg(hwnd,FALSE);
return (MRESULT)0L;
default:
sRC = WinDefDlgProc(hwnd, msg, mp1, mp2);
return sRC;
}
break;
default:
sRC = WinDefDlgProc(hwnd, msg, mp1, mp2);
return sRC;
}
return (MRESULT)0L;
}
/****************************************************************\
* Function name: AboutDlgProc()
*
* Parameters: hwnd, msg, mp1, mp2. Standard PM Dialog Proc params.
*
* Returns:
*
* Purpose: Handles all the messages associated with the About dialog.
*
* Usage:
*
\****************************************************************/
MRESULT EXPENTRY AboutDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
MRESULT sRC;
switch(msg)
{
case WM_INITDLG:
FixSysMenu(hwnd);
return (MRESULT)0L;
case WM_COMMAND:
WinDismissDlg(hwnd, TRUE);
return (MRESULT)0L;
default:
sRC = WinDefDlgProc(hwnd, msg, mp1, mp2);
return sRC;
}
return (MRESULT)0L;
}
/****************************************************************\
* Function name: RandomizeData()
*
* Parameters: cSetSize is the current size of the data set
*
* Returns: VOID
*
* Purpose: This routine randomizes the data arrays.
*
* Usage : This routine assumes that LISTCNT and NELEMS define
* the dimensions of the global Data array which is
* randomized.
\****************************************************************/
VOID RandomizeData(ULONG cSetSize)
{
USHORT cnt,cnt2;
for(cnt=0;cnt<LISTCNT;cnt++)
{
for(cnt2=0;cnt2<cSetSize;cnt2++)
Data[cnt][cnt2] = rand();
}
return;
}
/****************************************************************\
* Function name: FixSysMenu()
*
* Parameters: hwndDlg - handle to calling dialog
*
* Returns: VOID
*
* Purpose: This routine removes the Restore, Size, Minimize, and
* Maximize options from the system menu of a dialog.
*
* Usage : Called during the WM_INITDLG of a dialog procedure.
*
\****************************************************************/
VOID FixSysMenu(HWND hwndDlg)
{
HWND hwndMenu; /* handle to system menu */
hwndMenu = WinWindowFromID(hwndDlg, FID_SYSMENU);
WinSendMsg(hwndMenu, /* delete Restore from the system menu */
MM_DELETEITEM,
MPFROM2SHORT(SC_RESTORE, TRUE),
MPFROMP(NULL));
WinSendMsg(hwndMenu, /* delete Size from the system menu */
MM_DELETEITEM,
MPFROM2SHORT(SC_SIZE, TRUE),
MPFROMP(NULL));
WinSendMsg(hwndMenu, /* delete Minimize from the system menu */
MM_DELETEITEM,
MPFROM2SHORT(SC_MINIMIZE, TRUE),
MPFROMP(NULL));
WinSendMsg(hwndMenu, /* delete Maximize from the system menu */
MM_DELETEITEM,
MPFROM2SHORT(SC_MAXIMIZE, TRUE),
MPFROMP(NULL));
return;
}
/****************************************************************\
* Routine for initializing the help manager
*--------------------------------------------------------------
*
* Name: InitHelp()
*
* Purpose: Initializes the IPF help facility
*
* Usage: Called once during initialization of the program
*
* Method: Initializes the HELPINIT structure and creates the help
* instance. If successful, the help instance is associated
* with the main window
*
* Returns: VOID
*
\****************************************************************/
VOID InitHelp(VOID)
{
HELPINIT hini;
/* If we return because of an error, Help will be disabled */
fHelpEnabled = FALSE;
/* Initialize help init structure */
hini.cb = sizeof(HELPINIT);
hini.ulReturnCode = 0;
/* If tutorial added, add name here */
hini.pszTutorialName = (PSZ)NULL;
hini.phtHelpTable = (PHELPTABLE)MAKELONG(SORT_HELP_TABLE, 0xFFFF);
hini.hmodHelpTableModule = 0;
hini.hmodAccelActionBarModule = 0;
hini.idAccelTable = 0;
hini.idActionBar = 0;
if(!WinLoadString(hab,
0,
IDS_HELPWINDOWTITLE,
HELPLIBRARYNAMELEN,
(PSZ)szWindowTitle))
{
MessageBox(hwndClient, IDMSG_CANNOTLOADSTRING,
MB_OK | MB_ERROR, FALSE);
return;
}
hini.pszHelpWindowTitle = (PSZ)szWindowTitle;
/* If debugging, show panel ids, else don't */
#ifdef DEBUG
hini.fShowPanelId = CMIC_SHOW_PANEL_ID;
#else
hini.fShowPanelId = CMIC_HIDE_PANEL_ID;
#endif
if(!WinLoadString(hab,
0,
IDS_HELPLIBRARYNAME,
HELPLIBRARYNAMELEN,
(PSZ)szLibName))
{
MessageBox(hwndClient, IDMSG_CANNOTLOADSTRING,
MB_OK | MB_ERROR, FALSE);
return;
}
hini.pszHelpLibraryName = (PSZ)szLibName;
/* Creating help instance */
hwndHelpInstance = WinCreateHelpInstance(hab, &hini);
if(hwndHelpInstance == 0 || hini.ulReturnCode)
{
MessageBox(hwndFrame, IDMSG_HELPLOADERROR, MB_OK | MB_ERROR, TRUE);
return;
}
/* Associate help instance with main frame */
if(!WinAssociateHelpInstance(hwndHelpInstance, hwndFrame))
{
MessageBox(hwndFrame, IDMSG_HELPLOADERROR,
MB_OK | MB_ERROR, TRUE);
return;
}
/* Help manager is successfully initialized so set flag to TRUE */
fHelpEnabled = TRUE;
return;
} /* InitHelp() */
/****************************************************************\
* Processes the Help for Help command from the menu bar
*--------------------------------------------------------------
*
* Name: HelpHelpForHelp(mp2)
*
* Purpose: Processes the WM_COMMAND message posted by the Help for
* Help item of the Help menu
*
* Usage: Called from MainCommand when the Help for Help menu item
* is selected
*
* Method: Sends an HM_DISPLAY_HELP message to the help instance so
* that the default Help For Help is displayed.
*
* Returns: VOID
*
\****************************************************************/
VOID HelpHelpForHelp(MPARAM mp2)
{
/* This just displays the system help for help panel */
if(fHelpEnabled)
if(WinSendMsg(hwndHelpInstance, HM_DISPLAY_HELP, NULL, NULL))
MessageBox(hwndClient,
IDMSG_HELPDISPLAYERROR,
MB_OK | MB_ERROR,
FALSE);
/* This routine currently doesn't use the mp2 parameter but *\
* it is referenced here to prevent an 'Unreferenced Parameter'
\* warning at compile time. */
return;
} /* HelpHelpForHelp() */
/****************************************************************\
* Processes the Extended Help command from the menu bar
*--------------------------------------------------------------
*
* Name: HelpExtended(mp2)
*
* Purpose: Processes the WM_COMMAND message posted by the Extended
* Help item of the Help menu.
*
* Usage: Called from MainCommand when the Extended Help menu item
* is selected.
*
* Method: Sends an HM_EXT_HELP message to the help instance so that
* the default Extended Help is displayed.
*
* Returns: VOID
*
\****************************************************************/
VOID HelpExtended(MPARAM mp2)
{
/* This just displays the system extended help panel */
if(fHelpEnabled)
if(WinSendMsg(hwndHelpInstance, HM_EXT_HELP, NULL, NULL))
MessageBox(hwndClient,
IDMSG_HELPDISPLAYERROR,
MB_OK | MB_ERROR,
FALSE);
/* This routine currently doesn't use the mp2 parameter but *\
* it is referenced here to prevent an 'Unreferenced Parameter'
\* warning at compile time. */
return;
} /* HelpExtended() */
/****************************************************************\
* Processes the Keys Help command from the menu bar
*--------------------------------------------------------------
*
* Name: HelpKeys(mp2)
*
* Purpose: Processes the WM_COMMAND message posted by the Keys Help
* item of the Help menu.
*
* Usage: Called from MainCommand when the Keys Help menu item is
* selected
*
* Method: Sends an HM_KEYS_HELP message to the help instance so that
* the default Keys Help is displayed.
*
* Returns: VOID
*
\****************************************************************/
VOID HelpKeys(MPARAM mp2)
{
/* This just displays the system keys help panel */
if(fHelpEnabled)
if(WinSendMsg(hwndHelpInstance, HM_KEYS_HELP, NULL, NULL))
MessageBox(hwndClient,
IDMSG_HELPDISPLAYERROR,
MB_OK | MB_ERROR,
FALSE);
/* This routine currently doesn't use the mp2 parameter but *\
* it is referenced here to prevent an 'Unreferenced Parameter'
\* warning at compile time. */
return;
} /* HelpKeys() */
/****************************************************************\
* Processes the Index Help command from the menu bar
*--------------------------------------------------------------
*
* Name: HelpIndex(mp2)
*
* Purpose: Processes the WM_COMMAND message posted by the Index Help
* item of the Help menu
*
* Usage: Called from MainCommand when the Index Help menu item
* is selected
*
* Method: Sends an HM_INDEX_HELP message to the help instance so
* that the default Index Help is displayed.
*
*
* Returns: VOID
*
\****************************************************************/
VOID HelpIndex(MPARAM mp2)
{
/* This just displays the system help index panel */
if(fHelpEnabled)
if(WinSendMsg(hwndHelpInstance, HM_HELP_INDEX, NULL, NULL))
MessageBox(hwndClient,
IDMSG_HELPDISPLAYERROR,
MB_OK | MB_ERROR,
FALSE);
/* This routine currently doesn't use the mp2 parameter but *\
* it is referenced here to prevent an 'Unreferenced Parameter'
\* warning at compile time. */
return;
} /* HelpIndex() */
/****************************************************************\
* Processes the About command from the Help menu
*--------------------------------------------------------------
*
* Name: HelpAbout(mp2)
*
* Purpose: Processes the WM_COMMAND message posted by the About item
* of the Help menu
*
* Usage: Called from MainCommand when the About menu item is selected
*
* Method: Calls WinDlgBox to display the about box dialog.
*
* Returns: VOID
*
\****************************************************************/
VOID HelpAbout(MPARAM mp2)
{
/* Display the AboutBox dialog */
WinDlgBox(HWND_DESKTOP,
hwndClient,
AboutDlgProc,
(HMODULE)0,
IDD_PRODUCTINFO,
NULL);
/* This routine currently doesn't use the mp2 parameter but *\
* it is referenced here to prevent an 'Unreferenced Parameter'
\* warning at compile time. */
return;
} /* HelpAbout() */
/****************************************************************\
* Displays the help panel indicated
*--------------------------------------------------------------
*
* Name: DisplayHelpPanel(idPanel)
*
* Purpose: Displays the help panel whose id is given
*
* Usage: Called whenever a help panel is desired to be displayed,
* usually from the WM_HELP processing of the dialog boxes
*
* Method: Sends HM_DISPLAY_HELP message to the help instance
*
* Returns: VOID
*
\****************************************************************/
VOID DisplayHelpPanel(LONG idPanel)
{
if(fHelpEnabled)
if(WinSendMsg(hwndHelpInstance,
HM_DISPLAY_HELP,
MPFROMLONG(MAKELONG(idPanel, NULL)),
MPFROMSHORT(HM_RESOURCEID)))
MessageBox(hwndFrame,
IDMSG_HELPDISPLAYERROR,
MB_OK | MB_ERROR,
TRUE);
return;
} /* DisplayHelpPanel() */
/****************************************************************\
* Destroys the help instance
*--------------------------------------------------------------
*
* Name: DestroyHelpInstance(VOID)
*
* Purpose: Destroys the help instance for the application
*
* Usage: Called after exit from message loop
*
* Method: Calls WinDestroyHelpInstance() to destroy the help instance
*
* Returns: VOID
*
\****************************************************************/
VOID DestroyHelpInstance(VOID)
{
if(hwndHelpInstance != 0)
{
WinDestroyHelpInstance(hwndHelpInstance);
}
return;
} /* DestroyHelpInstance() */
/****************************************************************\
* Message Box procedure
*--------------------------------------------------------------
*
* Name: MessageBox(hwndOwner, nIdMsg, fsStyle, fBeep)
*
* Purpose: Displays the message box with the message given in idMsg
* retrieved from the message table and using the style
* flags in fsStyle
*
* Usage: Called whenever a MessageBox is to be displayed
*
* Method: - Message string is loaded from the process' message table
* - Alarm beep is sounded if desired
* - Message box with the message is displayed
* - WinMessageBox return value is returned
*
* Returns: Return value from WinMessageBox()
*
\****************************************************************/
LONG MessageBox(HWND hwndOwner, LONG idMsg, LONG fsStyle, BOOL fBeep)
{
CHAR szText[MESSAGELEN];
LONG sRC;
if(!WinLoadMessage(hab,
(HMODULE)NULL,
idMsg,
MESSAGELEN,
(PSZ)szText))
{
WinAlarm(HWND_DESKTOP, WA_ERROR);
return RETURN_ERROR;
}
if(fBeep)
WinAlarm(HWND_DESKTOP, WA_ERROR);
sRC = WinMessageBox(HWND_DESKTOP,
hwndOwner,
szText,
(PSZ)NULL,
IDD_MSGBOX,
fsStyle);
return sRC;
} /* MessageBox() */