Annotation of mstools/mfc/samples/restool/restool.cpp, revision 1.1

1.1     ! root        1: // restool.cpp : Parses RES files, making Foundation-ready header files for
        !             2: //               all dialogs in it.  This can make it easier to port the
        !             3: //               dialog code from existing applications, but it is not
        !             4: //               intended to make writing new dialog code easier or better.
        !             5: //
        !             6: // This is a part of the Microsoft Foundation Classes C++ library.
        !             7: // Copyright (C) 1992 Microsoft Corporation
        !             8: // All rights reserved.
        !             9: //
        !            10: // This source code is only intended as a supplement to the
        !            11: // Microsoft Foundation Classes Reference and Microsoft
        !            12: // QuickHelp documentation provided with the library.
        !            13: // See these sources for detailed information regarding the
        !            14: // Microsoft Foundation Classes product.
        !            15: 
        !            16: #include <afx.h>
        !            17: #include <afxcoll.h>
        !            18: 
        !            19: #include <windows.h>
        !            20: 
        !            21: #include <fcntl.h>
        !            22: #include <io.h>
        !            23: #include <ctype.h>
        !            24: 
        !            25: #include "dlgres.h"
        !            26: 
        !            27: /////////////////////////////////////////////////////////////////////////////
        !            28: 
        !            29: // forward declarations
        !            30: BOOL GenDialog(const char*, const char*, int, long, BYTE*);
        !            31: 
        !            32: BOOL CheckResFile(int fh, long cbytes)
        !            33: {
        !            34:        long lFilesize, lCurloc;
        !            35:        BYTE ch;
        !            36:        int iType, inum, n;
        !            37:        long l;
        !            38:        BYTE* pBuffer;
        !            39:        char szDlgName[128];
        !            40:        char szResourceName[128];
        !            41: 
        !            42:        lFilesize = cbytes;
        !            43:        lCurloc = 0;
        !            44:        if (lCurloc == lFilesize)
        !            45:                return FALSE;
        !            46:        while (lCurloc < lFilesize)
        !            47:        {
        !            48:                n = _read(fh, &ch, 1);
        !            49:                if (!CheckReadValue(n))
        !            50:                        return FALSE;
        !            51:                if (ch == 0xFF)
        !            52:                {
        !            53:                        n = _read(fh, &iType, 2);
        !            54:                        if (!CheckReadValue(n))
        !            55:                                return FALSE;
        !            56:                }
        !            57:                else
        !            58:                {
        !            59:                        while (ch != 0)
        !            60:                        {
        !            61:                                n = _read(fh, &ch, 1);
        !            62:                                if (!CheckReadValue(n))
        !            63:                                        return FALSE;
        !            64:                        }
        !            65:                }
        !            66:                // read name of resource
        !            67:                n = _read(fh, &ch, 1);
        !            68:                if (!CheckReadValue(n))
        !            69:                        return FALSE;
        !            70: 
        !            71:                if (ch == 0xFF)
        !            72:                {
        !            73:                        // numbered dialog template resource
        !            74:                        n = _read(fh, &inum, 2);
        !            75:                        if (!CheckReadValue(n))
        !            76:                                return FALSE;
        !            77:                        sprintf(szDlgName, "DLG%d", inum);
        !            78:                        sprintf(szResourceName, "MAKEINTRESOURCE(%d)", inum);
        !            79:                }
        !            80:                else
        !            81:                {
        !            82:                        char* psz;
        !            83:                        psz = szDlgName;
        !            84:                        while (ch != 0)
        !            85:                        {
        !            86:                                *psz++ = ch;
        !            87:                                n = _read(fh, &ch, 1);
        !            88:                                if (!CheckReadValue(n))
        !            89:                                        return FALSE;
        !            90:                        }
        !            91:                        *psz = 0;
        !            92:                        sprintf(szResourceName, "\"%s\"", szDlgName);
        !            93:                }
        !            94:                n = _read(fh, &inum, 2);
        !            95:                if (!CheckReadValue(n))
        !            96:                        return FALSE;
        !            97:                n = _read(fh, &l, sizeof(long));
        !            98:                if (!CheckReadValue(n))
        !            99:                        return FALSE;
        !           100: 
        !           101:                pBuffer = new BYTE[(size_t)l];
        !           102:                if (!pBuffer)
        !           103:                        return FALSE;
        !           104: 
        !           105:                n = _read(fh, pBuffer, (int)l);
        !           106: 
        !           107:                if (iType == 5)
        !           108:                {
        !           109:                        // Convert all but first letter of "class name" to lower case.
        !           110:                        //
        !           111:                        {
        !           112:                                char* pch = szDlgName;
        !           113:                                if (*pch)
        !           114:                                {
        !           115:                                        *pch = toupper(*pch);
        !           116:                                        for (pch++; *pch; pch++)
        !           117:                                                *pch = tolower(*pch);
        !           118:                                }
        !           119:                        }
        !           120: 
        !           121:                        if (!GenDialog(szDlgName, szResourceName, inum, l, pBuffer))
        !           122:                                return FALSE;
        !           123:                }
        !           124: 
        !           125:                delete pBuffer;
        !           126: 
        !           127:                if (n != l)
        !           128:                        return FALSE;
        !           129: 
        !           130:                lCurloc = _lseek(fh, 0l, 1);
        !           131:        }
        !           132:        if (lCurloc != lFilesize)
        !           133:                return FALSE;
        !           134: 
        !           135:        return TRUE;
        !           136: }
        !           137: 
        !           138: int main(int argc, char* argv[])
        !           139: {
        !           140:        int fh;
        !           141:        long lBytes;
        !           142: 
        !           143:        if (argc != 2)
        !           144:        {
        !           145:                fprintf(stderr, "restool : usage: restool file.res >file.h\n");
        !           146:                fprintf(stderr, "           Parses RES files, making Foundation-ready H files for\n");
        !           147:                fprintf(stderr, "           all dialogs in it.  This can make it easier to port the\n");
        !           148:                fprintf(stderr, "           dialog code from existing applications.\n");
        !           149:                fprintf(stderr, "           The output should be redirected into an H file for use.\n");
        !           150:                exit(1);
        !           151:        }
        !           152: 
        !           153:        fh = _open(argv[1], O_BINARY);
        !           154:        if (fh == -1)
        !           155:        {
        !           156:                fprintf(stderr, "restool : Cannot open file %s for reading.\n", argv[1]);
        !           157:                exit(1);
        !           158:        }
        !           159:        lBytes = _lseek(fh, 0l, 2);
        !           160:        _lseek(fh, 0l, 0);
        !           161: 
        !           162:        printf("// restool has generated the following header code from %s\n\n", argv[1]);
        !           163:        if (!CheckResFile(fh, lBytes))
        !           164:        {
        !           165:                fprintf(stderr, "restool : Cannot parse file %s; may be invalid.\n", argv[1]);
        !           166:                exit(1);
        !           167:        }
        !           168:        printf("\n\n// END OF restool code\n");
        !           169: 
        !           170:        return 0;
        !           171: }
        !           172: 
        !           173: /////////////////////////////////////////////////////////////////////////////
        !           174: // Information for control types
        !           175: 
        !           176: struct ControlType
        !           177: {
        !           178:        BYTE        code;       // if 0 => end, if 0xFF => match any
        !           179:        BYTE        style;      // lower 4 bits of style
        !           180:                                                        //   0xFF => accept any style
        !           181: 
        !           182:        const char* pszClass;   // if NULL use previous
        !           183:        const char* pszNoun;    // if NULL use previous
        !           184:        int         nCount;     // significant only if pszNoun != NULL
        !           185: };
        !           186: 
        !           187: ControlType types[] =
        !           188: {
        !           189:        { BUTTONCODE,   BS_AUTOCHECKBOX,    "CButton",  "Check" },
        !           190:        { BUTTONCODE,   BS_CHECKBOX,        NULL,       NULL },
        !           191:        { BUTTONCODE,   BS_3STATE,          NULL,       NULL },
        !           192:        { BUTTONCODE,   BS_AUTO3STATE,      NULL,       NULL },
        !           193:        { BUTTONCODE,   BS_AUTORADIOBUTTON, NULL,       "Option" },
        !           194:        { BUTTONCODE,   BS_RADIOBUTTON,     NULL,       NULL },
        !           195:        { BUTTONCODE,   BS_GROUPBOX,        NULL,       "Group" },
        !           196:        { BUTTONCODE,   BS_PUSHBUTTON,      NULL,       "Button" },
        !           197:        { BUTTONCODE,   BS_DEFPUSHBUTTON,   NULL,       NULL },
        !           198:        { EDITCODE,     0xFF,               "CEdit",    "Edit" },
        !           199:        { STATICCODE,   SS_SIMPLE,          "CStatic",  "Text" },
        !           200:        { STATICCODE,   SS_LEFT,            NULL,       NULL },
        !           201:        { STATICCODE,   SS_CENTER,          NULL,       NULL },
        !           202:        { STATICCODE,   SS_RIGHT,           NULL,       NULL },
        !           203:        { STATICCODE,   SS_LEFTNOWORDWRAP,  NULL,       NULL },
        !           204:        { STATICCODE,   SS_ICON,            NULL,       "Icon" },
        !           205:        { STATICCODE,   SS_BLACKRECT,       NULL,       "Box" },
        !           206:        { STATICCODE,   SS_GRAYRECT,        NULL,       NULL },
        !           207:        { STATICCODE,   SS_WHITERECT,       NULL,       NULL },
        !           208:        { STATICCODE,   SS_BLACKFRAME,      NULL,       NULL },
        !           209:        { STATICCODE,   SS_GRAYFRAME,       NULL,       NULL },
        !           210:        { STATICCODE,   SS_WHITEFRAME,      NULL,       NULL },
        !           211:        { LISTBOXCODE,  0xFF,               "CListBox", "List" },
        !           212:        { COMBOBOXCODE, 0xFF,               "CComboBox", "Combo" },
        !           213:        { SCROLLBARCODE, 0,                 "CScrollBar", "HScroll" },
        !           214:        { SCROLLBARCODE, SBS_VERT,          NULL,       "VScroll" },
        !           215:        { 0xFF,         0xFF,               "CWnd",     "Control" },    // 2nd last
        !           216:        { 0 }
        !           217: };
        !           218: 
        !           219: void InitCounts()
        !           220: {
        !           221:        for (register ControlType* pType = types; pType->code != 0; pType++)
        !           222:                if (pType->pszNoun != NULL)
        !           223:                        pType->nCount = 0;
        !           224: }
        !           225: 
        !           226: // IsLabel:
        !           227: // Simple logic for determining if an item is really a label.
        !           228: // Labels do not (usually) need any code, so none is generated.
        !           229: //
        !           230: BOOL IsLabel(BYTE code, DLGITEMTEMPLATE* pDit, BYTE nextCode)
        !           231: {
        !           232:        if (pDit->id == -1)
        !           233:                return TRUE;            // may not be real label, but ignore anyway
        !           234: 
        !           235:        if (code == STATICCODE && nextCode != 0)
        !           236:        {
        !           237:                // static code with something after it
        !           238:                if (pDit->style & SS_NOPREFIX)
        !           239:                        return FALSE;   // no accelerator => probably not a label
        !           240: 
        !           241:                switch (pDit->style & 0xf)
        !           242:                {
        !           243:                case SS_LEFT: case SS_CENTER: case SS_RIGHT:
        !           244:                case SS_SIMPLE: case SS_LEFTNOWORDWRAP:
        !           245:                        break;      // keep going
        !           246:                default:
        !           247:                        return FALSE;
        !           248:                }
        !           249: 
        !           250:                // lastly, only keep labels if next item is edit or list/combo
        !           251:                switch (nextCode)
        !           252:                {
        !           253:                case EDITCODE: case LISTBOXCODE: case COMBOBOXCODE:
        !           254:                        return TRUE;
        !           255:                }
        !           256:        }
        !           257:        return FALSE;
        !           258: }
        !           259: 
        !           260: /////////////////////////////////////////////////////////////////////////////
        !           261: 
        !           262: // ControlInfo:
        !           263: // Decode control information and place in easy-to-use structure.
        !           264: //
        !           265: struct ControlInfo
        !           266: {
        !           267:        BYTE code;
        !           268:        BYTE style;     // lower 4 bits of style
        !           269: 
        !           270:        const char* pszClass;
        !           271:        CString memberName;         // will be literal text for a label
        !           272:        UINT id;
        !           273: 
        !           274:        // special values
        !           275:        BOOL bLabel;                // label not an interactive control
        !           276:        int nRadioGroup;            // or -1 for none
        !           277: 
        !           278:        ControlInfo()   // structure initialization
        !           279:        {
        !           280:                pszClass = NULL;
        !           281:                id = 0;
        !           282:                bLabel = FALSE;
        !           283:                nRadioGroup = -1;
        !           284:        }
        !           285: };
        !           286: 
        !           287: struct ControlInfo* DecodeControls(BYTE* pBuffer, BYTE* pEnd, int nCount)
        !           288: {
        !           289:        // decode controls in dialog
        !           290:        CMapStringToPtr usedNames;
        !           291:        CString lastLabel, lastLabelLiteral;
        !           292:        lastLabel.GetBuffer(128);       // set a reasonable size
        !           293:        lastLabelLiteral.GetBuffer(128);    // set a reasonable size
        !           294: 
        !           295:        struct ControlInfo* pAllInfo = new ControlInfo[nCount];
        !           296:        ASSERT(pAllInfo != NULL);
        !           297: 
        !           298:        for (int iCtl = 0; iCtl < nCount; iCtl++)
        !           299:        {
        !           300:                struct ControlInfo* pInfo = &pAllInfo[iCtl];
        !           301:                DLGITEMTEMPLATE* pDit = (DLGITEMTEMPLATE*)pBuffer;
        !           302:                pBuffer += sizeof(DLGITEMTEMPLATE);
        !           303: 
        !           304:                BYTE cTokenCode = *pBuffer++;
        !           305:                char* pszString = (char*)pBuffer;
        !           306:                pBuffer = SkipString(pBuffer) + 1;
        !           307: 
        !           308:                ASSERT(pBuffer <= pEnd);
        !           309:                pInfo->code = cTokenCode;
        !           310:                pInfo->id = pDit->id;
        !           311:                pInfo->style = (BYTE)(pDit->style&0xf);     // lower 4 bits of style
        !           312: 
        !           313:                if (*pszString != '\0')
        !           314:                {
        !           315:                        // save it away as a reasonable symbol
        !           316:                        lastLabelLiteral = pszString;       // literal string (for comments)
        !           317:                        lastLabel = "";
        !           318: 
        !           319:                        while (*pszString != '\0' && !isalpha(*pszString))
        !           320:                                pszString++;        // skip non-alpha
        !           321: 
        !           322:                        // include alpha+numbers for the rest of the name
        !           323:                        while (*pszString != '\0')
        !           324:                        {
        !           325:                                if (isalnum(*pszString))
        !           326:                                        lastLabel += *pszString;
        !           327:                                *pszString++;
        !           328:                        }
        !           329:                }
        !           330: 
        !           331:                BYTE nextCode = 0;
        !           332:                if (pBuffer + sizeof(DLGITEMTEMPLATE) < pEnd)
        !           333:                        nextCode = *(pBuffer+sizeof(DLGITEMTEMPLATE));
        !           334: 
        !           335:                if (IsLabel(cTokenCode, pDit, nextCode))
        !           336:                {
        !           337:                        pInfo->bLabel = TRUE;
        !           338:                        pInfo->pszClass = NULL;
        !           339:                        pInfo->memberName = lastLabelLiteral;
        !           340:                        continue;
        !           341:                }
        !           342: 
        !           343:                const char* pszClass = NULL;
        !           344:                const char* pszNoun = NULL;
        !           345:                BOOL bExact = FALSE;
        !           346:                int* pnIndex = NULL;
        !           347:                for (register ControlType* pType = types; pType->code != 0; pType++)
        !           348:                {
        !           349:                        if (pType->code == cTokenCode || pType->code == 0xFF)
        !           350:                        {
        !           351:                                // match raw category
        !           352:                                if (pType->pszClass != NULL)
        !           353:                                        pszClass = pType->pszClass;
        !           354:                                ASSERT(pszClass != NULL);
        !           355:                                if (pType->pszNoun != NULL)
        !           356:                                {
        !           357:                                        pszNoun = pType->pszNoun;
        !           358:                                        pnIndex = &pType->nCount;
        !           359:                                }
        !           360: 
        !           361:                                // check for sub-type match
        !           362:                                if (pType->style == 0xFF ||
        !           363:                                        ((BYTE)pType->style == (BYTE)(pDit->style&0xf)))
        !           364:                                {
        !           365:                                        // exact match
        !           366:                                        bExact = TRUE;
        !           367:                                        break;
        !           368:                                }
        !           369:                        }
        !           370:                }
        !           371: 
        !           372:                ASSERT(bExact);
        !           373:                (*pnIndex)++;       // bump count of objects using that noun
        !           374: 
        !           375:                // save remaining info
        !           376:                pInfo->pszClass = pszClass;
        !           377:                CString memberName;
        !           378:                if (!lastLabel.IsEmpty())
        !           379:                {
        !           380:                        pInfo->memberName = lastLabel;
        !           381:                        pInfo->memberName += pszNoun;
        !           382:                }
        !           383:                else
        !           384:                {
        !           385:                        pInfo->memberName = pszNoun;
        !           386:                        char szT[10];
        !           387:                        pInfo->memberName += _itoa(*pnIndex, szT, 10);
        !           388:                }
        !           389: 
        !           390:                void* p;
        !           391:                if (usedNames.Lookup(pInfo->memberName, p))
        !           392:                {
        !           393:                        // name has already been used in this class
        !           394:                        char szT[10];
        !           395:                        pInfo->memberName += _itoa(*pnIndex, szT, 10);
        !           396:                }
        !           397:                usedNames[pInfo->memberName] = "USED";
        !           398: 
        !           399:                lastLabel = "";
        !           400:                lastLabelLiteral = "";
        !           401:        }
        !           402:        ASSERT(pBuffer == pEnd);
        !           403:        return pAllInfo;        // return array
        !           404: }
        !           405: 
        !           406: /////////////////////////////////////////////////////////////////////////////
        !           407: // Print out control info
        !           408: 
        !           409: void PrintControls(const struct ControlInfo * pInfo, int nCount,
        !           410:                DWORD /* styleDlg */)
        !           411: {
        !           412:        for (int iCtl = 0; iCtl < nCount; iCtl++, pInfo++)
        !           413:        {
        !           414:                if (pInfo->bLabel)
        !           415:                {
        !           416:                        printf("\t// label '%s'\n", (const char*)pInfo->memberName);
        !           417:                }
        !           418:                else
        !           419:                {
        !           420:                        // Build normal member type.
        !           421:                        //
        !           422:                        CString typeName = pInfo->pszClass;
        !           423:                        typeName += '&';            // return reference
        !           424:                        if (typeName.GetLength() < 8)
        !           425:                                typeName += '\t';
        !           426: 
        !           427:                        // Write out member function definition.
        !           428:                        printf("\t%s %s()\n"
        !           429:                                "\t\t\t{ return *((%s*) GetDlgItem(%d)); } \n",
        !           430:                                        (const char*)typeName,
        !           431:                                        (const char*)pInfo->memberName,
        !           432:                                        pInfo->pszClass, pInfo->id);
        !           433:                }
        !           434:        }
        !           435: }
        !           436: 
        !           437: /////////////////////////////////////////////////////////////////////////////
        !           438: 
        !           439: // DetectRadioGroups:
        !           440: // Special detection for radio groups.
        !           441: //
        !           442: void DetectRadioGroups(struct ControlInfo* pInfo, int nCount)
        !           443: {
        !           444:        int nRadioGroup = -1;
        !           445:        UINT idLast = 0;
        !           446: 
        !           447:        for (int iCtl = 0; iCtl < nCount; iCtl++, pInfo++)
        !           448:        {
        !           449:                if (pInfo->code == BUTTONCODE &&
        !           450:                        (pInfo->style == BS_AUTORADIOBUTTON ||
        !           451:                         pInfo->style == BS_RADIOBUTTON))
        !           452:                {
        !           453:                        if (pInfo->id != idLast+1)
        !           454:                        {
        !           455:                                // start new group
        !           456:                                nRadioGroup = -1;
        !           457:                        }
        !           458:                        pInfo->nRadioGroup = ++nRadioGroup;
        !           459:                                // next in sequence
        !           460:                }
        !           461:                else
        !           462:                {
        !           463:                        nRadioGroup = -1;
        !           464:                }
        !           465:                idLast = pInfo->id;
        !           466:        }
        !           467: }
        !           468: 
        !           469: 
        !           470: /////////////////////////////////////////////////////////////////////////////
        !           471: 
        !           472: // GenDialog:
        !           473: // Do the actual code-generation work.
        !           474: //
        !           475: BOOL GenDialog(const char* pszName, const char* pszResourceName,
        !           476:        int /* flags */, long l, BYTE* pBuffer)
        !           477: {
        !           478:        BYTE* pEnd = &pBuffer[l];
        !           479: 
        !           480:        InitCounts();
        !           481: 
        !           482:        DLGTEMPLATE* pdt = (DLGTEMPLATE*)pBuffer;
        !           483:        pBuffer += sizeof(DLGTEMPLATE);
        !           484:        DWORD styleDlg = pdt->style;
        !           485:        BYTE cdit = pdt->cdit;
        !           486: 
        !           487:        fprintf(stderr, "restool : Generating header for dialog %s.\n", pszName);
        !           488: 
        !           489:        // Make sure there is no menu string...
        !           490:        if (*pBuffer != '\0')
        !           491:                fprintf(stderr, "\nrestool : WARNING: Menus in dialogs are not supported.\n");
        !           492:        pBuffer = SkipString(pBuffer);
        !           493: 
        !           494:        // Make sure only generic window class used
        !           495: 
        !           496:        if (*pBuffer != '\0')
        !           497:                fprintf(stderr, "\nrestool : WARNING: Only generic window classes are supported.\n");
        !           498:        pBuffer = SkipString(pBuffer);
        !           499: 
        !           500:        // Deal with caption string...
        !           501:        char* pszCaption = (char*) pBuffer;
        !           502:        pBuffer = SkipString(pBuffer);
        !           503: 
        !           504:        // Skip over font data if present
        !           505:        if (styleDlg & DS_SETFONT)
        !           506:                pBuffer = SkipString(pBuffer + sizeof(short int));
        !           507: 
        !           508:        // preliminary stuff
        !           509:        const char* pszBaseClass;
        !           510: 
        !           511:        BOOL bModal = ((styleDlg & (DS_SYSMODAL | DS_MODALFRAME)) != 0);
        !           512:        pszBaseClass = bModal ? "CModalDialog" : "CDialog";
        !           513: 
        !           514:        printf("///////////////////////////////////////////////////////////\n");
        !           515:        printf("// class C%s manages the %s dialog resource\n\n", pszName,
        !           516:                pszResourceName);
        !           517:        printf("class C%s : public %s\n", pszName, pszBaseClass);
        !           518:        printf("{\n");
        !           519:        printf("public:\n");
        !           520: 
        !           521:        // Write the constructor.
        !           522:        //
        !           523:        printf("\tC%s(CWnd* pParentWnd = NULL)\n", pszName);
        !           524:        if (bModal)
        !           525:        {
        !           526:                // CModalDialog constructor
        !           527:                printf("\t\t: %s(%s, pParentWnd)\n", pszBaseClass, pszResourceName);
        !           528:                printf("\t\t\t{ }\n");
        !           529:        }
        !           530:        else
        !           531:        {
        !           532:                // CModal dialog constructor + create modeless
        !           533:                printf("\t\t{\n");
        !           534:                printf("\t\t\tVERIFY(Create(%s, pParentWnd));\n", pszResourceName);
        !           535:                printf("\t\t}\n");
        !           536:        }
        !           537: 
        !           538:        // Write the public member variable declarations.
        !           539:        //
        !           540:        printf("\n\t// Attributes\n");
        !           541:        struct ControlInfo* pAllInfo;
        !           542:        pAllInfo = DecodeControls(pBuffer, pEnd, cdit);
        !           543:        DetectRadioGroups(pAllInfo, cdit);
        !           544:        PrintControls(pAllInfo, cdit, styleDlg);
        !           545: 
        !           546:        // Write the member function declarations.
        !           547:        printf("\n\t// Operations\n");
        !           548: 
        !           549:        // Write the overriding virtual member function declarations.
        !           550:        //
        !           551:        printf("\n\t// Overridables\n");
        !           552: 
        !           553:        // Write the message-map and message-handling member function declarations.
        !           554:        //
        !           555:        printf("\n\t// Implementation\n");
        !           556:        printf("private:\n");
        !           557:        printf("\tBOOL OnInitDialog();\n");
        !           558:        printf("\tDECLARE_MESSAGE_MAP()\n");
        !           559:        printf("};\n\n");
        !           560:        return TRUE;
        !           561: }

unix.superglobalmegacorp.com

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