Annotation of uae/mac.c, revision 1.1

1.1     ! root        1:  /* 
        !             2:   * UAE - The Un*x Amiga Emulator
        !             3:   * 
        !             4:   * Mac port specific stuff
        !             5:   * 
        !             6:   * (c) 1996 Ernesto Corvi
        !             7:   */
        !             8: 
        !             9: #include <stdio.h>
        !            10: #include <stdlib.h>
        !            11: #include <string.h>
        !            12: #include <QDOffscreen.h>
        !            13: #include <Palettes.h>
        !            14: #include <Profiler.h>
        !            15: 
        !            16: #include "mackbd.h"
        !            17: #include "config.h"
        !            18: #include "amiga.h"
        !            19: #include "options.h"
        !            20: #include "memory.h"
        !            21: #include "custom.h"
        !            22: #include "newcpu.h"
        !            23: #include "xwin.h"
        !            24: #include "keyboard.h"
        !            25: #include "keybuf.h"
        !            26: 
        !            27: #define kQuitError 128
        !            28: 
        !            29: extern bool left, right, top, bot, but;
        !            30: 
        !            31: KeyMap keys,keysold;
        !            32: GDHandle               curDevice;
        !            33: int            oldDepth=0;
        !            34: static int screen;
        !            35: Boolean        RM=false,Joy=false;
        !            36: WindowPtr mywin;
        !            37: short  gOldMBarHeight;
        !            38: RgnHandle gMBarRgn;
        !            39: static int bitdepth;
        !            40: KeyMap theKeys;
        !            41: 
        !            42: unsigned long refresh;
        !            43: char *xlinebuffer;
        !            44: unsigned int *obuff;
        !            45: long int xcolors[4096];
        !            46: 
        !            47:  /* Keyboard and mouse */
        !            48: 
        !            49: static bool keystate[256];
        !            50: 
        !            51: bool buttonstate[3];
        !            52: int lastmx, lastmy;
        !            53: bool newmousecounters;
        !            54: static bool inwindow;
        !            55: 
        !            56: int GetRawCode (long set0, long set1, long set2, long set3);
        !            57: 
        !            58: static inline unsigned long doMask(int p, int bits, int shift)
        !            59: {
        !            60:     /* p is a value from 0 to 15 (Amiga color value)
        !            61:      * scale to 0..255, shift to align msb with mask, and apply mask */
        !            62: 
        !            63:     unsigned long val = p * 0x11111111UL;
        !            64:     val >>= (32 - bits);
        !            65:     val <<= shift;
        !            66: 
        !            67:     return val;
        !            68: }
        !            69: 
        !            70: static void InitXColors(void)
        !            71: {
        !            72:     int n=16;
        !            73:     int red_bits = 5;
        !            74:     int green_bits = 5;
        !            75:     int blue_bits = 5;
        !            76:     int red_shift = 10;
        !            77:     int green_shift = 5;
        !            78:     int blue_shift = 0;
        !            79:     int i=0;
        !            80:     int r,g,b;
        !            81:        
        !            82:     for(i = 0; i < 4096; i++) {
        !            83:        r = i >> 8;
        !            84:        g = (i >> 4) & 0xF;
        !            85:        b = i & 0xF;
        !            86:        xcolors[i] = (doMask(r, red_bits, red_shift) 
        !            87:                      | doMask(g, green_bits, green_shift) 
        !            88:                      | doMask(b, blue_bits, blue_shift));
        !            89:     }
        !            90: }
        !            91: 
        !            92: static void InitToolbox(void)
        !            93: {
        !            94:        InitGraf (&qd.thePort);
        !            95:        InitFonts ();
        !            96:        FlushEvents (everyEvent,0);
        !            97:        InitWindows ();
        !            98:        InitMenus ();
        !            99:        TEInit ();
        !           100:        InitDialogs (nil);
        !           101:        InitCursor ();
        !           102: }
        !           103: 
        !           104: static void HideMenuBar(void)
        !           105: {
        !           106:     Rect mBarRect;
        !           107: 
        !           108:     /* GET RID OF THE MENU BAR */
        !           109:                                        
        !           110:     gOldMBarHeight = GetMBarHeight();
        !           111:     /* make the Menu Bar's height zero */
        !           112:     LMSetMBarHeight(0);
        !           113:     SetRect(&mBarRect, qd.screenBits.bounds.left, qd.screenBits.bounds.top,
        !           114:            qd.screenBits.bounds.right, qd.screenBits.bounds.top + gOldMBarHeight);
        !           115:     gMBarRgn = NewRgn();
        !           116:     RectRgn(gMBarRgn, &mBarRect);
        !           117:     UnionRgn(LMGetGrayRgn(), gMBarRgn, LMGetGrayRgn());        /* tell the desktop it covers the menu bar */
        !           118: 
        !           119:     PaintOne(nil, gMBarRgn); /* redraw desktop */
        !           120: }
        !           121: 
        !           122: static void ShowMenuBar(void)
        !           123: {
        !           124:     LMSetMBarHeight(gOldMBarHeight); /* make the menu bar's height normal */
        !           125:     DiffRgn(LMGetGrayRgn(), gMBarRgn, LMGetGrayRgn()); /* remove the menu bar from the desktop */
        !           126:     DisposeRgn(gMBarRgn);
        !           127: }
        !           128: 
        !           129: void graphics_init()
        !           130: {      int i;
        !           131:        long p1;
        !           132:        long tmp;
        !           133: 
        !           134:     Rect       windowRectangle={0,0,480,640};
        !           135:     InitToolbox();
        !           136:        
        !           137:        if (CheckForSetup()) ExitToShell();
        !           138:        
        !           139:        HideMenuBar();
        !           140:        mywin = NewCWindow(nil, &windowRectangle, "\pUAE", true, 2, (WindowPtr)-1L, false, 0);
        !           141:     SetPort(mywin);
        !           142: 
        !           143:     PaintRect(&qd.screenBits.bounds);
        !           144:     
        !           145:     xlinebuffer = (char *)malloc (3200);
        !           146:     InitXColors();
        !           147:     buttonstate[0] = buttonstate[1] = buttonstate[2] = false;
        !           148:     for(i=0; i<256; i++) keystate[i] = false;
        !           149:     
        !           150:     lastmx = lastmy = 0; newmousecounters = false; inwindow = false;
        !           151:     
        !           152:     obuff=(unsigned int *)NewPtrClear(481*1280);
        !           153:        {
        !           154:                for(p1=0;p1 < (480*1280);p1++)
        !           155:                        *obuff=-1;
        !           156:        }
        !           157:        
        !           158:        HideCursor();
        !           159:     refresh=TickCount();
        !           160:     
        !           161: /*    tmp=ProfilerInit(collectDetailed,bestTimeBase,200,10); */
        !           162: }
        !           163: 
        !           164: void graphics_leave()
        !           165: {
        !           166: /*     ProfilerDump((unsigned char *)"\pmyProf");
        !           167:        ProfilerTerm();
        !           168:  */
        !           169:     DisposeWindow(mywin);
        !           170:     ShowCursor();
        !           171:     if (oldDepth != 0) SetDepth(curDevice,oldDepth,0,0);
        !           172:     ShowMenuBar();
        !           173:     FlushEvents (everyEvent,0);
        !           174:     ExitToShell();
        !           175: }
        !           176: 
        !           177: static bool next_line_double;
        !           178: static int next_line_pos = 0;
        !           179: 
        !           180: void flush_screen ()
        !           181: {  
        !           182:     GrafPtr oldPort;
        !           183:     short      y,x,daColor=0;
        !           184:     RGBColor   daColorRGB;
        !           185:     unsigned char *winbaseaddr;
        !           186:     double *src,*dest;
        !           187:     unsigned long winrowbytes;
        !           188:     PixMapHandle       ph;
        !           189:     
        !           190:     if (TickCount() < refresh + 4) return;
        !           191:     GetPort(&oldPort);
        !           192:     SetPort(mywin);
        !           193:    
        !           194:     ph=GetGWorldPixMap((CGrafPort *) mywin);
        !           195:     LockPixels(ph);
        !           196:     winbaseaddr=( unsigned char *) GetPixBaseAddr(ph);
        !           197:     winrowbytes=(*ph)->rowBytes & 0x3FFF;
        !           198:     winbaseaddr-=((**ph).bounds.left);
        !           199:     winbaseaddr-=((**ph).bounds.top*winrowbytes);
        !           200:     dest=(double *)winbaseaddr;
        !           201:     src=(double *)obuff;
        !           202:     
        !           203:     for (y=1; y< 480; y++)
        !           204:     {
        !           205:        for (x=0;x < 160;x++)
        !           206:        {  
        !           207:            *dest++ = *src++;
        !           208:        }
        !           209:        dest=(double *)(winbaseaddr+(y*winrowbytes));
        !           210:     }
        !           211:     UnlockPixels(ph);
        !           212:     SetPort(oldPort);
        !           213: 
        !           214: }
        !           215: 
        !           216: void prepare_line (int y, bool need_double)
        !           217: {
        !           218:     next_line_double = need_double;
        !           219:     next_line_pos = y;
        !           220: }
        !           221: 
        !           222: void flush_line()
        !           223: {
        !           224:     short i;
        !           225:     char *dst,*src;
        !           226:     double *dst1,*src1;
        !           227:         
        !           228:     if ((next_line_pos < 508) && (next_line_pos > 28))
        !           229:     {  
        !           230:        dst=(char *)obuff+((next_line_pos-28)*1280);
        !           231:        src=(char *)xlinebuffer+292;
        !           232:        BlockMove(src,dst,1280);  
        !           233:     }
        !           234:     if (next_line_double)
        !           235:     {  
        !           236:        if ((next_line_pos+1 < 508) && (next_line_pos+1 > 28))
        !           237:        {       
        !           238:            dst1=(double *)obuff+((next_line_pos+1-28)*160);
        !           239:            src1=(double *)obuff+((next_line_pos-28)*160);
        !           240:            for (i=0;i < 160;i++)
        !           241:            {  
        !           242:                *dst1++=*src1++;
        !           243:            }
        !           244:        }
        !           245:     }
        !           246: }
        !           247: 
        !           248: /* Decode KeySyms. This function knows about all keys that are common 
        !           249:  * between different keyboard languages.
        !           250:  */
        !           251: static int kc_decode (long ks)
        !           252: {      
        !           253:     switch (ks)
        !           254:     {
        !           255:      case kAKeyMap: return AK_A;
        !           256:      case kBKeyMap: return AK_B;
        !           257:      case kCKeyMap: return AK_C;
        !           258:      case kDKeyMap: return AK_D;
        !           259:      case kEKeyMap: return AK_E;
        !           260:      case kFKeyMap: return AK_F;
        !           261:      case kGKeyMap: return AK_G;
        !           262:      case kHKeyMap: return AK_H;
        !           263:      case kIKeyMap: return AK_I;
        !           264:      case kJKeyMap: return AK_J;
        !           265:      case kKKeyMap: return AK_K;
        !           266:      case kLKeyMap: return AK_L;
        !           267:      case kMKeyMap: return AK_M;
        !           268:      case kNKeyMap: return AK_N;
        !           269:      case kOKeyMap: return AK_O;
        !           270:      case kPKeyMap: return AK_P;
        !           271:      case kQKeyMap: return AK_Q;
        !           272:      case kRKeyMap: return AK_R;
        !           273:      case kSKeyMap: return AK_S;
        !           274:      case kTKeyMap: return AK_T;
        !           275:      case kUKeyMap: return AK_U;
        !           276:      case kVKeyMap: return AK_V;
        !           277:      case kWKeyMap: return AK_W;
        !           278:      case kXKeyMap: return AK_X;
        !           279:      
        !           280:      case k0KeyMap: return AK_0;
        !           281:      case k1KeyMap: return AK_1;
        !           282:      case k2KeyMap: return AK_2;
        !           283:      case k3KeyMap: return AK_3;
        !           284:      case k4KeyMap: return AK_4;
        !           285:      case k5KeyMap: return AK_5;
        !           286:      case k6KeyMap: return AK_6;
        !           287:      case k7KeyMap: return AK_7;
        !           288:      case k8KeyMap: return AK_8;
        !           289:      case k9KeyMap: return AK_9;
        !           290:      
        !           291:      case kKP0KeyMap: return AK_NP0;
        !           292:      case kKP1KeyMap: return AK_NP1;
        !           293:      case kKP2KeyMap: return AK_NP2;
        !           294:      case kKP3KeyMap: return AK_NP3;
        !           295:      case kKP4KeyMap: return AK_NP4;
        !           296:      case kKP5KeyMap: return AK_NP5;
        !           297:      case kKP6KeyMap: return AK_NP6;
        !           298:      case kKP7KeyMap: return AK_NP7;
        !           299:      case kKP8KeyMap: return AK_NP8;
        !           300:      case kKP9KeyMap: return AK_NP9;
        !           301:        
        !           302:      case kF1KeyMap: return AK_F1;
        !           303:      case kF2KeyMap: return AK_F2;
        !           304:      case kF3KeyMap: return AK_F3;
        !           305:      case kF4KeyMap: return AK_F4;
        !           306:      case kF5KeyMap: return AK_F5;
        !           307:      case kF6KeyMap: return AK_F6;
        !           308:      case kF7KeyMap: return AK_F7;
        !           309:      case kF8KeyMap: return AK_F8;
        !           310:      case kF9KeyMap: return AK_F9;
        !           311:      case kF10KeyMap: return AK_F10;
        !           312:        
        !           313:      case kBackSpaceKeyMap: return AK_BS;
        !           314:      case kTabKeyMap: return AK_TAB;
        !           315:      case kReturnKeyMap: return AK_RET;
        !           316:      case kEscapeKeyMap: return AK_ESC;
        !           317:      
        !           318:      case kSpaceBarMap: if (Joy) return -1; else return AK_SPC;
        !           319:      
        !           320:      case kUpArrowKeyMap: if (Joy) return -1; else return AK_UP;
        !           321:      case kDownArrowKeyMap: if (Joy) return -1; else return AK_DN;
        !           322:      case kLeftArrowKeyMap: if (Joy) return -1; else return AK_LF;
        !           323:      case kRightArrowKeyMap: if (Joy) return -1; else return AK_RT;
        !           324:        
        !           325:      case kF11KeyMap: graphics_leave();
        !           326:      case kF12KeyMap: { Joy=!Joy; SysBeep(0); return -1; }
        !           327: 
        !           328:      case kPgUpKeyMap: return AK_RAMI;
        !           329:      case kPgDnKeyMap: return AK_LAMI;
        !           330:      case kBackSlash: return AK_BACKSLASH;
        !           331:     }
        !           332:     return -1;
        !           333: }
        !           334: 
        !           335: static int decode_us(long ks)
        !           336: {
        !           337:     switch(ks) {
        !           338:        /* US specific */
        !           339: 
        !           340:      case kYKeyMap: return AK_Y;
        !           341:      case kZKeyMap: return AK_Z;
        !           342:      case kLBracketKeyMap: return AK_LBRACKET;
        !           343:      case kRBracketKeyMap: return AK_RBRACKET;
        !           344:      case kCommaKeyMap: return AK_COMMA;
        !           345:      case kPeriodKeyMap: return AK_PERIOD;
        !           346:      case kSlashKeyMap: return AK_SLASH;
        !           347:      case kSemiColonKeyMap: return AK_SEMICOLON;
        !           348:      case kMinusKeyMap: return AK_MINUS;
        !           349:      case kEqualKeyMap: return AK_EQUAL;
        !           350:      case kQuoteKeyMap: return AK_QUOTE;
        !           351:     }
        !           352: 
        !           353:     return -1;
        !           354: }
        !           355: 
        !           356: static int decode_de(long ks)
        !           357: {
        !           358:     switch(ks) {
        !           359: /* DE specific
        !           360:      case XK_Y: case XK_y: return AK_Z;
        !           361:      case XK_Z: case XK_z: return AK_Y;
        !           362:      case XK_Odiaeresis: case XK_odiaeresis: return AK_SEMICOLON;
        !           363:      case XK_Adiaeresis: case XK_adiaeresis: return AK_QUOTE;
        !           364:      case XK_Udiaeresis: case XK_udiaeresis: return AK_LBRACKET;
        !           365:      case XK_plus: case XK_asterisk: return AK_RBRACKET;
        !           366:      case XK_comma: return AK_COMMA;
        !           367:      case XK_period: return AK_PERIOD;
        !           368:      case XK_less: case XK_greater: return AK_LTGT;
        !           369:      case XK_numbersign: return AK_NUMBERSIGN;
        !           370:      case XK_ssharp: return AK_MINUS;
        !           371:      case XK_apostrophe: return AK_EQUAL;
        !           372:      case XK_asciicircum: return AK_00;
        !           373:      case XK_minus: return AK_SLASH;       
        !           374: */
        !           375:     }
        !           376: 
        !           377:     return -1;
        !           378: }
        !           379: 
        !           380: static int keycode2amiga(long code)
        !           381: {
        !           382:     long ks;
        !           383:     int as;
        !           384:     
        !           385:     ks = (code & keyCodeMask) >> 8;
        !           386:     as = kc_decode (ks);
        !           387:        
        !           388:     if (as == -1) {        
        !           389:        switch(keyboard_lang) {
        !           390:         case KBD_LANG_US:
        !           391:            as = decode_us(ks);
        !           392:            break;
        !           393:                
        !           394:         case KBD_LANG_DE:
        !           395:            as = decode_de(ks);
        !           396:            break;
        !           397:                
        !           398:         default:
        !           399:            as = -1;
        !           400:            break;
        !           401:        }
        !           402:     }
        !           403:     if(-1 != as)
        !           404:        return as;
        !           405:     return -1;
        !           406: }
        !           407: 
        !           408: void handle_events()
        !           409: {
        !           410:     Boolean repeat;
        !           411:     Boolean itHappened;
        !           412:     Point   mpos;
        !           413:     EventRecord event;
        !           414:     int kc,i,count;
        !           415:        
        !           416:     SetEventMask(-1);
        !           417:     SelectWindow(mywin);
        !           418:     HideCursor();
        !           419:        
        !           420:     GetKeys(keys);
        !           421:     if (BitTst(&keys, kCommandRawKey))
        !           422:        RM=true;
        !           423:     else
        !           424:        RM=false;
        !           425:     
        !           426:     if (BitTst(&keys, kShiftRawKey))
        !           427:     {  
        !           428:        if (!keystate[AK_LSH]) {
        !           429:            keystate[AK_LSH] = true;
        !           430:            record_key (AK_LSH << 1);
        !           431:            goto label1;
        !           432:        }
        !           433:     } else {
        !           434:        if (keystate[AK_LSH]) {
        !           435:            keystate[AK_LSH] = false;
        !           436:            record_key ((AK_LSH << 1) | 1);
        !           437:            goto label1;
        !           438:        }
        !           439:     }
        !           440:     if (BitTst(&keys, kControlRawKey))
        !           441:     {  
        !           442:        if (!keystate[AK_CTRL]) {
        !           443:            keystate[AK_CTRL] = true;
        !           444:            record_key (AK_CTRL << 1);
        !           445:            goto label1;
        !           446:        }
        !           447:     } else {   
        !           448:        if (keystate[AK_CTRL]) {
        !           449:            keystate[AK_CTRL] = false;
        !           450:            record_key ((AK_CTRL << 1) | 1);
        !           451:            goto label1;
        !           452:        }
        !           453:     }
        !           454:     if (BitTst(&keys, kOptionRawKey))
        !           455:     {  
        !           456:        if (!keystate[AK_LALT]) {
        !           457:            keystate[AK_LALT] = true;
        !           458:            record_key (AK_LALT << 1);
        !           459:            goto label1;
        !           460:        }
        !           461:     } else {
        !           462:        if (keystate[AK_LALT]) {
        !           463:            keystate[AK_LALT] = false;
        !           464:            record_key ((AK_LALT << 1) | 1);
        !           465:            goto label1;
        !           466:        }
        !           467:     }
        !           468:     do {
        !           469:        repeat = false;
        !           470:        newmousecounters = false;
        !           471:        itHappened=WaitNextEvent(-1,&event,0L,0L);
        !           472: 
        !           473:        switch(event.what) {
        !           474:         case keyDown:
        !           475:         case autoKey: {        
        !           476:             int kc = keycode2amiga(event.message);
        !           477:             if (kc == -1) break;
        !           478:             if (RM == true && kc == AK_Q) graphics_leave();
        !           479:             switch (kc) {
        !           480:              case AK_mousestuff:
        !           481: #if 0
        !           482:                 if (keystate[AK_CTRL])
        !           483:                     mousesetup();
        !           484:                         else 
        !           485: #endif
        !           486:                     togglemouse();
        !           487:                         break;
        !           488: 
        !           489:              case AK_inhibit:
        !           490:                         inhibit_frame ^= 1;
        !           491:                         break;
        !           492: 
        !           493:              default:
        !           494:                 if (!keystate[kc]) {
        !           495:                     keystate[kc] = true;
        !           496:                     record_key (kc << 1);
        !           497:                 }
        !           498:                 break;
        !           499:             }
        !           500:             break;
        !           501:         }
        !           502:         case keyUp: {       
        !           503:             if (Joy) break;
        !           504:             kc = keycode2amiga(event.message);
        !           505:             if (kc == -1) break;
        !           506:             keystate[kc] = false;
        !           507:             record_key ((kc << 1) | 1);
        !           508:             break;
        !           509:         }
        !           510:         case mouseDown:
        !           511:            if (RM == true) buttonstate[2] = true;
        !           512:            else buttonstate[0] = true;
        !           513:            break;
        !           514:         case mouseUp:
        !           515:            buttonstate[0] = false;
        !           516:            buttonstate[2] = false;
        !           517:            break;
        !           518:        }
        !           519:        GetMouse(&mpos);
        !           520:        if (mpos.h != lastmx) { lastmx=mpos.h; repeat = true; }
        !           521:        if (mpos.v != lastmy) { lastmy=mpos.v; repeat = true; }
        !           522:     } while (repeat);
        !           523:     
        !           524: label1:
        !           525:     /* "Affengriff" */
        !           526:     if(keystate[AK_CTRL] && keystate[AK_LAMI] && keystate[AK_RAMI])
        !           527:        MC68000_reset();
        !           528: }
        !           529: 
        !           530: bool debuggable()
        !           531: {
        !           532:     return true;
        !           533: }
        !           534: 
        !           535: bool needmousehack()
        !           536: {
        !           537:     return true;
        !           538: }
        !           539: 
        !           540: void LED(int on)
        !           541: {
        !           542: }
        !           543: 
        !           544: void parse_cmdline ()
        !           545: {
        !           546:     /* No commandline on the Mac. Implemented on Menus soon!*/
        !           547: }
        !           548: 
        !           549: // Check Minimal System Configuration and Setup
        !           550: static Boolean CheckForSetup (void)
        !           551: {      Boolean                 retvalue=FALSE;
        !           552:        SysEnvRec               env;
        !           553:        
        !           554:        SysEnvirons( 2, &env );
        !           555:        
        !           556:        if ( env.systemVersion < 0x0700 )
        !           557:        {       ParamAString("\pUAE requires System 7 or later!");
        !           558:                DisplayError(kQuitError);
        !           559:                retvalue=TRUE;
        !           560:        }
        !           561:        if ( !env.hasColorQD)
        !           562:        {       ParamAString("\pUAE requires Color QuickDraw!");
        !           563:                DisplayError(kQuitError);
        !           564:                retvalue=TRUE;
        !           565:        }
        !           566:        if ( env.processor < 3)
        !           567:        {       ParamAString("\pUAE requires a 68020 or better processor to run!");
        !           568:                DisplayError(kQuitError);
        !           569:                retvalue=TRUE;
        !           570:        }
        !           571:        curDevice = GetMainDevice();
        !           572:        if ((*curDevice)->gdPMap == NULL || (*(*curDevice)->gdPMap)->pixelSize != 16)
        !           573:        {       if (HasDepth(curDevice,16,0,0) == 0)
        !           574:                {       ParamAString("\pUAE requires 16 bit color and your display doesn't support it!");
        !           575:                        DisplayError(kQuitError);
        !           576:                        retvalue=TRUE;
        !           577:                }
        !           578:                else
        !           579:                {
        !           580:                oldDepth=(*(*curDevice)->gdPMap)->pixelSize;
        !           581:                SetDepth(curDevice,16,0,0);
        !           582:                }
        !           583:        }
        !           584:        return(retvalue);
        !           585: }
        !           586: 
        !           587: // Shows up the standard error alert;
        !           588: int DisplayError(int ID)
        !           589: {      int     ret=0;
        !           590: 
        !           591:        InitCursor();
        !           592:        ret=Alert(ID,0);
        !           593: 
        !           594:        return (ret);
        !           595: }
        !           596: 
        !           597: // Parses a Pascal string for error display
        !           598: void ParamAString( ConstStr255Param theStr )
        !           599: {
        !           600:        ParamText(theStr, "\p", "\p", "\p");
        !           601: }

unix.superglobalmegacorp.com

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