File:  [WindowsNT SDKs] / ntddk / src / print / pscript / header.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

//--------------------------------------------------------------------------
//
// Module Name:  HEADER.C
//
// Brief Description:  This module contains the PSCRIPT driver's header
// output functions and related routines.
//
// Author:  Kent Settle (kentse)
// Created: 26-Nov-1990
//
// Copyright (c) 1990-1993 Microsoft Corporation
//
// This routine contains routines to output the PostScript driver's header.
//--------------------------------------------------------------------------

#include "pscript.h"
#include "header.h"
#include "resource.h"
#include "enable.h"


extern HMODULE     ghmodDrv;    // GLOBAL MODULE HANDLE.
extern int NameComp(CHAR *, CHAR *);

BOOL bSendDeviceSetup(PDEVDATA);
VOID DownloadNTProcSet(PDEVDATA, BOOL);
VOID SetFormAndTray(PDEVDATA);

//--------------------------------------------------------------------------
// BOOL bOutputHeader(pdev)
// PDEVDATA    pdev;
//
// This routine sends the driver's header to the output channel.
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
// Returns:
//   This function returns TRUE if the header was successfully sent,
//   FALSE otherwise.
//
// History:
//   26-Nov-1990     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

BOOL  bOutputHeader(pdev)
PDEVDATA     pdev;
{
    CHAR            buf[128];
    CHAR           *pstr;
    WCHAR          *pwstr;
    DWORD           cTmp, i;
    BOOL            bDuplex;
    SYSTEMTIME      systime;
    DWORD           pbgr;
    PSRESOLUTION   *pRes;
    PNTPD           pntpd;

    // don't do anything if the header has already been sent to the printer.

    if (pdev->dwFlags & PDEV_PROCSET)
	return TRUE;

    // set the header sent flag.  this needs to be done before a call
    // to Print is made in order to keep from getting stuck in a loop.

    pdev->dwFlags |= PDEV_PROCSET;

    // if RAWDATA has already been sent to the printer, then we only want
    // to send down our ProcSet, and not the rest of the header, or any
    // of the device setup commands.

    if (pdev->dwFlags & PDEV_RAWDATASENT)
    {
        // define our procedure set, FALSE means don't even think
        // about defining the error handler..

        DownloadNTProcSet(pdev, FALSE);

        // output a save command for the first page.  this is done in the
        // header as part of the effort to avoid outputting two headers in
        // the raw data case.  FALSE means to perform a save and not a gsave.

        ps_save(pdev, FALSE);
        pdev->dwFlags |= PDEV_WITHINPAGE;

        return(TRUE);
    }

    // get a local pointer.

    pntpd = pdev->pntpd;

    // output the header comments.  NOTE, these comments conform to
    // Version 2.0 of the Adobe Structuring Conventions.

    // if the printer supports job switching, put the printer into
    // postscript mode now.

    if (pntpd->flFlags & PJL_PROTOCOL)
        PrintString(pdev, "\033%-12345X@PJL ENTER LANGUAGE=POSTSCRIPT\n");
    if (pntpd->flFlags & SIC_PROTOCOL)
    {
        // call directly to bPSWrite to output the necessary escape commands.
        // PrintString will NOT output '\000'.

        bPSWrite(pdev, "\033\133\113\030\000\006\061\010\000\000\000\000\000", 13);
        bPSWrite(pdev, "\000\000\000\000\000\000\000\000\004\033\133\113\003", 13);
        bPSWrite(pdev, "\000\006\061\010\004", 5);
    }

    //!!! output something different if Encapsulated PS.
    //!!! PrintString(pdev, "%!PS-Adobe-2.0 EPSF-2.0\n");

    PrintString(pdev, "%!PS-Adobe-2.0\n");

    // output the title of the document.

    if (pdev->pwstrDocName)
    {
//!!! need to output UNICODE document name???  -kentse.
//!!! for now just lop off top word.
        pstr = buf;
        pwstr = pdev->pwstrDocName;

        cTmp = min((sizeof(buf) - 1), wcslen(pwstr));

        while (cTmp--)
            *pstr++ = (CHAR)*pwstr++;

        // NULL terminate the document name.

        *pstr = '\0';

	PrintString(pdev, "%%Title: ");
	PrintString(pdev, buf);
	PrintString(pdev, "\n");
    }
    else
	PrintString(pdev, "%%Title: Untitled Document\n");

    // let the world know who we are.

    PrintString(pdev, "%%Creator: Windows NT 3.1\n");

    // print the date and time of creation.

    GetLocalTime(&systime);

    PrintString(pdev, "%%CreationDate: ");
    PrintDecimal(pdev, 1, systime.wHour);
    PrintString(pdev, ":");
    PrintDecimal(pdev, 1, systime.wMinute);
    PrintString(pdev, " ");
    PrintDecimal(pdev, 1, systime.wMonth);
    PrintString(pdev, "/");
    PrintDecimal(pdev, 1, systime.wDay);
    PrintString(pdev, "/");
    PrintDecimal(pdev, 1, systime.wYear);

    // mark the bounding box of the document.

    PrintString(pdev, "\n%%BoundingBox: ");
    PrintDecimal(pdev, 4, pdev->CurForm.imagearea.left,
                 pdev->CurForm.imagearea.bottom,
                 pdev->CurForm.imagearea.right,
		 pdev->CurForm.imagearea.top);

    PrintString(pdev, "\n%%DocumentProcSets: Windows_NT_3.1\n");
    PrintString(pdev, "%%DocumentSuppliedProcSets: Windows_NT_3.1\n");

    if (pdev->cCopies > 1)
    {
        PrintString(pdev, "%%Requirements: numcopies(");
        PrintDecimal(pdev, 1, pdev->cCopies);
        PrintString(pdev, ") collate\n");
    }

    // we are done with the comments portion of the document.

    PrintString(pdev, "%%EndComments\n");

    // define our procedure set.

    DownloadNTProcSet(pdev, TRUE);

    PrintString(pdev, "%%EndProlog\n");

    // do the device setup.

    PrintString(pdev, "%%BeginSetup\n");

    // send the resolution selection command, if necessary.

    if (pntpd->cResolutions > 0)
    {
        pRes = (PSRESOLUTION *)((CHAR *)pntpd + pntpd->loResolution);

        // search each possible resolution until the specified one is
        // found.

        for (i = 0; i < (DWORD)pntpd->cResolutions; i++)
        {
            if (pRes[i].iValue == (DWORD)pdev->psdm.dm.dmPrintQuality)
            {
                PrintString(pdev, "%%BeginFeature: *Resolution ");
                PrintDecimal(pdev, 1, pdev->psdm.dm.dmPrintQuality);
                PrintString(pdev, "\n");
                PrintString(pdev, (CHAR *)pntpd + pRes[i].loInvocation);
                PrintString(pdev, "\n%%EndFeature\n");
            }
        }
    }

    // send form and tray selection commands.

    SetFormAndTray(pdev);

    // handle duplex if necessary.

    if ((pntpd->loszDuplexNone) ||
        (pntpd->loszDuplexNoTumble) ||
        (pntpd->loszDuplexTumble))
        bDuplex = TRUE;
    else
        bDuplex = FALSE;

    if (bDuplex)
    {
        if (pdev->psdm.dm.dmDuplex == DMDUP_HORIZONTAL)
        {
            if (pdev->psdm.dm.dmOrientation == DMORIENT_LANDSCAPE)
            {
                PrintString(pdev, "%%BeginFeature: *Duplex DuplexNoTumble\n");
                if (pntpd->loszDuplexNoTumble)
                    pstr = (char *)pntpd + pntpd->loszDuplexNoTumble;
            }
            else
            {
                PrintString(pdev, "%%BeginFeature: *Duplex DuplexTumble\n");
                if (pntpd->loszDuplexTumble)
                    pstr = (char *)pntpd + pntpd->loszDuplexTumble;
            }
        }
        else if (pdev->psdm.dm.dmDuplex == DMDUP_VERTICAL)
        {
            if (pdev->psdm.dm.dmOrientation == DMORIENT_LANDSCAPE)
            {
                PrintString(pdev, "%%BeginFeature: *Duplex DuplexTumble\n");
                if (pntpd->loszDuplexTumble)
                    pstr = (char *)pntpd + pntpd->loszDuplexTumble;
            }
            else
            {
                PrintString(pdev, "%%BeginFeature: *Duplex DuplexNoTumble\n");
                if (pntpd->loszDuplexNoTumble)
                    pstr = (char *)pntpd + pntpd->loszDuplexNoTumble;
            }
        }
        else // turn duplex off.
        {
            PrintString(pdev, "%%BeginFeature: *Duplex None\n");
            if (pntpd->loszDuplexNone)
                pstr = (char *)pntpd + pntpd->loszDuplexNone;
        }

        PrintString(pdev, pstr);
        PrintString(pdev, "\n%%EndFeature\n");
    }

    // handle collation if the device supports it.

    if (pntpd->loszCollateOn && pntpd->loszCollateOff)
    {
        if (pdev->psdm.dm.dmCollate = DMCOLLATE_TRUE)
        {
            PrintString(pdev, "%%BeginFeature: *Collate True\n");
            pstr = (char *)pntpd + pntpd->loszCollateOn;
        }
        else
        {
            PrintString(pdev, "%%BeginFeature: *Collate False\n");
            pstr = (char *)pntpd + pntpd->loszCollateOff;
        }

        PrintString(pdev, pstr);
        PrintString(pdev, "\n%%EndFeature\n");
    }

    if (pdev->cCopies > 1)
    {
        PrintString(pdev, "/#copies ");
        PrintDecimal(pdev, 1, pdev->cCopies);
        PrintString(pdev, " def\n");
    }

    PrintString(pdev, "%%EndSetup\n%%Page: 1 1\n%%BeginPageSetup\n");

    // the form / tray information has already been sent for the first page.

    pdev->dwFlags &= ~PDEV_CHANGEFORM;

    bSendDeviceSetup(pdev);

    PrintString(pdev, "%%EndPageSetup\n");

    // output a save command for the first page.  this is done in the
    // header as part of the effort to avoid outputting two headers in
    // the raw data case.  FALSE means to perform a save and not a gsave.

    ps_save(pdev, FALSE);
    pdev->dwFlags |= PDEV_WITHINPAGE;

    if (pdev->psdm.dwFlags & PSDEVMODE_NEG)
    {
        // fill the entire imageable area with white, which will get
        // transformed to black.  then restore the color to black.

        pbgr = RGB_WHITE;
        ps_setrgbcolor(pdev, (BGR_PAL_ENTRY *)&pbgr);

        PrintDecimal(pdev, 4, 0,
                     (pdev->CurForm.imagearea.left * pdev->psdm.dm.dmScale) / 100,
                     (pdev->CurForm.sizlPaper.cy -
                     ((pdev->CurForm.imagearea.top * pdev->psdm.dm.dmScale) / 100)),
                     (pdev->CurForm.imagearea.right * pdev->psdm.dm.dmScale) / 100,
                     (pdev->CurForm.sizlPaper.cy -
                     ((pdev->CurForm.imagearea.bottom * pdev->psdm.dm.dmScale) / 100)));

        PrintString(pdev, " box\n");
        pdev->cgs.dwFlags |= CGS_PATHEXISTS;

        ps_fill(pdev, (FLONG)FP_WINDINGMODE);
        pbgr = RGB_BLACK;
        ps_setrgbcolor(pdev, (BGR_PAL_ENTRY *)&pbgr);
    }

    pdev->dwFlags |= PDEV_COMPLETEHEADER;

    return(TRUE);
}


//--------------------------------------------------------------------------
// BOOL bSendDeviceSetup(pdev)
// PDEVDATA    pdev;
//
// This routine sends the driver's device setup section of the header
// to the output channel.
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
// Returns:
//   This function returns TRUE if the header was successfully sent,
//   FALSE otherwise.
//
// History:
//   26-Nov-1990     -by-     Kent Settle     (kentse)
//  Wrote it.
//--------------------------------------------------------------------------

BOOL bSendDeviceSetup(pdev)
PDEVDATA    pdev;
{
    PSTR    pstr;
    PNTPD   pntpd;

    // set up for new form if necessary.

    if (pdev->dwFlags & PDEV_CHANGEFORM)
    {
        SetFormAndTray(pdev);
        pdev->dwFlags &= ~PDEV_CHANGEFORM;
    }

    pntpd = pdev->pntpd;

    // rotate and translate if we are in landscape mode.

    if (pdev->psdm.dm.dmOrientation == DMORIENT_LANDSCAPE)
    {
#ifdef LANDSCAPE_270_ROTATE
        PrintString(pdev, "270 rotate ");
        PrintDecimal(pdev, 2, -pdev->CurForm.sizlPaper.cx, 0);
        PrintString(pdev, " translate\n");
#else   // 90 degree rotation case.
        PrintString(pdev, "90 rotate ");
        PrintDecimal(pdev, 2, 0, -pdev->CurForm.sizlPaper.cy);
        PrintString(pdev, " translate\n");
#endif
    }

    // this implementation of mirror imaging is to simply flip over the
    // x axis.  ie, the image is reversed in the horizontal direction.
    //!!! perhaps at some point we will want to allow flipping in the
    //!!! vertical direction as well.  -kentse.

    if (pdev->psdm.dwFlags & PSDEVMODE_MIRROR)
    {
        PrintDecimal(pdev, 1, pdev->CurForm.sizlPaper.cx);
        PrintString(pdev, " 0 translate -1 1 scale\n");
    }

    // send the proper normalized transfer function, if one exists.
    // send the inverted transfer function if the PSDEVMODE_NEG
    // flag is set.

    if (pdev->psdm.dwFlags & PSDEVMODE_NEG)
    {
        // if an inverse normalized transfer function is defined for
        // this device, send it to the printer, else send the default
        // inverse transfer function.

        if (pntpd->loszInvTransferNorm)
        {
            pstr = (char *)pntpd + pntpd->loszInvTransferNorm;
            PrintString(pdev, pstr);
        }
        else // default inverse transfer function.
            PrintString(pdev, "{1 exch sub}");

        PrintString(pdev, " settransfer\n");
    }
    else
    {
        // send the normalized transfer function to the printer if
        // one exists for this printer.

        if (pntpd->loszTransferNorm)
        {
            pstr = (char *)pntpd + pntpd->loszTransferNorm;
            PrintString(pdev, pstr);
            PrintString(pdev, " settransfer\n");
        }
    }

    // set the default line width (8 / 1000th inch).

    pdev->cgs.psfxLineWidth = 0;    // force the linewidth to be set.
    ps_setlinewidth(pdev, PSFX_DEFAULT_LINEWIDTH);

    return(TRUE);
}

//--------------------------------------------------------------------
// BOOL bSendPSProcSet(pdev, ulPSid)
// PDEVDATA        pdev;
// ULONG           ulPSid;
//
// Routine Description:
//
// This routine will output the PS Procset Resource referenced by ulPSid
// to the PS Interpreter. See PSPROC.H for valid ids.
//
// Return Value:
//
//  FALSE if an error occurred.
//
// Author:
//
//  15-Feb-1993 created  -by-  Rob Kiesler
//
//
// Revision History:
//--------------------------------------------------------------------

BOOL bSendPSProcSet(pdev, ulPSid)
PDEVDATA    pdev;
ULONG       ulPSid;
{
    HANDLE  hRes;
    USHORT  usSize;
    HANDLE  hProcRes;
    PSZ     pntps;

    if (pdev->dwFlags & PDEV_CANCELDOC)
        return(TRUE);

    if (!(hRes = FindResource(ghmodDrv, MAKEINTRESOURCE(ulPSid),
				  MAKEINTRESOURCE(PSPROC))))
	{
	    RIP("PSCRIPT!bSendPSProcSet: Couldn't find proc set resource\n");
	    return(FALSE);
	}

	usSize = (USHORT)SizeofResource(ghmodDrv, hRes);

	//
    // Get the handle to the resource.
    //
	if (!(hProcRes = LoadResource(ghmodDrv, hRes)))
	{
	    RIP("PSCRIPT!bSendPSProcSet: LoadResource failed.\n");
	    return(FALSE);
	}

    //
	// Get a pointer to the resource data.
    //
	if (!(pntps = (PSZ) LockResource(hProcRes)))
	{
	    RIP("PSCRIPT!bSendPSProcSet: LockResource failed.\n");
	    FreeResource(hProcRes);
	    return(FALSE);
	}
    if (!bPSWrite(pdev, pntps, usSize))
	{
	    RIP("PSCRIPT!bSendPSProcSet: Output of Header failed.\n");
	    FreeResource(hProcRes);
	    return(FALSE);
	}

    FreeResource(hProcRes);
    bPSFlush(pdev);
    return(TRUE);
}


//--------------------------------------------------------------------------
// VOID DownloadNTProcSet(pdev, bEhandler)
// PDEVDATA    pdev;
// BOOL        bEhandler;
//
// This routine sends the driver's ProcSet to the output channel.
//
// Parameters:
//   pdev:
//     pointer to DEVDATA structure.
//
//   bEhandler:
//     TRUE if we should even consider sending the error handler,
//     otherwise FALSE.
//
// Returns:
//   This function returns no value.
//
// History:
//   11-May-1993     -by-     Kent Settle     (kentse)
//  Broke into a separate routine.
//--------------------------------------------------------------------------

VOID DownloadNTProcSet(pdev, bEhandler)
PDEVDATA    pdev;
BOOL        bEhandler;
{
    PSZ            *ppsz;

    // define our procedure set.

    PrintString(pdev, "%%BeginProcSet: Windows_NT_3.1\n");
    PrintString(pdev, "% Copyright (c) 1991 - 1993 Microsoft Corporation\n");

    // we need to define the true resolution of the printer.

    PrintString(pdev, "100 dict begin ");
    PrintString(pdev, "/DPI ");
    PrintDecimal(pdev, 1, pdev->psdm.dm.dmPrintQuality);
    PrintString(pdev, " def\n");

    PrintString(pdev, "/_snap {transform 36 DPI div sub round 36 DPI div add\n");
    PrintString(pdev, "exch 36 DPI div sub round 36 DPI div add exch itransform}bind def\n");

    // download our error handler if we are told to.

    if (bEhandler)
    {
        if (pdev->psdm.dwFlags & PSDEVMODE_EHANDLER)
        {
            ppsz = apszEHandler;
            while (*ppsz)
            {
                PrintString(pdev, (PSZ)*ppsz++);
                PrintString(pdev, "\n");
            }
        }
    }
    // download our procedure definitions code.

    ppsz = apszHeader;
    while (*ppsz)
    {
	PrintString(pdev, (PSZ)*ppsz++);
	PrintString(pdev, "\n");
    }

    PrintString(pdev, "%%EndProcSet\n");

    pdev->dwFlags |= PDEV_PROCSET;
}


VOID SetFormAndTray(pdev)
PDEVDATA    pdev;
{
    WCHAR           FormName[CCHFORMNAME];
    WCHAR          *pFormName;
    WCHAR          *pSlotName;
    WCHAR          *pPrinterForm;
    WCHAR           ManualName[MAX_SLOT_NAME];
    WCHAR           SearchName[MAX_SLOT_NAME];
    BOOL            bManual, bForm, bFound, bRegion;
    WCHAR          *pwstr;
    PSINPUTSLOT    *pSlot;
    DWORD           i;
    PSFORM         *pPSForm;
    PNTPD           pntpd;

    pntpd = pdev->pntpd;

    // select the paper tray.  do this by selecting the first tray
    // which contains the form in question.

    // get a unicode version of the form name.

    strcpy2WChar(FormName, pdev->CurForm.PrinterForm);

    // get the manual tray name.

    LoadString(ghmodDrv, (SLOT_MANUAL + SLOTS_BASE),
               ManualName, (sizeof(ManualName) / sizeof(ManualName[0])));

    // assume the form is not in manual feed.

    if (pdev->dwFlags & PDEV_MANUALFEED)
    {
        PrintString(pdev, "%%BeginFeature: *ManualFeed False\n");
        PrintString(pdev, (CHAR *)pntpd + pntpd->loszManualFeedFALSE);
        PrintString(pdev, "\n%%EndFeature\n");
        pdev->dwFlags &= ~PDEV_MANUALFEED;
    }

    bManual = FALSE;

    // we have the form name, now check the registry to see if this form
    // is in any of the paper trays.

    if (pdev->pTrayFormTable)
    {
        pwstr = pdev->pTrayFormTable;
        bForm = FALSE;

        while (*pwstr)
        {
            pSlotName = pwstr;
            pFormName = pSlotName + (wcslen(pSlotName) + 1);
            pPrinterForm = pFormName + (wcslen(pFormName) + 1);

            if (!(wcscmp(pPrinterForm, FormName)))
            {
                // we found the form question.  get the tray name.

                if (!(wcscmp(pSlotName, ManualName)))
                {
                    // the form is in the manual tray, but see if it is
                    // one of the other trays first.

                    bManual = TRUE;

                    pwstr = pPrinterForm + (wcslen(pPrinterForm) + 1);
                }
                else
                {
                    bForm = TRUE;
                    break;
                }
            }
            else
            {
                // this was not the form in question.  skip over the
                // tray-form triplet.

                pwstr = pPrinterForm + (wcslen(pPrinterForm) + 1);
            }
        }

        // if the tray-form pair was found, output the proper commands
        // to select the tray in question.

        bFound = FALSE;

        if (bForm)
        {
            // select the tray if there are multiple trays to select from.

            if (pntpd->cInputSlots > 0)
            {
                pSlot = (PSINPUTSLOT *)((CHAR *)pntpd + pntpd->loPSInputSlots);

                // get each slot name from the NTPD, and do a look up in the
                // registry to find the associated form name.

                for (i = 0; i < pntpd->cInputSlots; i++)
                {
                    strcpy2WChar(SearchName, (CHAR *)pntpd + pSlot->loSlotName);

                    if (!(wcscmp(pSlotName, SearchName)))
                    {
                        bFound = TRUE;
                        break;
                    }

                    pSlot++;
                }

                if (bFound)
                {
                    PrintString(pdev, "%%BeginFeature: *InputSlot ");
                    PrintString(pdev, (CHAR *)pntpd + pSlot->loSlotName);
                    PrintString(pdev, "\n");

                    PrintString(pdev, (CHAR *)pntpd + pSlot->loSlotInvo);
                    PrintString(pdev, "\n%%EndFeature\n");
                }
            }

        }

        // if the form was not found in one of the paper trays, and the printer
        // supports manual feed, see if the form is is the manual feed slot.

        if ((!bFound) && (pntpd->loszManualFeedTRUE != 0) && (bManual))
        {
            // the requested form is in the manual feed slot,
            // so select manual feed.

            PrintString(pdev, "%%BeginFeature: *ManualFeed True\n");
            PrintString(pdev, (CHAR *)pntpd + pntpd->loszManualFeedTRUE);
            PrintString(pdev, "\n%%EndFeature\n");
            pdev->dwFlags |= PDEV_MANUALFEED;
        }
    }

    // select the page region if we are also selecting from multiple
    // paper trays or manual feed, otherwise select page size.

    bRegion = FALSE;

    if ((pdev->dwFlags & PDEV_MANUALFEED) || (bFound))
        bRegion = TRUE;

    // check for the odd occurence where there are no PageRegions (WANG15FP.PPD).

    // find the PSFORM structure in the NTPD for the current form.

    pPSForm = (PSFORM *)((CHAR *)pntpd + pntpd->loPSFORMArray);

    if (!pntpd->cPageRegions)
        bRegion = FALSE;

    if (bRegion)
        PrintString(pdev, "%%BeginFeature: *PageRegion ");
    else
        PrintString(pdev, "%%BeginFeature: *PageSize ");

    PrintString(pdev, pdev->CurForm.PrinterForm);
    PrintString(pdev, "\n");

    pPSForm = (PSFORM *)((CHAR *)pntpd + pntpd->loPSFORMArray);

    for (i = 0; i < pntpd->cPSForms; i++)
    {
        if (!(NameComp((CHAR *)pdev->CurForm.PrinterForm,
                     (CHAR *)pntpd + pPSForm->loFormName)))
        {
            if (bRegion)
                PrintString(pdev, (CHAR *)pntpd + pPSForm->loRegionInvo);
            else
                PrintString(pdev, (CHAR *)pntpd + pPSForm->loSizeInvo);

            PrintString(pdev, "\n");
            break;
        }

        // point to the next PSFORM.

        pPSForm++;
    }

    PrintString(pdev, "%%EndFeature\n");
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.