
// __________________________________________________________
//
//                         w2k_cv.c
//         SBS Windows 2000 CodeView Decompiler V1.00
//                08-27-2000 Sven B. Schreiber
//                       sbs@orgon.com
// __________________________________________________________

#include "w2k_cv.h"

// =================================================================
// DISCLAIMER
// =================================================================

/*

This software is provided "as is" and any express or implied
warranties, including, but not limited to, the implied warranties of
merchantability and fitness for a particular purpose are disclaimed.
In no event shall the author Sven B. Schreiber be liable for any
direct, indirect, incidental, special, exemplary, or consequential
damages (including, but not limited to, procurement of substitute
goods or services; loss of use, data, or profits; or business
interruption) however caused and on any theory of liability,
whether in contract, strict liability, or tort (including negligence
or otherwise) arising in any way out of the use of this software,
even if advised of the possibility of such damage.

*/

// =================================================================
// REVISION HISTORY
// =================================================================

/*

08-27-2000 V1.00 Original version (SBS).

*/

// =================================================================
// GLOBAL STRINGS
// =================================================================

TBYTE atArguments   [] =
 T("{ [+-hedcpPfmstx] <module> }");

TBYTE atMoreInfo    [] =
 T("\r\n")
 T("       +   enable subsequent options\r\n")
 T("       -   disable subsequent options\r\n")
 T("       h   display PE section headers\r\n")
 T("       e   display exported symbols\r\n")
 T("       d   display debug directories\r\n")
 T("       c   display CodeView data\r\n")
 T("       p   display public symbols\r\n")
 T("       P   display public symbols (extended information)\r\n")
 T("       f   display frame pointer omission (FPO) data\r\n")
 T("       m   display miscellaneous data\r\n")
 T("       s   display OMAP source table\r\n")
 T("       t   display OMAP target table\r\n")
 T("       x   display all of the above\r\n");

// -----------------------------------------------------------------

TBYTE atSeparator   [] =
 T("----------------------------------------")
 T("---------------------------------------\r\n");

TBYTE atSections    [] =
 T("\r\n%lu PE file section%s\r\n\r\n")
 T("     #  Name     Source   Target   Size     Raw Size\r\n")
 T("\0\0s\0\r\nNo PE file sections\r\n");

TBYTE atExports     [] =
 T("\r\n%lu exported symbol%s\r\n\r\n")
 T("     #  Symbol\r\n")
 T("\0\0s\0\r\nNo exported symbols\r\n");

TBYTE atDirectories [] =
 T("\r\n%lu debug director%s\r\n\r\n")
 T("     #  Address  Size     Type     Description\r\n")
 T("\0y\0ies\0\r\nNo debug directories\r\n");

TBYTE atSegments    [] =
 T("\r\n%lu CodeView NB09 segment%s (%hu logical)\r\n\r\n")
 T("     # Frame Offset   Size     Flags\r\n")
 T("\0\0s\0\r\nNo NB09 segments\r\n");

TBYTE atCodeView09  [] =
 T("\r\n%lu CodeView NB09 directory entr%s\r\n\r\n")
 T("     #  Offset   Size     Type Index Name\r\n")
 T("\0y\0ies\0\r\nNo CodeView NB09 directory entries\r\n");

TBYTE atCodeView10  [] =
 T("\r\n%lu CodeView NB10 byte%s\r\n\r\n")
 T("     #  Member     Value\r\n")
 T("\0\0s\0");

TBYTE atCodeViewXX  [] =
 T("\r\n%lu CodeView byte%s (%hc%hc%hc%hc)\r\n\r\n")
 T("Offset  ")
 T(" | 00 01 02 03 04 05 06 07 : 08 09 0A 0B 0C 0D 0E 0F")
 T(" | 0123456789ABCDEF\r\n")
 T("\0\0s\0\r\nNo CodeView data\r\n");

TBYTE atSymbols     [] =
 T("\r\n%lu symbol%s (%hc%hc%hc%hc)\r\n\r\n")
 T("     #  Section  Address  Symbol\r\n")
 T("\0\0s\0\r\nNo symbols\r\n");

TBYTE atSymbolsEx   [] =
 T("\r\n%lu symbol%s (%hc%hc%hc%hc)\r\n\r\n")
 T("     #  Section  Raw      Source   Target   Address  ")
 T("  Offset    Stack X Symbol\r\n")
 T("\0\0s\0\r\nNo symbols\r\n");

TBYTE atFpoEntries   [] =
 T("\r\n%lu FPO entr%s\r\n\r\n")
 T("     #  Address  Size     Locals   Args\r\n")
 T("\0y\0ies\0\r\nNo FPO entries\r\n");

TBYTE atMiscEntries  [] =
 T("\r\n%lu miscellaneous entr%s\r\n\r\n")
 T("     #  Type     Size     Data\r\n")
 T("\0y\0ies\0\r\nNo miscellaneous entries\r\n");

TBYTE atOmapFromSrc  [] =
 T("\r\n%lu OMAP source entr%s\r\n\r\n")
 T("     #  Source   Target\r\n")
 T("\0y\0ies\0\r\nNo OMAP source entries\r\n");

TBYTE atOmapToSrc    [] =
 T("\r\n%lu OMAP target entr%s\r\n\r\n")
 T("     #  Target   Source\r\n")
 T("\0y\0ies\0\r\nNo OMAP target entries\r\n");

// =================================================================
// PRIMITIVE DISPLAY ROUTINES
// =================================================================

VOID DisplaySeparator (VOID)
    {
    printf  (atSeparator);
    return;
    }

// -----------------------------------------------------------------

VOID DisplayTop (PTBYTE ptFormat,
                 DWORD  dCount,
                 PTBYTE ptSuffix,
                 ...)
    {
    PVOID  pArguments = &dCount;
    PTBYTE ptText     = ptFormat;

    ptText += lstrlen (ptText) + 1;

    if (dCount != 1)
        {
        ptText += lstrlen (ptText) + 1;
        }
    if (dCount == -1)
        {
        ptText += lstrlen (ptText) + 1;
        printf (ptText);
        }
    else
        {
        ((PTBYTE *) pArguments) [1] = ptText;
        vprintf (ptFormat, pArguments);

        DisplaySeparator ();
        }
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayTime (PTBYTE ptFormat,
                         DWORD  dTime)
    {
    TBYTE    atTime [] = T("mm-dd-yyyy HH:MM:SS");
    IMG_TIME it        = imgTimeUnpack (dTime);

    sprintf (atTime, T("%02lu-%02lu-%04lu %02lu:%02lu:%02lu"),
            (DWORD) it.bMonth,
            (DWORD) it.bDay,
            (DWORD) it.wYear,
            (DWORD) it.bHour,
            (DWORD) it.bMinute,
            (DWORD) it.bSecond);

    printf (ptFormat, atTime);
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayOmfName (POMF_NAME pon)
    {
    DWORD i;

    for (i = 0; i < pon->bLength; i++)
        {
        printf (T("%hc"),
                pon->abName [i]);
        }
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplaySectionName (PIMG_INFO pii,
                                DWORD     dSection)
    {
    DWORD                 i, j;
    PIMAGE_SECTION_HEADER pish = pii->pSections + (dSection-1);

    for (i = j = 0; i < IMAGE_SIZEOF_SHORT_NAME; i++)
        {
        printf (T("%hc"),
                (pish->Name [j] ? pish->Name [j++] : ' '));
        }
    return;
    }

// =================================================================
// COMPLEX DISPLAY ROUTINES
// =================================================================

VOID WINAPI DisplaySections (PIMG_INFO pii)
    {
    DWORD i;

    if (pii->dSections)
        {
        DisplayTop (atSections, pii->dSections, NULL);

        for (i = 0; i < pii->dSections; i++)
            {
            printf (T("%6lu: "), i+1);

            DisplaySectionName (pii, i+1);

            printf (T(" %08lX %08lX %08lX %08lX\r\n"),
                    pii->pSections [i].PointerToRawData,
                    pii->pSections [i].VirtualAddress,
                    pii->pSections [i].Misc.VirtualSize,
                    pii->pSections [i].SizeOfRawData);
            }
        }
    else
        {
        DisplayTop (atSections, -1, NULL);
        }
    DisplaySeparator ();
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayExports (PIMG_INFO pii)
    {
    DWORD i, j;

    if (pii->dExports)
        {
        DisplayTop (atExports, pii->dExports, NULL);

        for (i = j = 0; i < pii->dExports; i++)
            {
            printf (T("%6lu: %hs\r\n"),
                    i+1,
                    pii->pbExports + j);

            j += (lstrlenA (pii->pbExports + j) + 1);
            }
        }
    else
        {
        DisplayTop (atExports, -1, NULL);
        }
    DisplaySeparator ();
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayDirectories (PIMG_INFO pii)
    {
    DWORD i;

    if (pii->dDirectories)
        {
        DisplayTop (atDirectories, pii->dDirectories, NULL);

        for (i = 0; i < pii->dDirectories; i++)
            {
            printf (T("%6lu: %08lX %08lX %08lX %s\r\n"),
                    i+1,
                    pii->pDirectories [i].PointerToRawData,
                    pii->pDirectories [i].SizeOfData,
                    pii->pDirectories [i].Type,
                    imgInfoType (pii, i));
            }
        }
    else
        {
        DisplayTop (atDirectories, -1, NULL);
        }
    DisplaySeparator ();
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayNB09Segments (PIMG_INFO pii,
                                 PCV_NB09  pc09)
    {
    PCV_SEGMAP pcs;
    DWORD      dCount, i;

    if ((pcs = imgCvSegments (pc09, &dCount)) != NULL)
        {
        DisplayTop (atSegments, dCount, NULL, pcs->wLogical);

        for (i = 0; i < dCount; i++)
            {
            printf (T("%6lu: %04hX %08lX %08lX %04hX\r\n"),
                    i+1,
                    pcs->Descriptors [i].wFrame,
                    pcs->Descriptors [i].dOffset,
                    pcs->Descriptors [i].dSize,
                    pcs->Descriptors [i].wFlags);
            }
        }
    else
        {
        DisplayTop (atSegments, -1, NULL);
        }
    DisplaySeparator ();
    return;
    }


// -----------------------------------------------------------------

VOID WINAPI DisplayNB09Data (PIMG_INFO pii,
                             PCV_NB09  pc09,
                             DWORD     dSize)
    {
    DWORD      i, j;
    PCV_MODULE pcm;

    if (pc09->Directory.dEntries)
        {
        DisplayTop (atCodeView09, pc09->Directory.dEntries, NULL);

        for (i = j = 0; i < pc09->Directory.dEntries; i++)
            {
            printf (T("%6lu: %08lX %08lX %04hX %04hX "),
                    i+1,
                    pc09->Entries [i].lSubSectionOffset,
                    pc09->Entries [i].dSubSectionSize,
                    pc09->Entries [i].wSubSectionType,
                    pc09->Entries [i].wModuleIndex);

            if ((pc09->Entries [i].wSubSectionType == sstModule) &&
                ((pcm = imgCvModule (pc09, j++, NULL)) != NULL))
                {
                printf (T(" "));
                DisplayOmfName (CV_MODULE_NAME (pcm));
                }
            printf (T("\r\n"));
            }
        DisplaySeparator ();
        DisplayNB09Segments (pii, pc09);
        }
    else
        {
        DisplayTop (atCodeView09, -1, NULL);
        DisplaySeparator ();
        }
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayNB10Data (PIMG_INFO pii,
                             PCV_NB10  pc10,
                             DWORD     dSize)
    {
    DisplayTop (atCodeView10, dSize, NULL);

    DisplayTime (T("     1: Signature  %s\r\n"),
                 pc10->dSignature);

    printf      (T("     2: Age        %08lX\r\n"),
                 pc10->dAge);

    printf      (T("     3: PDB name   %hs\r\n"),
                 pc10->abPdbName);

    DisplaySeparator ();
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayNBXXData (PIMG_INFO  pii,
                             PCV_HEADER pch,
                             DWORD      dSize)
    {
    DWORD i, j, k, n;

    DisplayTop (atCodeViewXX, dSize, NULL,
                pch->Signature.abText [0],
                pch->Signature.abText [1],
                pch->Signature.abText [2],
                pch->Signature.abText [3]);

    n = (((dSize - 1) / 16) + 1) * 16;

    for (i = 0; i < n; i += 16)
        {
        printf (T("%08lX | "), i);

        for (j = i; j < i + 16; j++)
            {
            if ((j & 0xF) == 8)
                {
                printf (T(": "));
                }
            if (j < dSize)
                {
                k = ((PBYTE) pch) [j];
                printf (T("%02lX "), k);
                }
            else
                {
                printf (T("   "));
                }
            }
        printf (T("| "));

        for (j = i; j < i + 16; j++)
            {
            if (j < dSize)
                {
                k = ((PBYTE) pch) [j];

                if ((k >= 0x20) && (k != 0x7F))
                    {
                    printf (T("%c"), k);
                    }
                else
                    {
                    printf (T("."));
                    }
                }
            }
        printf (T("\r\n"));
        }
    DisplaySeparator ();
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayCvData (PIMG_INFO pii)
    {
    if (pii->dCvData >= CV_HEADER_)
        {
        switch (pii->pCvData->Header.Signature.dVersion)
            {
            case CV_SIGNATURE_NB09:
                {
                DisplayNB09Data (pii, &pii->pCvData->NB09,
                                 pii->dCvData);
                break;
                }
            case CV_SIGNATURE_NB10:
                {
                DisplayNB10Data (pii, &pii->pCvData->NB10,
                                 pii->dCvData);
                break;
                }
            default:
                {
                DisplayNBXXData (pii, &pii->pCvData->Header,
                                 pii->dCvData);
                break;
                }
            }
        }
    else
        {
        DisplayTop (atCodeViewXX, -1, NULL);
        DisplaySeparator ();
        }
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplaySymbols (PIMG_INFO pii)
    {
    PIMG_PUBSYM pip, pip1;
    IMG_SYMBOL  is;
    DWORD       dCount, dSize, dVersion, dIndex;

    if ((pip = imgInfoSymbols (pii, &dCount, &dSize, &dVersion))
        != NULL)
        {
        DisplayTop (atSymbols, dCount, NULL,
                    ((PCV_SIGNATURE) &dVersion)->abText [0],
                    ((PCV_SIGNATURE) &dVersion)->abText [1],
                    ((PCV_SIGNATURE) &dVersion)->abText [2],
                    ((PCV_SIGNATURE) &dVersion)->abText [3]);

        dIndex = 0;
        pip1   = pip;

        while (dIndex < dCount)
            {
            if (imgSymbolTest (pip1))
                {
                imgSymbolInfo (pip1, pii, &is, TRUE);

                printf (T("%6lu: "), dIndex+1);

                if (is.dSection &&
                    (is.dSection <= pii->dSections))
                    {
                    DisplaySectionName (pii, is.dSection);
                    }
                else
                    {
                    printf (T("[#%04hX] "), is.dSection);
                    }
                printf (T(" %08lX %hs\r\n"),
                        is.pAddress, is.abName);

                dIndex++;
                }
            pip1 = imgSymbolNext (pip1);
            }
        imgMemoryDestroy (pip);
        }
    else
        {
        DisplayTop (atSymbols, -1, NULL);
        }
    DisplaySeparator ();
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplaySymbolsEx (PIMG_INFO pii)
    {
    PIMG_PUBSYM pip, pip1;
    IMG_SYMBOL  is;
    DWORD       dCount, dSize, dVersion, dIndex;

    if ((pip = imgInfoSymbols (pii, &dCount, &dSize, &dVersion))
        != NULL)
        {
        DisplayTop (atSymbolsEx, dCount, NULL,
                    ((PCV_SIGNATURE) &dVersion)->abText [0],
                    ((PCV_SIGNATURE) &dVersion)->abText [1],
                    ((PCV_SIGNATURE) &dVersion)->abText [2],
                    ((PCV_SIGNATURE) &dVersion)->abText [3]);

        dIndex = 0;
        pip1   = pip;

        while (dIndex < dCount)
            {
            if (imgSymbolTest (pip1))
                {
                imgSymbolInfo (pip1, pii, &is, TRUE);

                printf (T("%6lu: "), dIndex+1);

                if (is.dSection &&
                    (is.dSection <= pii->dSections))
                    {
                    DisplaySectionName (pii, is.dSection);
                    }
                else
                    {
                    printf (T("[#%04hX] "), is.dSection);
                    }
                printf (T(" %08lX %08lX %08lX %08lX %8lX "),
                        is.dRaw,     is.dSource, is.dTarget,
                        is.pAddress, is.dOffset);

                if (is.dStack != -1)
                    {
                    printf (T("%8lX "), is.dStack);
                    }
                else
                    {
                    printf (T("         "));
                    }
                printf (T("%c %hs\r\n"),
                        (imgSymbolExported (pip1, pii) ? '*' : ' '),
                        is.abName);

                dIndex++;
                }
            pip1 = imgSymbolNext (pip1);
            }
        imgMemoryDestroy (pip);
        }
    else
        {
        DisplayTop (atSymbols, -1, NULL);
        }
    DisplaySeparator ();
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayFpoEntries (PIMG_INFO pii)
    {
    DWORD i;

    if (pii->dFpoEntries)
        {
        DisplayTop (atFpoEntries, pii->dFpoEntries, NULL);

        for (i = 0; i < pii->dFpoEntries; i++)
            {
            printf (T("%6lu: %08lX %08lX %08lX %04hX\r\n"),
                    i+1,
                    pii->pFpoEntries [i].ulOffStart,
                    pii->pFpoEntries [i].cbProcSize,
                    pii->pFpoEntries [i].cdwLocals,
                    pii->pFpoEntries [i].cdwParams);
            }
        }
    else
        {
        DisplayTop (atFpoEntries, -1, NULL);
        }
    DisplaySeparator ();
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayMiscEntries (PIMG_INFO pii)
    {
    DWORD i;

    if (pii->dMiscEntries)
        {
        DisplayTop (atMiscEntries, pii->dMiscEntries, NULL);

        for (i = 0; i < pii->dMiscEntries; i++)
            {
            printf ((pii->pMiscEntries [i].Unicode
                     ? T("%6lu: %08lX %08lX %ls\r\n")
                     : T("%6lu: %08lX %08lX %hs\r\n")),
                    i+1,
                    pii->pMiscEntries [i].DataType,
                    pii->pMiscEntries [i].Length,
                    pii->pMiscEntries [i].Data);
            }
        }
    else
        {
        DisplayTop (atMiscEntries, -1, NULL);
        }
    DisplaySeparator ();
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayOmapFromSrc (PIMG_INFO pii)
    {
    DWORD i, j;

    if (pii->dOmapFromSrc)
        {
        DisplayTop (atOmapFromSrc, pii->dOmapFromSrc, NULL);

        for (i = j = 0; i < pii->dOmapFromSrc; i++)
            {
            printf (T("%6lu: %08lX %08lX\r\n"),
                    i+1,
                    pii->pOmapFromSrc [i].dSource,
                    pii->pOmapFromSrc [i].dTarget);

            if (!pii->pOmapFromSrc [i].dTarget) j++;
            }
        DisplaySeparator ();

        printf (T("%6lu entr%s mapped to zero\r\n"),
                j, (j == 1 ? T("y") : T("ies")));
        }
    else
        {
        DisplayTop (atOmapFromSrc, -1, NULL);
        DisplaySeparator ();
        }
    return;
    }

// -----------------------------------------------------------------

VOID WINAPI DisplayOmapToSrc (PIMG_INFO pii)
    {
    DWORD i, j;

    if (pii->dOmapToSrc)
        {
        DisplayTop (atOmapToSrc, pii->dOmapToSrc, NULL);

        for (i = j = 0; i < pii->dOmapToSrc; i++)
            {
            printf (T("%6lu: %08lX %08lX\r\n"),
                    i+1,
                    pii->pOmapToSrc [i].dTarget,
                    pii->pOmapToSrc [i].dSource);

            if (!pii->pOmapToSrc [i].dSource) j++;
            }
        DisplaySeparator ();

        printf (T("%6lu entr%s mapped to zero\r\n"),
                j, (j == 1 ? T("y") : T("ies")));
        }
    else
        {
        DisplayTop (atOmapToSrc, -1, NULL);
        DisplaySeparator ();
        }
    return;
    }

// =================================================================
// MODULE HANDLER
// =================================================================

void WINAPI DisplayModule (PTBYTE ptModule,
                           DWORD  dOptions)
    {
    TBYTE     atPath [MAX_PATH];
    PVOID     pBase;
    PIMG_INFO pii;

    pBase = imgModuleBase (ptModule);

    if (imgPathDbg (ptModule, atPath, MAX_PATH) &&
        ((pii = imgInfoLoad (atPath, pBase)) != NULL))
        {
        printf (T("\r\nModule name:  %s")
                T("\r\nModule base:  %08lX%s")
                T("\r\nSymbol file:  %s\r\n"),
                ptModule, pii->pBase,
                (pBase != NULL ? T("") : T(" (not resident)")),
                pii->atPath);

        if (dOptions & OPTION_SECTIONS   ) DisplaySections    (pii);
        if (dOptions & OPTION_EXPORTS    ) DisplayExports     (pii);
        if (dOptions & OPTION_DIRECTORIES) DisplayDirectories (pii);
        if (dOptions & OPTION_CODEVIEW   ) DisplayCvData      (pii);
        if (dOptions & OPTION_PUBSYM     ) DisplaySymbols     (pii);
        if (dOptions & OPTION_PUBSYM_EX  ) DisplaySymbolsEx   (pii);
        if (dOptions & OPTION_FPO        ) DisplayFpoEntries  (pii);
        if (dOptions & OPTION_MISC       ) DisplayMiscEntries (pii);
        if (dOptions & OPTION_SOURCE     ) DisplayOmapFromSrc (pii);
        if (dOptions & OPTION_TARGET     ) DisplayOmapToSrc   (pii);

        imgMemoryDestroy   (pii);
        }
    else
        {
        printf (T("\r\nNo symbol file available for %s\r\n"),
                ptModule);
        }
    return;
    }

// =================================================================
// MAIN PROGRAM
// =================================================================

DWORD Main (DWORD argc, PTBYTE *argv, PTBYTE *argp)
    {
    DWORD dOption, dOptions, i, j;
    BOOL  fPlus;

    printf (atAbout);

    if (argc < 2)
        {
        printf (atUsage, atArguments);
        printf (atMoreInfo);
        }
    else
        {
        dOptions = OPTION_DEFAULT;

        for (i = 1; i < argc; i++)
            {
            switch (argv [i] [0])
                {
                default:
                    {
                    DisplayModule (argv [i], dOptions);
                    break;
                    }
                case '+':
                case '-':
                    {
                    for (j = 0; argv [i] [j]; j++)
                        {
                        dOption = 0;

                        switch (argv [i] [j])
                            {
                            case '+':
                                {
                                fPlus = TRUE;
                                break;
                                }
                            case '-':
                                {
                                fPlus = FALSE;
                                break;
                                }
                            case 'h':
                            case 'H':
                                {
                                dOption = OPTION_SECTIONS;
                                break;
                                }
                            case 'e':
                            case 'E':
                                {
                                dOption = OPTION_EXPORTS;
                                break;
                                }
                            case 'd':
                            case 'D':
                                {
                                dOption = OPTION_DIRECTORIES;
                                break;
                                }
                            case 'c':
                            case 'C':
                                {
                                dOption = OPTION_CODEVIEW;
                                break;
                                }
                            case 'p':
                                {
                                dOption = OPTION_PUBSYM;
                                break;
                                }
                            case 'P':
                                {
                                dOption = OPTION_PUBSYM_EX;
                                break;
                                }
                            case 'f':
                            case 'F':
                                {
                                dOption = OPTION_FPO;
                                break;
                                }
                            case 'm':
                            case 'M':
                                {
                                dOption = OPTION_MISC;
                                break;
                                }
                            case 's':
                            case 'S':
                                {
                                dOption = OPTION_SOURCE;
                                break;
                                }
                            case 't':
                            case 'T':
                                {
                                dOption = OPTION_TARGET;
                                break;
                                }
                            case 'x':
                            case 'X':
                                {
                                dOption = OPTION_ALL;
                                break;
                                }
                            }
                        if (dOption)
                            {
                            if (fPlus) dOptions |=  dOption;
                            else       dOptions &= ~dOption;
                            }
                        }
                    break;
                    }
                }
            }
        }
    return 0;
    }

// =================================================================
// END OF PROGRAM
// =================================================================
