Annotation of researchv9/X11/src/X.V11R1/lib/oldXtk/Form.c, revision 1.1.1.1

1.1       root        1: /* $Header: Form.c,v 1.1 87/09/11 07:58:23 toddb Exp $ */
                      2: #ifndef lint
                      3: static char *sccsid = "@(#)Form.c      1.17    5/18/87";
                      4: #endif lint
                      5: /*
                      6:  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
                      7:  * 
                      8:  *                         All Rights Reserved
                      9:  * 
                     10:  * Permission to use, copy, modify, and distribute this software and its 
                     11:  * documentation for any purpose and without fee is hereby granted, 
                     12:  * provided that the above copyright notice appear in all copies and that
                     13:  * both that copyright notice and this permission notice appear in 
                     14:  * supporting documentation, and that the name of Digital Equipment
                     15:  * Corporation not be used in advertising or publicity pertaining to
                     16:  * distribution of the software without specific, written prior permission.  
                     17:  * 
                     18:  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
                     19:  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
                     20:  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
                     21:  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
                     22:  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
                     23:  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
                     24:  * SOFTWARE.
                     25:  */
                     26: 
                     27: #include "Xlib.h"
                     28: #include "Intrinsic.h"
                     29: #include "Form.h"
                     30: #include "Atoms.h"
                     31: 
                     32: 
                     33: /* Private Definitions */
                     34: 
                     35: 
                     36: typedef struct SubWidgetDataRec {
                     37:     Window w;                  /* Window id for this subwidget. */
                     38:     struct WidgetDataRec *data;        /* Pointer to form widget data. */
                     39:     XtEdgeType top, bottom, left, right;
                     40:                                /* Where to drag things on resize. */
                     41:     int dx;                    /* Desired initial horiz offset. */
                     42:     Window fromhoriz;          /* Other subwidget to base dx off of.
                     43:                                   (NULL if form edge.) */
                     44:     int dy;                    /* Desired initial vertical offset. */
                     45:     Window fromvert;           /* Other subwidget to base dy off of.
                     46:                                   (NULL if form edge.) */
                     47:     Boolean allowresize;       /* TRUE if we allow the subwidget to resize
                     48:                                   itself. */
                     49:     WindowBox wb;              /* Current coordinates.  */
                     50: } SubWidgetDataRec, *SubWidgetData;
                     51: 
                     52: 
                     53: static SubWidgetDataRec subglob;
                     54: static SubWidgetDataRec subinit = {0};
                     55: 
                     56: typedef struct WidgetDataRec {
                     57:     Display *dpy;              /* Display connection for the form widget */
                     58:     Window mywin;              /* Window ID of form widget. */
                     59:     WindowBox wb;              /* Coordinates of form widget. */
                     60:     SubWidgetData *sub;                /* Array of subwidgets. */
                     61:     int numsub;                        /* Number of subwidgets. */
                     62:     Pixel background;          /* Background color. */
                     63:     Pixel border;              /* Border color. */
                     64:     int defaultdistance;       /* Default distance between widgets. */
                     65:     int dontrefigure;          /* Nonzero if we don't want to recalc. */
                     66:     Boolean needsrefigure;     /* TRUE if we need to recalc. */
                     67: } WidgetDataRec, *WidgetData;
                     68: 
                     69: /* !!! STATIC !!! */
                     70: static WidgetDataRec globaldata;
                     71: static WidgetDataRec globalinit = {0};
                     72: 
                     73: /* Private Data */
                     74: 
                     75: static Resource resources[] = {
                     76:     {XtNwindow, XtCWindow, XrmRWindow, sizeof(Window),
                     77:         (caddr_t)&globaldata.mywin, (caddr_t)NULL},
                     78:     {XtNborderWidth, XtCBorderWidth, XrmRInt, sizeof(int),
                     79:         (caddr_t)&globaldata.wb.borderWidth, (caddr_t)NULL},
                     80:     {XtNx, XtCX, XrmRInt, sizeof(int),
                     81:   (caddr_t)&globaldata.wb.x, (caddr_t)NULL},
                     82:     {XtNy, XtCY, XrmRInt, sizeof(int),
                     83:   (caddr_t)&globaldata.wb.y, (caddr_t)NULL},
                     84:     {XtNwidth, XtCWidth, XrmRInt, sizeof(int),
                     85:         (caddr_t)&globaldata.wb.width, (caddr_t)NULL},
                     86:     {XtNheight, XtCHeight, XrmRInt, sizeof(int),
                     87:         (caddr_t)&globaldata.wb.height, (caddr_t)NULL},
                     88:     {XtNbackground, XtCColor, XrmRPixel, sizeof(Pixel),
                     89:         (caddr_t)&globaldata.background, (caddr_t)&XtDefaultBGPixel},
                     90:     {XtNborder, XtCColor, XrmRPixel, sizeof(Pixel),
                     91:         (caddr_t)&globaldata.border,(caddr_t)&XtDefaultFGPixel},
                     92:     {XtNdefaultDistance, XtCThickness, XrmRInt,
                     93:        sizeof(int), (caddr_t)&globaldata.defaultdistance, (caddr_t)NULL},
                     94: };
                     95: 
                     96: static XtEdgeType defEdge = XtRubber;
                     97: 
                     98: static Resource subresources[] = {
                     99:     {XtNtop, XtCEdge, XtRJustify, sizeof(XtEdgeType),
                    100:         (caddr_t)&subglob.top, (caddr_t)&defEdge},
                    101:     {XtNbottom, XtCEdge, XtRJustify, sizeof(XtEdgeType),
                    102:         (caddr_t)&subglob.bottom, (caddr_t)&defEdge},
                    103:     {XtNleft, XtCEdge, XtRJustify, sizeof(XtEdgeType),
                    104:         (caddr_t)&subglob.left, (caddr_t)&defEdge},
                    105:     {XtNright, XtCEdge, XtRJustify, sizeof(XtEdgeType),
                    106:         (caddr_t)&subglob.right, (caddr_t)&defEdge},
                    107:     {XtNfromHoriz, XtCWindow, XrmRWindow, sizeof(Window),
                    108:         (caddr_t)&subglob.fromhoriz, (caddr_t)NULL},
                    109:     {XtNfromVert, XtCWindow, XrmRWindow, sizeof(Window),
                    110:         (caddr_t)&subglob.fromvert, (caddr_t)NULL},
                    111:     {XtNhorizDistance, XtCThickness, XrmRInt, sizeof(int),
                    112:         (caddr_t)&subglob.dx, (caddr_t)NULL},
                    113:     {XtNvertDistance, XtCThickness, XrmRInt, sizeof(int),
                    114:         (caddr_t)&subglob.dy, (caddr_t)NULL},
                    115:     {XtNresizable, XtCBoolean, XrmRBoolean, sizeof(Boolean),
                    116:         (caddr_t)&subglob.allowresize, (caddr_t) NULL}
                    117: };
                    118: 
                    119: 
                    120: static XContext formContext;
                    121: static XContext subContext;
                    122: 
                    123: /****************************************************************
                    124:  *
                    125:  * Private Procedures
                    126:  *
                    127:  ****************************************************************/
                    128: 
                    129: static Boolean initialized = FALSE;
                    130: 
                    131: static void Initialize () 
                    132: {
                    133:     if (initialized)
                    134:        return;
                    135:     initialized = TRUE;
                    136: 
                    137:     subinit.top = subinit.bottom = subinit.left = subinit.right = XtRubber;
                    138:     subinit.wb.x = subinit.wb.y = -1;
                    139: 
                    140:     globalinit.wb.width = globalinit.wb.height = 10;
                    141:     globalinit.wb.x = globalinit.wb.y = 0;
                    142:     globalinit.defaultdistance = 4;
                    143:     globalinit.wb.borderWidth = 1;
                    144: 
                    145:     formContext = XUniqueContext();
                    146:     subContext = XUniqueContext();
                    147: }
                    148: 
                    149: 
                    150: static WidgetData DataFromWindow(dpy, w)
                    151: Display *dpy;
                    152: Window w;
                    153: {
                    154:     WidgetData result;
                    155:     if (XFindContext(dpy, w, formContext, (caddr_t *)&result))
                    156:        return NULL;
                    157:     return result;
                    158: }
                    159: 
                    160: static SubWidgetData SubFromWindow(dpy, w)
                    161: Display *dpy;
                    162: Window w;
                    163: {
                    164:     SubWidgetData result;
                    165:     if (XFindContext(dpy, w, subContext, (caddr_t *)&result))
                    166:        return NULL;
                    167:     return result;
                    168: }
                    169: 
                    170: static void RefigureLocations(data)
                    171: WidgetData data;
                    172: {
                    173:     int i;
                    174:     Position x, y, maxx, maxy;
                    175:     SubWidgetData sub, sub2;
                    176:     WindowBox reqBox, replBox;
                    177:     XtGeometryReturnCode result;
                    178:     if (data->dontrefigure) {
                    179:        data->needsrefigure = TRUE;
                    180:        return;
                    181:     }
                    182:     maxx = maxy = 0;
                    183:     for (i=0 ; i<data->numsub ; i++) {
                    184:        sub = data->sub[i];
                    185:        x = sub->dx;
                    186:        y = sub->dy;
                    187:        if (sub->fromhoriz && (sub2 = SubFromWindow(data->dpy, sub->fromhoriz)))
                    188:            x += sub2->wb.x + sub2->wb.width;
                    189:        if (sub->fromvert && (sub2 = SubFromWindow(data->dpy, sub->fromvert)))
                    190:            y += sub2->wb.y + sub2->wb.height;
                    191:        if (x != sub->wb.x || y != sub->wb.y) {
                    192:            XMoveWindow(data->dpy, sub->w, x, y);
                    193:            sub->wb.x = x;
                    194:            sub->wb.y = y;
                    195:        }
                    196:        if (maxx < x + sub->wb.width) maxx = x + sub->wb.width;
                    197:        if (maxy < y + sub->wb.height) maxy = y + sub->wb.height;
                    198:     }
                    199:     maxx += data->defaultdistance;
                    200:     maxy += data->defaultdistance;
                    201:     if (maxx != data->wb.width || maxy != data->wb.height) {
                    202:        reqBox.width = maxx;
                    203:        reqBox.height = maxy;
                    204:        result = XtMakeGeometryRequest(data->dpy, data->mywin, XtgeometryResize,
                    205:                                       &reqBox, &replBox);
                    206:        if (result == XtgeometryAlmost) {
                    207:            replBox = reqBox;
                    208:            result = XtMakeGeometryRequest(data->dpy, data->mywin, XtgeometryResize,
                    209:                                           &reqBox, &replBox);
                    210:        }
                    211:        if (result == XtgeometryYes) {
                    212:            data->wb.width = reqBox.width;
                    213:            data->wb.height = reqBox.height;
                    214:        }
                    215:     }
                    216:     data->needsrefigure = FALSE;
                    217: }
                    218: 
                    219: 
                    220: static int MoveEdge(loc, old, new, type)
                    221: int loc, old, new;
                    222: XtEdgeType type;
                    223: {
                    224:     if (type == XtRubber)
                    225:        return loc * new / old;
                    226:     if (type == XtChainTop || type == XtChainLeft)
                    227:        return loc;
                    228:     return loc + new - old;
                    229: }
                    230: 
                    231: static void ChangeSize(data, newwidth, newheight)
                    232: WidgetData data;
                    233: int newwidth, newheight;
                    234: {
                    235:     int i;
                    236:     SubWidgetData sub;
                    237:     WindowBox wb;
                    238:     for (i=0 ; i<data->numsub ; i++) {
                    239:        sub = data->sub[i];
                    240:        wb.borderWidth = sub->wb.borderWidth;
                    241:        wb.x = MoveEdge(sub->wb.x, (int)data->wb.width, newwidth, sub->left);
                    242:        wb.y = MoveEdge(sub->wb.y, (int)data->wb.height, newheight, sub->top);
                    243:        wb.width =
                    244:            MoveEdge((int)(sub->wb.x + sub->wb.width),
                    245:                       (int)data->wb.width, newwidth, sub->right) - wb.x;
                    246:        wb.height = MoveEdge((int)(sub->wb.y + sub->wb.height),
                    247:                            (int)data->wb.height, newheight, sub->bottom)
                    248:                        - wb.y;
                    249:        if (wb.width < 1) wb.width = 1;
                    250:        if (wb.height < 1) wb.height = 1;
                    251:        if (wb.x != sub->wb.x || wb.y != sub->wb.y ||
                    252:                wb.width != sub->wb.width || wb.height != sub->wb.height) {
                    253:            XMoveResizeWindow(data->dpy, sub->w, wb.x, wb.y,
                    254:                              wb.width, wb.height);
                    255:            (void) XtSendConfigureNotify(data->dpy, sub->w, &wb);
                    256:            sub->wb = wb;
                    257:        }
                    258:     }
                    259:     data->wb.width = newwidth;
                    260:     data->wb.height = newheight;
                    261: }
                    262: 
                    263: 
                    264: /* ARGSUSED */
                    265: static XtGeometryReturnCode FormGeometryHandler(dpy, w, req, reqBox, replBox)
                    266: Display *dpy;
                    267: Window w;
                    268: XtGeometryRequest req;
                    269: WindowBox *reqBox;
                    270: WindowBox *replBox;    /* RETURN */
                    271: {
                    272:     SubWidgetData sub;
                    273:     sub = SubFromWindow(dpy, w);
                    274:     if (sub && req == XtgeometryResize && sub->allowresize) {
                    275:        XResizeWindow(sub->data->dpy, sub->w, reqBox->width, reqBox->height);
                    276:        *replBox = *reqBox;
                    277:        sub->wb.width = reqBox->width;
                    278:        sub->wb.height = reqBox->height;
                    279:        (void) XtSendConfigureNotify(sub->data->dpy, w, &(sub->wb));
                    280:        RefigureLocations(sub->data);
                    281:        return XtgeometryYes;
                    282:     }
                    283:     return XtgeometryNo;
                    284: }
                    285: 
                    286: 
                    287: /*
                    288:  *
                    289:  * Destroy the widget
                    290:  *
                    291:  */
                    292: 
                    293: static void Destroy(data)
                    294: WidgetData data;
                    295: {
                    296:     int i;
                    297:     for (i=0 ; i<data->numsub; i++) {
                    298:        (void) XDeleteContext(data->dpy, data->sub[i]->w, subContext);
                    299:        (void) XtSendDestroyNotify(data->dpy, data->sub[i]->w);
                    300:     }
                    301:     XtClearEventHandlers(data->dpy, data->mywin);
                    302:     (void) XDeleteContext(data->dpy, data->mywin, formContext);
                    303:     XtFree((char *) data->sub);
                    304:     XtFree((char *) data);
                    305: }
                    306: 
                    307: 
                    308: /*
                    309:  *
                    310:  * Generic widget event handler
                    311:  *
                    312:  */
                    313: 
                    314: static XtEventReturnCode EventHandler(event, eventdata)
                    315: XEvent *event;
                    316: caddr_t eventdata;
                    317: {
                    318:     WidgetData data = (WidgetData ) eventdata;
                    319:     int newwidth, newheight;
                    320: 
                    321:     switch (event->type) {
                    322:        case ConfigureNotify:
                    323:            newwidth = event->xconfigure.width;
                    324:            newheight = event->xconfigure.height;
                    325:            if (newwidth != data->wb.width || newheight != data->wb.height)
                    326:                ChangeSize(data, newwidth, newheight);
                    327:            break;
                    328: 
                    329:        case DestroyNotify:
                    330:            Destroy(data);
                    331:            break;
                    332:        
                    333:     }
                    334:     return (XteventHandled);
                    335: }
                    336: 
                    337: /*
                    338:  * Handle events in subwidgets. 
                    339:  */
                    340: 
                    341: static XtEventReturnCode SubEventHandler(event, sub)
                    342: XEvent *event;
                    343: SubWidgetData sub;
                    344: {
                    345:     if (event->type == DestroyNotify) {
                    346:        XtFormRemoveWidget(sub->data->dpy, sub->data->mywin, sub->w);
                    347:        return XteventHandled;
                    348:     }
                    349:     return XteventNotHandled;
                    350: }
                    351: 
                    352: /****************************************************************
                    353:  *
                    354:  * Public Procedures
                    355:  *
                    356:  ****************************************************************/
                    357: 
                    358: Window XtFormCreate(dpy, parent, args, argCount)
                    359: Display  *dpy;
                    360: Window   parent;
                    361: ArgList  args;
                    362: int      argCount;
                    363: {
                    364:     WidgetData data;
                    365:     XrmNameList  names;
                    366:     XrmClassList classes;
                    367:     if (!initialized)
                    368:        Initialize ();
                    369: 
                    370:     data = (WidgetData) XtMalloc(sizeof(WidgetDataRec));
                    371: 
                    372:     /* Set Default Values */
                    373:     globaldata = globalinit;
                    374:     globaldata.dpy = dpy;
                    375:     XtGetResources(dpy, resources, XtNumber(resources), args, argCount, parent,
                    376:                   "form", "Form", &names, &classes);
                    377:     *data = globaldata;    
                    378: 
                    379:     data->numsub = 0;
                    380:     data->sub = (SubWidgetData *)XtMalloc(sizeof(SubWidgetData));
                    381:     if (data->mywin != NULL) {
                    382:        XWindowAttributes wi;
                    383:        /* set global data from window parameters */
                    384:        if (! XGetWindowAttributes(data->dpy, data->mywin, &wi)) {
                    385:            data->mywin = NULL;
                    386:        } else {
                    387:            data->wb.borderWidth = wi.border_width;
                    388:            data->wb.width = wi.width;
                    389:            data->wb.height = wi.height;
                    390:             data->wb.x = wi.x;
                    391:             data->wb.y = wi.y;
                    392:        }
                    393:     }
                    394:     if (data->mywin == NULL) {
                    395:        /* create the Form window */
                    396:         data->mywin = XCreateSimpleWindow(data->dpy, parent, data->wb.x,
                    397:                                          data->wb.y, data->wb.width, data->wb.height,
                    398:                                          data->wb.borderWidth,
                    399:                                          data->border, data->background);
                    400:     }
                    401: 
                    402:     XtSetNameAndClass(data->dpy, data->mywin, names, classes);
                    403:     XrmFreeNameList(names);
                    404:     XrmFreeClassList(classes);
                    405:     (void) XSaveContext(data->dpy, data->mywin, formContext, (caddr_t)data);
                    406: 
                    407:     /* set handler for resize, and message events */
                    408: 
                    409:     XtSetEventHandler (data->dpy, data->mywin, (XtEventHandler)EventHandler,
                    410:                       StructureNotifyMask, (caddr_t)data);
                    411: 
                    412:     return (data->mywin);
                    413: }
                    414: 
                    415: /*
                    416:  *
                    417:  * Get Attributes
                    418:  *
                    419:  */
                    420: 
                    421: void XtFormGetValues (dpy, w, args, argCount)
                    422: Display *dpy;
                    423: Window w;
                    424: ArgList args;
                    425: int argCount;
                    426: {
                    427:     WidgetData data;
                    428: 
                    429:     if ((data = DataFromWindow(dpy, w)) == NULL)
                    430:        return;
                    431:     globaldata = *data;
                    432:     XtGetValues(resources, XtNumber(resources), args, argCount);
                    433: }
                    434: 
                    435: /*
                    436:  *
                    437:  * Set Values
                    438:  *
                    439:  */
                    440: 
                    441: void XtFormSetValues (dpy, w, args, argCount)
                    442: Display *dpy;
                    443: Window w;
                    444: ArgList args;
                    445: int argCount;
                    446: {
                    447:     WidgetData data;
                    448: 
                    449:     if ((data = DataFromWindow(dpy, w)) == NULL)
                    450:        return;
                    451:     globaldata = *data;
                    452:     XtSetValues(resources, XtNumber(resources), args, argCount);
                    453:     *data = globaldata;
                    454: }
                    455: 
                    456: 
                    457: /*
                    458:  * Add a new widget to the form.
                    459:  */
                    460: 
                    461: void XtFormAddWidget(dpy, mywin, w, args, argCount)
                    462: Display *dpy;
                    463: Window mywin, w;
                    464: ArgList args;
                    465: int argCount;
                    466: {
                    467:     WidgetData data;
                    468:     SubWidgetData sub;
                    469:     XrmNameList names;
                    470:     XrmClassList classes;
                    471:     XWindowAttributes info;
                    472:     if ((data = DataFromWindow(dpy, mywin)) == NULL) return;
                    473:     if ((sub = SubFromWindow(dpy, w)) == NULL) {
                    474:        data->sub = (SubWidgetData *)
                    475:            XtRealloc((char *) data->sub,
                    476:                      (unsigned) sizeof(SubWidgetData) * ++data->numsub);
                    477:        sub = data->sub[data->numsub - 1] =
                    478:            (SubWidgetData) XtMalloc(sizeof(SubWidgetDataRec));
                    479:        (void)XSaveContext(dpy, w, subContext, (caddr_t)sub);
                    480:        *sub = subinit;
                    481:        sub->data = data;
                    482:        sub->w = w;
                    483:        sub->dx = sub->dy = data->defaultdistance;
                    484:        (void) XGetWindowAttributes(data->dpy, w, &info); /* %%% Icky-poo. */
                    485:        sub->wb.width = info.width;
                    486:        sub->wb.height = info.height;
                    487:        sub->wb.borderWidth = info.border_width;
                    488:        (void) XtSetGeometryHandler(dpy, w, (XtGeometryHandler) FormGeometryHandler);
                    489:        (void) XtSetEventHandler(dpy, w, (XtEventHandler)SubEventHandler,
                    490:                                 StructureNotifyMask, (caddr_t)sub);
                    491:     }
                    492:     subglob = *sub;
                    493:     XtGetResources(dpy, subresources, XtNumber(subresources), args, argCount,
                    494:                   w, "ignore", "Ignore", &names, &classes);
                    495:     *sub = subglob;
                    496:     XrmFreeNameList(names);
                    497:     XrmFreeClassList(classes);
                    498:     RefigureLocations(data);
                    499:     XMapWindow(data->dpy, w);
                    500: }
                    501: 
                    502: 
                    503: /*
                    504:  * Remove a subwidget from a form.  Doesn't delete the subwidget. 
                    505:  */
                    506: 
                    507: void XtFormRemoveWidget(dpy, mywin, w)
                    508: Display *dpy;
                    509: Window mywin, w;
                    510: {
                    511:     WidgetData data;
                    512:     SubWidgetData sub;
                    513:     Boolean found;
                    514:     int i;
                    515:     if ((data = DataFromWindow(dpy, mywin)) == NULL ||
                    516:        (sub = SubFromWindow(dpy, w)) == NULL) return;
                    517:     found = FALSE;
                    518:     for (i=0 ; i<data->numsub ; i++) {
                    519:        if (data->sub[i]->fromhoriz == w)
                    520:            data->sub[i]->fromhoriz = sub->fromhoriz;
                    521:        if (data->sub[i]->fromvert == w)
                    522:            data->sub[i]->fromvert = sub->fromvert;
                    523:        if (!found) found = (data->sub[i] == sub);
                    524:        if (found) data->sub[i] = data->sub[i+1];
                    525:     }
                    526:     if (found) (data->numsub)--;
                    527:     XtSetEventHandler(dpy, w, (XtEventHandler) SubEventHandler,
                    528:                      (unsigned long) 0, (caddr_t) NULL);
                    529:     (void) XtClearGeometryHandler(dpy, w);
                    530:     (void) XDeleteContext(dpy, w, subContext);
                    531:     XtFree((char *)sub);
                    532: }
                    533:     
                    534: 
                    535: 
                    536: /* 
                    537:  * Set or reset figuring
                    538:  */
                    539: 
                    540: void XtFormDoLayout(dpy, mywin, doit)
                    541: Display *dpy;
                    542: Window mywin;
                    543: Boolean doit;
                    544: {
                    545:     WidgetData data;
                    546:     if ((data = DataFromWindow(dpy, mywin)) == NULL)
                    547:        return;
                    548:     if (doit && data->dontrefigure > 0) data->dontrefigure--;
                    549:     else data->dontrefigure++;
                    550:     if (data->needsrefigure) RefigureLocations(data);
                    551: }

unix.superglobalmegacorp.com

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