Index: trunk/src/helpers/dosh.c
===================================================================
--- trunk/src/helpers/dosh.c	(revision 93)
+++ trunk/src/helpers/dosh.c	(revision 94)
@@ -373,4 +373,6 @@
  *      to cause problems with some device drivers for
  *      removeable disks.
+ *
+ *@@changed V0.9.14 (2001-08-03) [umoeller]: added extra fix for A: and B:
  */
 
@@ -379,4 +381,13 @@
 {
     APIRET arc = ERROR_INVALID_DRIVE;
+
+    if (    (ulLogicalDrive == 1)
+         || (ulLogicalDrive == 2)
+       )
+    {
+        // drive A: and B: can never be fixed V0.9.14 (2001-08-03) [umoeller]
+        *pfFixed = FALSE;
+        return NO_ERROR;
+    }
 
     if (ulLogicalDrive)
@@ -395,6 +406,6 @@
         parms.drive = (UCHAR)(ulLogicalDrive-1);
         arc = doshDevIOCtl((HFILE)-1,
-                           IOCTL_DISK,
-                           DSK_BLOCKREMOVABLE,
+                           IOCTL_DISK,                  // 0x08
+                           DSK_BLOCKREMOVABLE,          // 0x20
                            &parms, sizeof(parms),
                            &ucNonRemoveable, sizeof(ucNonRemoveable));
@@ -471,6 +482,6 @@
 
         arc = doshDevIOCtl((HFILE)-1,
-                           IOCTL_DISK,
-                           DSK_GETDEVICEPARAMS,
+                           IOCTL_DISK,                  // 0x08
+                           DSK_GETDEVICEPARAMS,         // 0x63
                            &parms, sizeof(parms),
                            pdp,   sizeof(BIOSPARAMETERBLOCK));
@@ -520,4 +531,5 @@
 
 APIRET doshHasAudioCD(ULONG ulLogicalDrive,
+                      HFILE hfDrive,            // in: DASD open
                       BOOL fMixedModeCD,
                       PBOOL pfAudio)
@@ -525,128 +537,95 @@
     APIRET  arc = NO_ERROR;
 
-    HFILE   hfDrive = 0;
-    ULONG   ulTemp = 0;
-
-    CHAR    szDrive[3] = "C:";
-    szDrive[0] = 'A' + ulLogicalDrive - 1;
+    ULONG ulAudioTracks = 0,
+          ulDataTracks = 0;
+
+    CHAR cds1[4] = { 'C', 'D', '0', '1' };
+    CHAR cds2[4];
 
     *pfAudio = FALSE;
 
-    arc = DosOpen(szDrive,   // "C:", "D:", ...
-                  &hfDrive,
-                  &ulTemp,
-                  0,
-                  FILE_NORMAL,
-                  OPEN_ACTION_FAIL_IF_NEW
-                         | OPEN_ACTION_OPEN_IF_EXISTS,
-                  OPEN_FLAGS_DASD
-                         | OPEN_FLAGS_FAIL_ON_ERROR
-                         | OPEN_FLAGS_NOINHERIT     // V0.9.6 (2000-11-25) [pr]
-              //            | OPEN_ACCESS_READONLY  // V0.9.13 (2001-06-14) [umoeller]
-                         | OPEN_SHARE_DENYNONE,
-                  NULL);
-
-    // _Pmpf(("   DosOpen(OPEN_FLAGS_DASD) returned %d", arc));
-
-    // this still returns NO_ERROR for audio CDs in a
-    // CD-ROM drive...
-    // however, the WPS then attempts to read in the
-    // root directory for audio CDs, which produces
-    // a "sector not found" error box...
-
-    if (!arc && hfDrive)     // determined above
-    {
-        ULONG ulAudioTracks = 0,
-              ulDataTracks = 0;
-
-        CHAR cds1[4] = { 'C', 'D', '0', '1' };
-        CHAR cds2[4];
-        // check for proper driver signature
-        if (!(arc = doshDevIOCtl(hfDrive,
-                                 IOCTL_CDROMDISK,
-                                 CDROMDISK_GETDRIVER,
-                                 &cds1, sizeof(cds1),
-                                 &cds2, sizeof(cds2))))
+    // check for proper driver signature
+    if (!(arc = doshDevIOCtl(hfDrive,
+                             IOCTL_CDROMDISK,
+                             CDROMDISK_GETDRIVER,
+                             &cds1, sizeof(cds1),
+                             &cds2, sizeof(cds2))))
+    {
+        if (memcmp(&cds1, &cds2, 4))
+            // this is not a CD-ROM then:
+            arc = NO_ERROR;
+        else
         {
-            if (memcmp(&cds1, &cds2, 4))
-                // this is not a CD-ROM then:
-                arc = NO_ERROR;
-            else
+            struct {
+                UCHAR   ucFirstTrack,
+                        ucLastTrack;
+                ULONG   ulLeadOut;
+            } cdat;
+
+            // get track count
+            if (!(arc = doshDevIOCtl(hfDrive,
+                                     IOCTL_CDROMAUDIO,
+                                     CDROMAUDIO_GETAUDIODISK,
+                                     &cds1, sizeof(cds1),
+                                     &cdat, sizeof(cdat))))
             {
-                struct {
-                    UCHAR   ucFirstTrack,
-                            ucLastTrack;
-                    ULONG   ulLeadOut;
-                } cdat;
-
-                // get track count
-                if (!(arc = doshDevIOCtl(hfDrive,
-                                         IOCTL_CDROMAUDIO,
-                                         CDROMAUDIO_GETAUDIODISK,
-                                         &cds1, sizeof(cds1),
-                                         &cdat, sizeof(cdat))))
+                // still no error: build the audio TOC
+                ULONG i;
+                for (i = cdat.ucFirstTrack;
+                     i <= cdat.ucLastTrack;
+                     i++)
                 {
-                    // still no error: build the audio TOC
-                    ULONG i;
-                    for (i = cdat.ucFirstTrack;
-                         i <= cdat.ucLastTrack;
-                         i++)
+                    BYTE cdtp[5] =
+                      { 'C', 'D', '0', '1', (UCHAR)i };
+
+                    struct {
+                        ULONG   ulTrackAddress;
+                        BYTE    bFlags;
+                    } trackdata;
+
+                    if (!(arc = doshDevIOCtl(hfDrive,
+                                             IOCTL_CDROMAUDIO,
+                                             CDROMAUDIO_GETAUDIOTRACK,
+                                             &cdtp, sizeof(cdtp),
+                                             &trackdata, sizeof(trackdata))))
                     {
-                        BYTE cdtp[5] =
-                          { 'C', 'D', '0', '1', (UCHAR)i };
-
-                        struct {
-                            ULONG   ulTrackAddress;
-                            BYTE    bFlags;
-                        } trackdata;
-
-                        if (!(arc = doshDevIOCtl(hfDrive,
-                                                 IOCTL_CDROMAUDIO,
-                                                 CDROMAUDIO_GETAUDIOTRACK,
-                                                 &cdtp, sizeof(cdtp),
-                                                 &trackdata, sizeof(trackdata))))
+                        if (trackdata.bFlags & 64)
+                            ulDataTracks++;
+                        else
                         {
-                            if (trackdata.bFlags & 64)
-                                ulDataTracks++;
-                            else
+                            ulAudioTracks++;
+
+                            if (!fMixedModeCD)
                             {
-                                ulAudioTracks++;
-
-                                if (!fMixedModeCD)
-                                {
-                                    // caller doesn't want mixed mode:
-                                    // stop here
-                                    ulDataTracks = 0;
-                                    break;
-                                }
+                                // caller doesn't want mixed mode:
+                                // stop here
+                                ulDataTracks = 0;
+                                break;
                             }
                         }
                     }
-
-                    // _Pmpf(("   got %d audio, %d data tracks",
-                    //             ulAudioTracks, ulDataTracks));
-
-                    if (!ulDataTracks)
-                        *pfAudio = TRUE;
                 }
-                else
-                {
-                    // not audio disk:
-                    // go on then
-                    // _Pmpf(("   CDROMAUDIO_GETAUDIODISK returned %d", arc));
-                    arc = NO_ERROR;
-                }
+
+                // _Pmpf(("   got %d audio, %d data tracks",
+                //             ulAudioTracks, ulDataTracks));
+
+                if (!ulDataTracks)
+                    *pfAudio = TRUE;
+            }
+            else
+            {
+                // not audio disk:
+                // go on then
+                // _Pmpf(("   CDROMAUDIO_GETAUDIODISK returned %d", arc));
+                arc = NO_ERROR;
             }
         }
-        else
-        {
-            // not CD-ROM: go on then
-            // _Pmpf(("   CDROMDISK_GETDRIVER returned %d", arc));
-            arc = NO_ERROR;
-        }
-    }
-
-    if (hfDrive)
-        DosClose(hfDrive);
+    }
+    else
+    {
+        // not CD-ROM: go on then
+        // _Pmpf(("   CDROMDISK_GETDRIVER returned %d", arc));
+        arc = NO_ERROR;
+    }
 
     return (arc);
@@ -835,6 +814,6 @@
                           &fFixed);    // V0.9.13 (2001-06-14) [umoeller]
 
-    // _Pmpf((__FUNCTION__ ": doshIsFixedDisk returned %d for disk %d", arc, ulLogicalDrive));
-    // _Pmpf(("   fFixed is %d", fFixed));
+    _Pmpf((__FUNCTION__ ": doshIsFixedDisk returned %d for disk %d", arc, ulLogicalDrive));
+    _Pmpf(("   fFixed is %d", fFixed));
 
     if (!arc)
@@ -846,5 +825,5 @@
             arc = doshQueryDiskParams(ulLogicalDrive,
                                       &bpb);
-            // _Pmpf(("   doshQueryDiskParams returned %d", arc));
+            _Pmpf(("   doshQueryDiskParams returned %d", arc));
 
             if (    (!arc)
@@ -852,18 +831,56 @@
                )
             {
-                // _Pmpf(("   --> is CD-ROM"));
+                _Pmpf(("   --> is CD-ROM"));
                 fCDROM = TRUE;
             }
         }
 
-    if ((!arc) && (fCDROM))
-    {
-        BOOL fAudio;
-        if (    (!(arc = doshHasAudioCD(ulLogicalDrive,
-                                        ((fl & ASSERTFL_MIXEDMODECD) != 0),
-                                        &fAudio)))
-             && (fAudio)
+    if (!arc)
+    {
+        HFILE hfDrive = NULLHANDLE;
+
+        ULONG   ulTemp = 0;
+        CHAR    szDrive[3] = "C:";
+        szDrive[0] = 'A' + ulLogicalDrive - 1;
+
+        arc = DosOpen(szDrive,   // "C:", "D:", ...
+                      &hfDrive,
+                      &ulTemp,
+                      0,
+                      FILE_NORMAL,
+                      OPEN_ACTION_FAIL_IF_NEW
+                             | OPEN_ACTION_OPEN_IF_EXISTS,
+                      OPEN_FLAGS_DASD
+                             | OPEN_FLAGS_FAIL_ON_ERROR
+                             | OPEN_FLAGS_NOINHERIT     // V0.9.6 (2000-11-25) [pr]
+                  //            | OPEN_ACCESS_READONLY  // V0.9.13 (2001-06-14) [umoeller]
+                             | OPEN_SHARE_DENYNONE,
+                      NULL);
+
+        // _Pmpf(("   DosOpen(OPEN_FLAGS_DASD) returned %d", arc));
+
+        // this still returns NO_ERROR for audio CDs in a
+        // CD-ROM drive...
+        // however, the WPS then attempts to read in the
+        // root directory for audio CDs, which produces
+        // a "sector not found" error box...
+
+        if (    (!arc)
+             && (hfDrive)
+             && (fCDROM)
            )
-            arc = ERROR_AUDIO_CD_ROM;       // special private error code (10000)
+        {
+            BOOL fAudio;
+            if (    (!(arc = doshHasAudioCD(ulLogicalDrive,
+                                            hfDrive,
+                                            ((fl & ASSERTFL_MIXEDMODECD) != 0),
+                                            &fAudio)))
+                 && (fAudio)
+               )
+                arc = ERROR_AUDIO_CD_ROM;       // special private error code (10000)
+        }
+
+        if (hfDrive)
+            DosClose(hfDrive);
     }
 
@@ -2649,7 +2666,12 @@
  *
  *      If (fWait), this function will create a termination queue
- *      and not return until the child session has ended. Otherwise
- *      the function will return immediately, and the SID/PID of
- *      the child session can be found in *pulSID and *ppid.
+ *      and not return until the child session has ended. Be warned,
+ *      this blocks the calling thread.
+ *
+ *      Otherwise the function will return immediately.
+ *
+ *      The session and process IDs of the child session will be
+ *      written to *pulSID and *ppid. Of course, in "wait" mode,
+ *      these are no longer valid after this function returns.
  *
  *      Returns the error code of DosStartSession.
@@ -2661,4 +2683,6 @@
  *@@changed V0.9.1 (99-12-30) [umoeller]: queue was sometimes not closed. Fixed.
  *@@changed V0.9.3 (2000-05-03) [umoeller]: added fForeground
+ *@@changed V0.9.14 (2001-08-03) [umoeller]: fixed potential queue leak
+ *@@changed V0.9.14 (2001-08-03) [umoeller]: fixed memory leak in wait mode; added pusReturn to prototype
  */
 
@@ -2669,73 +2693,89 @@
                              BOOL fWait,        // in: wait for termination?
                              PULONG pulSID,     // out: session ID (req.)
-                             PPID ppid)         // out: process ID (req.)
-{
-    APIRET      arc;
+                             PPID ppid,         // out: process ID (req.)
+                             PUSHORT pusReturn) // out: in wait mode, session's return code (ptr can be NULL)
+{
+    APIRET      arc = NO_ERROR;
     // queue stuff
     const char  *pcszQueueName = "\\queues\\xwphlpsw.que";
     HQUEUE      hq = 0;
     PID         qpid = 0;
-    STARTDATA   SData;
-    CHAR        szObjBuf[CCHMAXPATH];
 
     if (fWait)
     {
-        if ((arc = DosCreateQueue(&hq,
-                                  QUE_FIFO | QUE_CONVERT_ADDRESS,
-                                  (PSZ)pcszQueueName))
-                    != NO_ERROR)
-            return (arc);
-
-        if ((arc = DosOpenQueue(&qpid, &hq, (PSZ)pcszQueueName)) != NO_ERROR)
-            return (arc);
-    }
-
-    SData.Length  = sizeof(STARTDATA);
-    SData.Related = SSF_RELATED_CHILD; //INDEPENDENT;
-    SData.FgBg    = (fForeground) ? SSF_FGBG_FORE : SSF_FGBG_BACK;
-            // V0.9.3 (2000-05-03) [umoeller]
-    SData.TraceOpt = SSF_TRACEOPT_NONE;
-
-    SData.PgmTitle = (PSZ)pcszPath;       // title for window
-    SData.PgmName = (PSZ)pcszPath;
-    SData.PgmInputs = (PSZ)pcszParams;
-
-    SData.TermQ = (fWait) ? (PSZ)pcszQueueName : NULL;
-    SData.Environment = 0;
-    SData.InheritOpt = SSF_INHERTOPT_PARENT;
-    SData.SessionType = SSF_TYPE_DEFAULT;
-    SData.IconFile = 0;
-    SData.PgmHandle = 0;
-
-    SData.PgmControl = usPgmCtl;
-
-    SData.InitXPos  = 30;
-    SData.InitYPos  = 40;
-    SData.InitXSize = 200;
-    SData.InitYSize = 140;
-    SData.Reserved = 0;
-    SData.ObjectBuffer  = (CHAR*)&szObjBuf;
-    SData.ObjectBuffLen = (ULONG)sizeof(szObjBuf);
-
-    arc = DosStartSession(&SData, pulSID, ppid);
-
-    if (arc == NO_ERROR)
-    {
-        if (fWait)
+        if (!(arc = DosCreateQueue(&hq,
+                                   QUE_FIFO | QUE_CONVERT_ADDRESS,
+                                   (PSZ)pcszQueueName)))
+            arc = DosOpenQueue(&qpid, &hq, (PSZ)pcszQueueName);
+    }
+
+    if (!arc)    // V0.9.14 (2001-08-03) [umoeller]
+    {
+        STARTDATA   SData;
+        CHAR        szObjBuf[CCHMAXPATH];
+
+        SData.Length  = sizeof(STARTDATA);
+        SData.Related = SSF_RELATED_CHILD; //INDEPENDENT;
+        SData.FgBg    = (fForeground) ? SSF_FGBG_FORE : SSF_FGBG_BACK;
+                // V0.9.3 (2000-05-03) [umoeller]
+        SData.TraceOpt = SSF_TRACEOPT_NONE;
+
+        SData.PgmTitle = (PSZ)pcszPath;       // title for window
+        SData.PgmName = (PSZ)pcszPath;
+        SData.PgmInputs = (PSZ)pcszParams;
+
+        SData.TermQ = (fWait) ? (PSZ)pcszQueueName : NULL;
+        SData.Environment = 0;
+        SData.InheritOpt = SSF_INHERTOPT_PARENT;
+        SData.SessionType = SSF_TYPE_DEFAULT;
+        SData.IconFile = 0;
+        SData.PgmHandle = 0;
+
+        SData.PgmControl = usPgmCtl;
+
+        SData.InitXPos  = 30;
+        SData.InitYPos  = 40;
+        SData.InitXSize = 200;
+        SData.InitYSize = 140;
+        SData.Reserved = 0;
+        SData.ObjectBuffer  = szObjBuf;
+        SData.ObjectBuffLen = (ULONG)sizeof(szObjBuf);
+
+        if (    (!(arc = DosStartSession(&SData, pulSID, ppid)))
+             && (fWait)
+           )
         {
+            // block on the termination queue, which is written
+            // to when the subprocess ends
             REQUESTDATA rqdata;
-            ULONG       DataLength = 0;
-            PULONG      DataAddress;
+            ULONG       cbData = 0;
+            PULONG      pulData = NULL;
             BYTE        elpri;
 
             rqdata.pid = qpid;
-            DosReadQueue(hq,                // in: queue handle
-                         &rqdata,           // out: pid and ulData
-                         &DataLength,       // out: size of data returned
-                         (PVOID*)&DataAddress, // out: data returned
-                         0,                 // in: remove first element in queue
-                         0,                 // in: wait for queue data (block thread)
-                         &elpri,            // out: element's priority
-                         0);                // in: event semaphore to be posted
+            if (!(arc = DosReadQueue(hq,                // in: queue handle
+                                     &rqdata,           // out: pid and ulData
+                                     &cbData,           // out: size of data returned
+                                     (PVOID*)&pulData,  // out: data returned
+                                     0,                 // in: remove first element in queue
+                                     0,                 // in: wait for queue data (block thread)
+                                     &elpri,            // out: element's priority
+                                     0)))               // in: event semaphore to be posted
+            {
+                if (!rqdata.ulData)
+                {
+                    // child session ended:
+                    // V0.9.14 (2001-08-03) [umoeller]
+
+                    // *pulSID = (*pulData) & 0xffff;
+                    if (pusReturn)
+                        *pusReturn = ((*pulData) >> 16) & 0xffff;
+
+                }
+                // else: continue looping
+
+                if (pulData)
+                    DosFreeMem(pulData);
+            }
         }
     }
Index: trunk/src/helpers/gpih.c
===================================================================
--- trunk/src/helpers/gpih.c	(revision 93)
+++ trunk/src/helpers/gpih.c	(revision 94)
@@ -325,9 +325,5 @@
  *      The specified rectangle is inclusive, that is, the top
  *      right corner specifies the top right pixel to be drawn.
- *      This is different from WinFillRect
- *      (see @GPI_rectangles).
- *
- *      If (lColor != -1), the HPS's current foreground color
- *      is changed to that color.
+ *      This is different from WinFillRect (see @GPI_rectangles).
  *
  *      Changes to the HPS:
@@ -343,5 +339,5 @@
 VOID gpihBox(HPS hps,              // in: presentation space for output
              LONG lControl,        // in: one of DRO_OUTLINE, DRO_FILL, DRO_OUTLINEFILL
-             PRECTL prcl)          // in: rectangle to draw (exclusive)
+             PRECTL prcl)          // in: rectangle to draw (inclusive)
 {
     POINTL      ptl;
@@ -554,4 +550,260 @@
 
 /*
+ *@@ gpihMatchFont:
+ *      attempts to find a font matching the specified
+ *      data and fills the specified FATTRS structure
+ *      accordingly.
+ *
+ *      This function performs the insane "11-step process" to
+ *      match a font, as described in the GPI reference.
+ *
+ *      This function can operate in two modes:
+ *
+ *      -- "Family" mode. In that case, specify the font family name
+ *         with pszName and set fFamily to TRUE. This is useful for
+ *         WYSIWYG text viewing if you need several font faces for
+ *         the same family, such as Courier Bold, Bold Italics, etc.
+ *         You can specify those attributes with usFormat then.
+ *
+ *      -- "Face" mode. In that case, specify the full font face name
+ *         with pszName and set fFamily to FALSE. This is useful for
+ *         font presentation parameters which use the "WarpSans Bold"
+ *         format. In that case, set usFormat to 0.
+ *
+ *      Returns TRUE if a "true" match was found, FALSE
+ *      otherwise. In both cases, *pfa receives data
+ *      which will allow GpiCreateLogFont to work; however,
+ *      if FALSE is returned, GpiCreateLogFont will most
+ *      likely find the default font (System Proportional)
+ *      only.
+ *
+ *      If (pFontMetrics != NULL), *pFontMetrics receives the
+ *      FONTMETRICS of the font which was found. If an outline
+ *      font has been found (instead of a bitmap font),
+ *      FONTMETRICS.fsDefn will have the FM_DEFN_OUTLINE bit set.
+ *
+ *      This function was extracted from gpihFindFont with
+ *      0.9.14 to allow for caching the font search results,
+ *      which is most helpful for memory device contexts,
+ *      where gpihFindFont can be inefficient.
+ *
+ *@@added V0.9.14 (2001-08-03) [umoeller]
+ *@@changed V0.9.14 (2001-08-03) [umoeller]: fixed a few weirdos with outline fonts
+ */
+
+BOOL gpihMatchFont(HPS hps,
+                   LONG lSize,            // in: font point size
+                   BOOL fFamily,          // in: if TRUE, pszName specifies font family;
+                                          //     if FALSE, pszName specifies font face
+                   const char *pcszName,  // in: font family or face name (without point size)
+                   USHORT usFormat,       // in: none, one or several of:
+                                          // -- FATTR_SEL_ITALIC
+                                          // -- FATTR_SEL_UNDERSCORE (underline)
+                                          // -- FATTR_SEL_BOLD
+                                          // -- FATTR_SEL_STRIKEOUT
+                                          // -- FATTR_SEL_OUTLINE (hollow)
+                   FATTRS *pfa,           // out: font attributes if found
+                   PFONTMETRICS pFontMetrics) // out: font metrics of created font (optional)
+{
+    // first find out how much memory we need to allocate
+    // for the FONTMETRICS structures
+    ULONG   ul = 0;
+    LONG    lTemp = 0;
+    LONG    cFonts = GpiQueryFonts(hps,
+                                   QF_PUBLIC | QF_PRIVATE,
+                                   NULL, // pszFaceName,
+                                   &lTemp,
+                                   sizeof(FONTMETRICS),
+                                   NULL);
+    PFONTMETRICS    pfm = (PFONTMETRICS)malloc(cFonts * sizeof(FONTMETRICS)),
+                    pfm2 = pfm,
+                    pfmFound = NULL;
+
+    BOOL            fQueriedDevice = FALSE;     // V0.9.14 (2001-08-01) [umoeller]
+    LONG            alDevRes[2];            // device resolution
+
+    // _Pmpf(("gpihFindFont: enumerating for %s, %d points", pcszName, lSize));
+
+    GpiQueryFonts(hps,
+                  QF_PUBLIC | QF_PRIVATE,
+                  NULL, // pszFaceName,
+                  &cFonts,
+                  sizeof(FONTMETRICS),      // length of each metrics structure
+                                            // -- _not_ total buffer size!
+                  pfm);
+
+    // now we have an array of FONTMETRICS
+    // for EVERY font that is installed on the system...
+    // these things are completely unsorted, so there's
+    // nothing we can rely on, we have to check them all.
+
+    // fill in some default values for FATTRS,
+    // in case we don't find something better
+    // in the loop below; these values will be
+    // applied if
+    // a)   an outline font has been found;
+    // b)   bitmap fonts have been found, but
+    //      none for the current device resolution
+    //      exists;
+    // c)   no font has been found at all.
+    // In all cases, GpiCreateLogFont will do
+    // a "close match" resolution (at the bottom).
+    pfa->usRecordLength = sizeof(FATTRS);
+    pfa->fsSelection = usFormat; // changed later if better font is found
+    pfa->lMatch = 0L;             // closest match
+    strcpy(pfa->szFacename, pcszName);
+    pfa->idRegistry = 0;          // default registry
+    pfa->usCodePage = 0;          // default codepage
+    // the following two must be zero, or outline fonts
+    // will not be found; if a bitmap font has been passed
+    // to us, we'll modify these two fields later
+    pfa->lMaxBaselineExt = 0;     // font size (height)
+    pfa->lAveCharWidth = 0;       // font size (width)
+    pfa->fsType = 0;              // default type
+    pfa->fsFontUse = FATTR_FONTUSE_NOMIX;
+
+    // now go thru the array of FONTMETRICS
+    // to check if we have a bitmap font
+    // pszFaceName; the default WPS behavior
+    // is that bitmap fonts appear to take
+    // priority over outline fonts of the
+    // same name, so we check these first
+    pfm2 = pfm;
+    for (ul = 0;
+         ul < cFonts;
+         ul++)
+    {
+        const char *pcszCompare = (fFamily)
+                                     ? pfm2->szFamilyname
+                                     : pfm2->szFacename;
+
+        /* _Pmpf(("  Checking font: %s (Fam: %s), %d, %d, %d",
+               pcszCompare,
+               pfm2->szFamilyname,
+               pfm2->sNominalPointSize,
+               pfm2->lMaxBaselineExt,
+               pfm2->lAveCharWidth)); */
+
+        if (!strcmp(pcszCompare, pcszName))
+        {
+            /* _Pmpf(("  Found font %s; slope %d, usWeightClass %d",
+                    pfm2->szFacename,
+                    pfm2->sCharSlope,
+                    pfm2->usWeightClass)); */
+
+            if ((pfm2->fsDefn & FM_DEFN_OUTLINE) == 0)
+            {
+                // image (bitmap) font:
+                // check point size
+                if (pfm2->sNominalPointSize == lSize * 10)
+                {
+                    // OK: check device resolutions, because
+                    // normally, there are always several image
+                    // fonts for different resolutions
+                    // for bitmap fonts, there are normally two versions:
+                    // one for low resolutions, one for high resolutions
+                    if (!fQueriedDevice)
+                    {
+                        DevQueryCaps(GpiQueryDevice(hps),
+                                     CAPS_HORIZONTAL_FONT_RES,
+                                     2L,
+                                     alDevRes);
+                        fQueriedDevice = TRUE;
+                    }
+
+                    if (    (pfm2->sXDeviceRes == alDevRes[0])
+                         && (pfm2->sYDeviceRes == alDevRes[1])
+                       )
+                    {
+                        // OK: use this for GpiCreateLogFont
+                        pfa->lMaxBaselineExt = pfm2->lMaxBaselineExt;
+                        pfa->lAveCharWidth = pfm2->lAveCharWidth;
+                        // pfa->lMatch = pfm2->lMatch;
+
+                        pfmFound = pfm2;
+                        break;
+                    }
+                }
+            }
+            else
+                // outline font:
+                if (pfmFound == NULL)
+                {
+                    // no bitmap font found yet:
+
+                    /*
+                        #define FATTR_SEL_ITALIC               0x0001
+                        #define FATTR_SEL_UNDERSCORE           0x0002
+                        #define FATTR_SEL_OUTLINE              0x0008
+                        #define FATTR_SEL_STRIKEOUT            0x0010
+                        #define FATTR_SEL_BOLD                 0x0020
+                     */
+
+                    if (    (!fFamily)          // face mode is OK always
+                                                // V0.9.14 (2001-08-03) [umoeller]
+                         || (    (    (    (usFormat & FATTR_SEL_BOLD)
+                                        && (pfm2->usWeightClass == 7) // bold
+                                      )
+                                   || (    (!(usFormat & FATTR_SEL_BOLD))
+                                        && (pfm2->usWeightClass == 5) // regular
+                                      )
+                                 )
+                              && (    (    (usFormat & FATTR_SEL_ITALIC)
+                                        && (pfm2->sCharSlope != 0) // italics
+                                      )
+                                   || (    (!(usFormat & FATTR_SEL_ITALIC))
+                                        && (pfm2->sCharSlope == 0) // regular
+                                      )
+                                 )
+                            )
+                       )
+                    {
+                        // yes, we found a true font for that face:
+                        pfmFound = pfm2;
+
+                        // use this exact font for GpiCreateLogFont
+                        pfa->lMatch = pfm2->lMatch;
+
+                        // the following two might have been set
+                        // for a bitmap font above
+                        // V0.9.14 (2001-08-03) [umoeller]
+                        pfa->lMaxBaselineExt = pfm2->lMaxBaselineExt;
+                        pfa->lAveCharWidth = pfm2->lAveCharWidth;
+
+                        pfa->idRegistry = pfm2->idRegistry;
+
+                        // override NOMIX // V0.9.14 (2001-08-03) [umoeller]
+                        pfa->fsFontUse = FATTR_FONTUSE_OUTLINE;
+
+                        // according to GPIREF, we must also specify
+                        // the full face name... geese!
+                        strcpy(pfa->szFacename, pfm2->szFacename);
+                        // unset flag in FATTRS, because this would
+                        // duplicate bold or italic
+                        pfa->fsSelection = 0;
+
+                        // _Pmpf(("    --> using it"));
+                        // but loop on, because we might have a bitmap
+                        // font which should take priority
+                    }
+                }
+        }
+
+        pfm2++;
+    }
+
+    if (pfmFound)
+        // FONTMETRICS found:
+        // copy font metrics?
+        if (pFontMetrics)
+            memcpy(pFontMetrics, pfmFound, sizeof(FONTMETRICS));
+
+    // free the FONTMETRICS array
+    free(pfm);
+
+    return (pfmFound != NULL);
+}
+
+/*
  *@@ gpihSplitPresFont:
  *      splits a presentation parameter font
@@ -746,28 +998,38 @@
 
 /*
+ *@@ gpihCreateFont:
+ *
+ *@@added V0.9.14 (2001-08-03) [umoeller]
+ */
+
+LONG gpihCreateFont(HPS hps,
+                    FATTRS *pfa)
+{
+    LONG lLCIDReturn = 0;
+
+    if (gpihLockLCIDs())        // V0.9.9 (2001-04-01) [umoeller]
+    {
+        // new logical font ID: last used plus one
+        lLCIDReturn = gpihQueryNextFontID(hps);
+
+        GpiCreateLogFont(hps,
+                         NULL,  // don't create "logical font name" (STR8)
+                         lLCIDReturn,
+                         pfa);
+
+        gpihUnlockLCIDs();
+    }
+
+    return (lLCIDReturn);
+}
+
+/*
  *@@ gpihFindFont:
  *      this returns a new logical font ID (LCID) for the specified
- *      font by calling GpiCreateLogFont.
- *      This function performs the insane "11-step process" to
- *      match a font, as described in the GPI reference.
- *
- *      This function can operate in two modes:
- *
- *      -- "Family" mode. In that case, specify the font family name
- *         with pszName and set fFamily to TRUE. This is useful for
- *         WYSIWYG text viewing if you need several font faces for
- *         the same family, such as Courier Bold, Bold Italics, etc.
- *         You can specify those attributes with usFormat then.
- *
- *      -- "Face" mode. In that case, specify the full font face name
- *         with pszName and set fFamily to FALSE. This is useful for
- *         font presentation parameters which use the "WarpSans Bold"
- *         format. In that case, set usFormat to 0.
- *
- *      After the font has been created, if (pFontMetrics != NULL),
- *      *pFontMetrics receives the FONTMETRICS of the font which
- *      has been created. If an outline font has been created
- *      (instead of a bitmap font), FONTMETRICS.fsDefn will have
- *      the FM_DEFN_OUTLINE bit set.
+ *      font by calling gpihMatchFont first and then
+ *      GpiCreateLogFont to create a logical font from the
+ *      data returned.
+ *
+ *      See gpihMatchFont for additional explanations.
  *
  *      To then use the font whose LCID has been returned by this
@@ -930,201 +1192,18 @@
                   PFONTMETRICS pFontMetrics) // out: font metrics of created font (optional)
 {
-    LONG    lLCIDReturn = 0;
-    ULONG   ul = 0;
     FATTRS  FontAttrs;
 
-    // first find out how much memory we need to allocate
-    // for the FONTMETRICS structures
-    LONG    lTemp = 0;
-    LONG    cFonts = GpiQueryFonts(hps,
-                                   QF_PUBLIC | QF_PRIVATE,
-                                   NULL, // pszFaceName,
-                                   &lTemp,
-                                   sizeof(FONTMETRICS),
-                                   NULL);
-    PFONTMETRICS    pfm = (PFONTMETRICS)malloc(cFonts * sizeof(FONTMETRICS)),
-                    pfm2 = pfm,
-                    pfmFound = NULL;
-
-    BOOL            fQueriedDevice = FALSE;     // V0.9.14 (2001-08-01) [umoeller]
-    LONG            alDevRes[2];            // device resolution
-
-    // _Pmpf(("gpihFindFont: enumerating for %s, %d points", pszFaceName, lSize));
-
-    GpiQueryFonts(hps,
-                  QF_PUBLIC | QF_PRIVATE,
-                  NULL, // pszFaceName,
-                  &cFonts,
-                  sizeof(FONTMETRICS),      // length of each metrics structure
-                                            // -- _not_ total buffer size!
-                  pfm);
-
-    // now we have an array of FONTMETRICS
-    // for EVERY font that is installed on the system...
-    // these things are completely unsorted, so there's
-    // nothing we can rely on, we have to check them all.
-
-    // fill in some default values for FATTRS,
-    // in case we don't find something better
-    // in the loop below; these values will be
-    // applied if
-    // a)   an outline font has been found;
-    // b)   bitmap fonts have been found, but
-    //      none for the current device resolution
-    //      exists;
-    // c)   no font has been found at all.
-    // In all cases, GpiCreateLogFont will do
-    // a "close match" resolution (at the bottom).
-    FontAttrs.usRecordLength = sizeof(FATTRS);
-    FontAttrs.fsSelection = usFormat; // changed later if better font is found
-    FontAttrs.lMatch = 0L;             // closest match
-    strcpy(FontAttrs.szFacename, pcszName);
-    FontAttrs.idRegistry = 0;          // default registry
-    FontAttrs.usCodePage = 0;          // default codepage
-    // the following two must be zero, or outline fonts
-    // will not be found; if a bitmap font has been passed
-    // to us, we'll modify these two fields later
-    FontAttrs.lMaxBaselineExt = 0;     // font size (height)
-    FontAttrs.lAveCharWidth = 0;       // font size (width)
-    FontAttrs.fsType = 0;              // default type
-    FontAttrs.fsFontUse = FATTR_FONTUSE_NOMIX;
-
-    // now go thru the array of FONTMETRICS
-    // to check if we have a bitmap font
-    // pszFaceName; the default WPS behavior
-    // is that bitmap fonts appear to take
-    // priority over outline fonts of the
-    // same name, so we check these first
-    pfm2 = pfm;
-    for (ul = 0;
-         ul < cFonts;
-         ul++)
-    {
-        /* _Pmpf(("  Checking font: %s (Fam: %s), %d, %d, %d",
-               pszFaceName,
-               pfm2->szFamilyname,
-               pfm2->sNominalPointSize,
-               pfm2->lMaxBaselineExt,
-               pfm2->lAveCharWidth)); */
-
-        const char *pcszCompare = (fFamily)
-                                     ? pfm2->szFamilyname
-                                     : pfm2->szFacename;
-
-        if (!strcmp(pcszCompare, pcszName))
-        {
-            /* _Pmpf(("  Found font %s; slope %d, usWeightClass %d",
-                    pfm2->szFacename,
-                    pfm2->sCharSlope,
-                    pfm2->usWeightClass)); */
-
-            if ((pfm2->fsDefn & FM_DEFN_OUTLINE) == 0)
-            {
-                // image (bitmap) font:
-                // check point size
-                if (pfm2->sNominalPointSize == lSize * 10)
-                {
-                    // OK: check device resolutions, because
-                    // normally, there are always several image
-                    // fonts for different resolutions
-                    // for bitmap fonts, there are always two versions:
-                    // one for low resolutions, one for high resolutions
-                    if (!fQueriedDevice)
-                    {
-                        DevQueryCaps(GpiQueryDevice(hps),
-                                     CAPS_HORIZONTAL_FONT_RES,
-                                     2L,
-                                     alDevRes);
-                        fQueriedDevice = TRUE;
-                    }
-
-                    if (    (pfm2->sXDeviceRes == alDevRes[0])
-                         && (pfm2->sYDeviceRes == alDevRes[1])
-                       )
-                    {
-                        // OK: use this for GpiCreateLogFont
-                        FontAttrs.lMaxBaselineExt = pfm2->lMaxBaselineExt;
-                        FontAttrs.lAveCharWidth = pfm2->lAveCharWidth;
-                        FontAttrs.lMatch = pfm2->lMatch;
-
-                        pfmFound = pfm2;
-                        break;
-                    }
-                }
-            }
-            else
-                // outline font:
-                if (pfmFound == NULL)
-                {
-                    /*
-                        #define FATTR_SEL_ITALIC               0x0001
-                        #define FATTR_SEL_UNDERSCORE           0x0002
-                        #define FATTR_SEL_OUTLINE              0x0008
-                        #define FATTR_SEL_STRIKEOUT            0x0010
-                        #define FATTR_SEL_BOLD                 0x0020
-                     */
-                    // no bitmap font found yet:
-                    if (  (     (   (usFormat & FATTR_SEL_BOLD)
-                                 && (pfm2->usWeightClass == 7) // bold
-                                )
-                            ||  (   (!(usFormat & FATTR_SEL_BOLD))
-                                 && (pfm2->usWeightClass == 5) // regular
-                                )
-                           )
-                        && (    (   (usFormat & FATTR_SEL_ITALIC)
-                                 && (pfm2->sCharSlope != 0) // italics
-                                )
-                            ||  (   (!(usFormat & FATTR_SEL_ITALIC))
-                                 && (pfm2->sCharSlope == 0) // regular
-                                )
-                           )
-                       )
-                    {
-                        // yes, we found a true font for that face:
-                        pfmFound = pfm2;
-                        // use this exact font for GpiCreateLogFont
-                        FontAttrs.lMatch = pfm2->lMatch;
-                        // according to GPIREF, we must also specify
-                        // the full face name... Jesus!
-                        strcpy(FontAttrs.szFacename, pfm2->szFacename);
-                        // unset flag in FATTRS, because this would
-                        // duplicate bold or italic
-                        FontAttrs.fsSelection = 0;
-
-                        // _Pmpf(("    --> using it"));
-                        // but loop on, because we might have a bitmap
-                        // font which should take priority
-                    }
-                }
-        }
-
-        pfm2++;
-    }
-
-    if (pfmFound)
-        // FONTMETRICS found:
-        // copy font metrics?
-        if (pFontMetrics)
-            memcpy(pFontMetrics, pfmFound, sizeof(FONTMETRICS));
-
-    // free the FONTMETRICS array
-    free(pfm);
-
-    if (gpihLockLCIDs())        // V0.9.9 (2001-04-01) [umoeller]
-    {
-        // new logical font ID: last used plus one
-        lLCIDReturn = gpihQueryNextFontID(hps);
-
-        GpiCreateLogFont(hps,
-                         NULL,  // don't create "logical font name" (STR8)
-                         lLCIDReturn,
-                         &FontAttrs);
-
-        gpihUnlockLCIDs();
-    }
+    gpihMatchFont(hps,
+                  lSize,
+                  fFamily,
+                  pcszName,
+                  usFormat,
+                  &FontAttrs,
+                  pFontMetrics);
+
+    return (gpihCreateFont(hps,
+                           &FontAttrs));
 
     // _Pmpf((__FUNCTION__ ": returning lcid %d", lLCIDReturn));
-
-    return (lLCIDReturn);
 }
 
@@ -1249,4 +1328,5 @@
  *
  *@@added V0.9.0 [umoeller]
+ *@@changed V0.9.14 (2001-08-03) [umoeller]: fixed bad rounding errors
  */
 
@@ -1255,4 +1335,5 @@
 {
     SIZEF   box;
+    HDC     hdc = GpiQueryDevice(hps);       // get the HDC from the HPS
     LONG    alDevRes[2];
     DevQueryCaps(GpiQueryDevice(hps),       // get the HDC from the HPS
@@ -1260,6 +1341,17 @@
                  2L,
                  alDevRes);
-    box.cx = MAKEFIXED((lPointSize * alDevRes[0]) / 72, 0);
-    box.cy = MAKEFIXED((lPointSize * alDevRes[1]) / 72, 0);
+
+    // V0.9.14: this code didn't work... it produced rounding
+    // errors which set the font size different from what
+    // it should be according to the WPS font palette
+    /* box.cx = MAKEFIXED((lPointSize * alDevRes[0]) / 72, 0);
+    box.cy = MAKEFIXED((lPointSize * alDevRes[1]) / 72, 0); */
+
+    // V0.9.14 (2001-08-03) [umoeller]: now using this one
+    // instead
+    lPointSize *= 65536;
+    box.cx = (FIXED)(lPointSize / 72 * alDevRes[0]);
+    box.cy = (FIXED)(lPointSize / 72 * alDevRes[1]);
+
     return (GpiSetCharBox(hps, &box));
 }
Index: trunk/src/helpers/stringh.c
===================================================================
--- trunk/src/helpers/stringh.c	(revision 93)
+++ trunk/src/helpers/stringh.c	(revision 94)
@@ -69,5 +69,5 @@
 
 /*
- *@@ strcpy:
+ *@@ strhcpy:
  *      like strdup, but this one doesn't crash if string2 is NULL,
  *      but sets the first byte in string1 to \0 instead.
