home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 4 / CDPD_IV.bin / networking / dnet / dnet2.3.2 / amiga / client / remoteload.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-29  |  23.3 KB  |  931 lines

  1. /*
  2.  *  RemoteLoad.c
  3.  *
  4.  *  DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
  5.  *
  6.  *  RemoteLoad, a more or less complete rewrite of Loadav
  7.  *     (c) Copyright 1993, Eric mehlhaff, 
  8.  *
  9.  *  LOADAV  [frequency]     Connect to remote UNIX system and display
  10.  *                load average.  Default is every 5 minutes.
  11.  *
  12.  *  frequency in seconds, default is every 60 seconds
  13.  *
  14.  */
  15.  
  16. /* #define DEBUG */
  17. /* #define TEST */
  18.  
  19. #include <exec/types.h>
  20. #include <intuition/intuition.h>
  21. #include <stdio.h>
  22. #include <proto/all.h>
  23. #include <devices/conunit.h>
  24. #include <devices/timer.h>
  25.  
  26. #ifdef __GNUC__
  27. #include <signal.h>  /* for signal trapping */
  28. #endif
  29.  
  30.  
  31. #ifdef DEBUG
  32. #define IFDEBUG(foo)  foo
  33. #else
  34. #define IFDEBUG(foo)  
  35. #endif
  36.  
  37. #include "server/servers.h"
  38.  
  39.  
  40. typedef struct IntuiMessage     IMESS;
  41. typedef struct IntuiText     ITEXT;
  42. typedef struct Library         LIB;
  43.  
  44.  
  45. unsigned char Title[128];   /* string that goes in the title window */
  46. unsigned char Uptime[128];  /* Current uptime reading, from remote */
  47.  
  48. #define LOADWINBORDER 2   /* pixels to either side of the LoadWinBorder */
  49.  
  50.  
  51. struct NewWindow Nw = {
  52.     0, 0, /* width */320, /* height */50, -1, -1,
  53.     NEWSIZE|CLOSEWINDOW,
  54.     WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|NOCAREREFRESH,
  55.     NULL, NULL, Title, NULL, NULL,
  56.     32, 18, -1, -1, WBENCHSCREEN
  57. };
  58.  
  59. struct Window *Win;
  60. struct RastPort  *Rp;
  61.  
  62.  
  63. struct IntuitionBase *IntuitionBase;
  64. struct GfxBase *GfxBase;
  65.  
  66.  
  67. int main (int, char **);
  68.  
  69. int broken = 0;  /* set to on when we received a signal (via gcc's/ixemul's
  70.          ** pseudo-signaling system 
  71.          */
  72. void brk()
  73. {
  74.     broken = 1; 
  75. }
  76.  
  77. struct LoadInfo {
  78.    short NumUsers;  /* number of users online */
  79.    short Load1;  /*  1 minute average -- first value from uptime */
  80.    short Load2;  /*  5 minute average -- second value from uptime */
  81.    short Load3;  /* 15 minute average -- third value from uptime */
  82. };
  83.  
  84. struct LoadInfo * LoadElement( int );
  85.  
  86. int NumLoadData = 0;   /* number of load points */
  87.  
  88. struct LoadInfo * LoadData = NULL;  /* will point to the load data */
  89.     /* LoadData will be a dynamically allocated array of LoadInfo
  90.     ** structures
  91.     */
  92.  
  93. int LoadScale;     /* maximum load, fix the update window so that it scales
  94.            ** to this
  95.            */
  96. int MaxUsers;      /* maximum number of users, to use with load scale */
  97.  
  98. int LoadStart;     /* index of start of load data, within LoadData structure
  99.            ** used when we're concerned about the CPU load of just
  100.            ** moving the entire structure everytime it is updated
  101.            */
  102.  
  103. int UpdateIndex = -1;   /* index point of last element filled. Should range 
  104.             ** 0 to NumLoadData-1 , -1 if nothing's been filled
  105.             */
  106.  
  107. char * strsep();
  108.  
  109. int
  110. main(argc,argv)
  111. char *argv[];
  112. {
  113.     void *chan = NULL;
  114.     short numsecs = 60;
  115.     long imask, tmask, dmask, mask;
  116.     char notdone = 1;
  117.     char *host = NULL;
  118.     struct MsgPort *TimPort = CreatePort(NULL, 0);
  119.     struct timerequest Iot;
  120.  
  121. #ifdef __GNUC__
  122.     signal( SIGINT, brk); /* disable normal ^C handler */
  123. #else
  124.     onbrk(brk);
  125. #endif
  126.  
  127.     sprintf(Title, "%s V.5", argv[0]);
  128.  
  129.     {
  130.     int i;
  131.     int usage = 0;
  132.     for (i = 1; i < argc; ++i) {
  133.         if( *argv[i] != '-'){
  134.             numsecs = atoi(argv[i]);
  135.         if(numsecs < 1){
  136.             printf("Bad time value %s, try another number\n", argv[i]);
  137.         } else {
  138.             printf("Remote load polling period %d seconds\n", numsecs);
  139.         }
  140.         } else {
  141.             char swchar = *(argv[i]+1);
  142.             switch( swchar ){
  143.           case 'W': /* set window width */
  144.               if( argv[i+1])  Nw.Width = atoi(argv[i+1]);
  145.             i++; break;
  146.           case 'H': /* set window Height */
  147.               if( argv[i+1])  Nw.Height = atoi(argv[i+1]);
  148.             i++; break;
  149.           case 'T': /* set window Top */
  150.               if( argv[i+1])  Nw.TopEdge = atoi(argv[i+1]);
  151.             i++; break;
  152.           case 'L': /* set window LeftEdge */
  153.               if( argv[i+1])  Nw.LeftEdge = atoi(argv[i+1]);
  154.             i++; break;
  155.           case 'N':  /* set host to connect to */
  156.               if( argv[i+1]) host = argv[i+1];
  157.             i++; break;
  158.           default:
  159.             printf("unknown option -%c \n", swchar);
  160.           case '?':
  161.           case 'h':
  162.             usage = 1;
  163.             }
  164.         }
  165.     }
  166.     if(usage){
  167.         printf("%s Usage:\n", argv[0]);
  168.         printf("-L num\tLeftEdge\n");
  169.         printf("-T num\tTopEdge\n");
  170.         printf("-H num\tHeight\n");
  171.         printf("-W num\tWidth\n");
  172.         printf("-N name\tDNet Host to connect to\n");
  173.         printf("-h or -?\t get usage information.\n");
  174.         printf(" num\t load polling period, in seconds" ); 
  175.         goto fail;
  176.     }
  177.     }
  178.  
  179.  
  180.     Iot.tr_node.io_Device = NULL;
  181.  
  182.     if (OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)&Iot, 0)){
  183.     printf("TimerDevice open failed??!\n");
  184.     goto fail;
  185.     }
  186.     Iot.tr_node.io_Command = TR_ADDREQUEST;
  187.     Iot.tr_node.io_Message.mn_ReplyPort = TimPort;
  188.     Iot.tr_time.tv_micro = 1;
  189.     Iot.tr_time.tv_secs  = 0;
  190.     SendIO((struct IORequest *)&Iot);
  191.  
  192. #if !defined( LATTICE) && !defined( __GNUC__)
  193.     Enable_Abort = 0; 
  194. #endif
  195.  
  196.     IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
  197.     if(IntuitionBase == NULL){
  198.        puts("Ack, couldn\'t open intuition.library!");
  199.        goto fail;
  200.     }
  201.     if((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0)) == NULL){
  202.        puts("Ack, couldn\'t open graphics.library!");
  203.        goto fail;
  204.     }
  205.  
  206. #ifndef TEST
  207.     chan = (void *) DOpen(host, PORT_LOADAV, 25, 25);
  208.     if (chan == NULL) {
  209.     puts("DOpen failed to connect!");
  210.     IFDEBUG(sleep(1);)
  211.     goto fail;
  212.     }
  213.     IFDEBUG(puts("DOpen() done"));
  214. #endif /* TEST */
  215.  
  216.     AdjustNewWindow(&Nw);  /* for negative offsets in windows and such */
  217.  
  218.     Win = OpenWindow(&Nw);
  219.     if (Win == NULL) {
  220.     puts("Unable to open window");
  221.     goto fail;
  222.     }
  223.     IFDEBUG(printf("Window opened...\n"));
  224.  
  225.     Rp = Win->RPort;
  226.     imask   = 1 << Win->UserPort->mp_SigBit;
  227. #ifndef TEST
  228.     dmask   = 1 << ((struct MsgPort *)chan)->mp_SigBit;
  229. #else
  230.     dmask   = 0 ;  /* What SigBit? */
  231. #endif
  232.     tmask   = 1 << TimPort->mp_SigBit;
  233.  
  234.     IFDEBUG(printf("signal masks: i %x, d %x, t %x\n", imask, dmask, tmask));
  235.  
  236.     DrawLoadWindow();
  237.     IFDEBUG(printf("LoadWindow Drawn...\n"));
  238.  
  239. #ifdef TEST
  240.     /* so we don't have to wait as long for data to test out with */
  241.     for(notdone=1;notdone<100;notdone++){
  242.     RandomLoadUpdate();   /* generate a random load input */
  243.     UpdateLoad();
  244.     }
  245.     notdone = 1;
  246. #endif
  247.  
  248.     while (notdone) {
  249.     mask = Wait(imask|dmask|tmask|SIGBREAKF_CTRL_C);
  250.         IFDEBUG(printf("signal(s) gotten:%x\n", mask));
  251.     if (mask & SIGBREAKF_CTRL_C){
  252.         notdone = 0;
  253.     }
  254.  
  255.     if (mask & imask) {  /* handle intuition messages */
  256.         IMESS *im;
  257.         while (im = (IMESS *)GetMsg(Win->UserPort)) {
  258.         IFDEBUG(printf("UserPort message:%d\n", im->Class);)
  259.         switch(im->Class) {
  260.         case NEWSIZE:
  261.             DrawLoadWindow();
  262.             break;
  263.         case CLOSEWINDOW:
  264.             notdone = 0;
  265.             break;
  266.         }
  267.         ReplyMsg((struct Message *)im);
  268.         }
  269.     }
  270.  
  271.     if (mask & dmask) {  /* DNet communications message */
  272.         char dummy;
  273.         if ((dummy = DNRead(chan, &dummy, 1)) != 0)
  274.         notdone = 0;
  275.         IFDEBUG(printf("DNRead resulted %d \n", dummy));
  276.     }
  277.  
  278.     if (mask & tmask) { /* a timer message */
  279.         char len = 0;
  280.  
  281.         IFDEBUG(printf("tmask\n"));
  282.  
  283.         if (GetMsg(TimPort)) {
  284.         Iot.tr_time.tv_micro = 0;
  285.         Iot.tr_time.tv_secs  = numsecs;
  286.         SendIO((struct IORequest *)&Iot);
  287.  
  288. #ifndef TEST
  289.         /* synch dnet by writing one '\0' character, and then
  290.         ** getting a response of one character.
  291.         ** this response is the length of the `uptime` string
  292.         ** we need to parse
  293.         */
  294.         if (DWrite(chan, &len, 1) == 1 && DRead(chan, &len, 1) == 1) {
  295.             if (len < sizeof(Uptime) && DRead(chan, Uptime, len) == len) {
  296.             Uptime[len] = 0;
  297.             IFDEBUG(printf("updatewindow() \n"));
  298.             UpdateLoad();
  299.             } else {
  300.             puts("Error: Could not get uptime!");
  301.                 if(len < sizeof(Uptime)){
  302.                 puts("DRead() confusion, I give up"); 
  303.                 notdone = 0;
  304.             }  else {
  305.                 printf("Overlong(%d) uptime string received...\n",
  306.                     len );
  307.             }
  308.             }
  309.         } else {
  310.             puts("Remote DNet Error, bye..");
  311.             notdone = 0;
  312.         }
  313. #else  /* TEST */
  314.         RandomLoadUpdate();   /* generate a random load input */
  315.         UpdateLoad();
  316. #endif
  317.         }
  318.     }
  319.     }
  320.  
  321.  
  322. fail:
  323.     IFDEBUG(printf("Shutting things down...\n"));
  324.     if (Iot.tr_node.io_Device) {
  325.     AbortIO((struct IORequest *)&Iot);
  326.     WaitIO((struct IORequest *)&Iot);
  327.     CloseDevice((struct IORequest *)&Iot);
  328.     }
  329.     DeletePort(TimPort);
  330.     IFDEBUG(printf("TimerPort deleted...\n"));
  331.     if (Win){
  332.     CloseWindow(Win);
  333.     IFDEBUG(printf("Window closed...\n"));
  334.     }
  335.     if (chan){
  336.     DClose(chan);
  337.     IFDEBUG(printf("channel DClosed()...\n"));
  338.     }
  339.     if (IntuitionBase)
  340.     CloseLibrary((LIB *)IntuitionBase);
  341.     if (GfxBase)
  342.     CloseLibrary((LIB *)GfxBase);
  343.  
  344.     if ( LoadData){
  345.     IFDEBUG(printf("LoadData freed at %x...\n", LoadData));
  346.         free(LoadData);
  347.     }
  348.  
  349.     IFDEBUG(printf("all done...\n"));
  350. }
  351.  
  352. /*
  353.  *  Graphics routines.    ************************************************
  354.  */
  355.  
  356. short     WOx, /* XOffset of window edge */
  357.     WOy, /* Y offset of window edge */
  358.      Ww,  /* width of drawable area inside window */
  359.     Wh;  /* height of drawable area inside window */
  360.  
  361. short LoadYPos(  short val , short maxrange){
  362.     short ypos;
  363.     ypos = Wh * val / maxrange;
  364.     return WOy + Wh - ypos ;
  365. }
  366.  
  367. /* draw all the graphics for the window */
  368. DrawWindow()
  369. {
  370.     short i, j, d;
  371.     short ypos;
  372.     register struct LoadInfo * ldta;
  373.     int notmoved = 1;
  374.  
  375.     IFDEBUG(printf("Start DrawWindow()\n"));
  376.  
  377.  
  378.     WOx = Win->BorderLeft;  /* the start of the drawable areas of the window */
  379.     WOy = Win->BorderTop;
  380.  
  381.     /* get sizes of drawable area of the window */
  382.     Ww    = Win->Width - Win->BorderRight - Win->BorderLeft -1 ;   
  383.     Wh    = Win->Height- Win->BorderTop    - Win->BorderBottom -1 ; 
  384.  
  385.     SetAPen(Rp, 0);   /* set pen to draw 'clear' color */
  386.     RectFill(Rp, WOx, WOy, Ww + WOx, Wh + WOy);  /* fill rectangle */
  387.  
  388.  
  389.     /* shrink in a few pixels for an internal border ? */
  390.     WOx += LOADWINBORDER; 
  391.     WOy += LOADWINBORDER; 
  392.     Ww -= LOADWINBORDER * 2; 
  393.     Wh -= LOADWINBORDER * 2;   
  394.  
  395.     if(Ww < 0) Ww = 0; 
  396.     if(Wh < 0) Wh = 0; 
  397.  
  398.     /* if window's too small to draw anytyhing, don't... */
  399.     if(Ww == 0) return;
  400.     if(Wh == 0) return;
  401.  
  402.     /* draw the load scale lines, if any */
  403.     if( LoadScale > 1 ){
  404.     IFDEBUG(printf("Drawing Max Load scale lines Max: %d\n", LoadScale));
  405.     SetAPen(Rp,  3 );
  406.         for(i=1;i< LoadScale;i++){
  407.         ypos = LoadYPos( i * 100, LoadScale * 100 );
  408.         Move(Rp, WOx, ypos);
  409.         Draw(Rp, WOx+Ww, ypos);
  410.     }
  411.     }
  412.  
  413.     /*
  414.      *    Redraw the graph.  Scale values relative to LoadScale and Wh.
  415.      *
  416.      */
  417.  
  418.     /* Someting to do later:  move all these move/draw calls into a single
  419.     ** PolyDraw
  420.     */
  421.  
  422.     /* draw curve for number of users */
  423.     SetAPen(Rp, 3 );
  424.     notmoved = 1;
  425.     for (i = 0; i <= UpdateIndex; i++) {
  426.     if( (ldta = LoadElement(i)) == NULL) continue;
  427.     if(ldta->NumUsers  == -1) continue;
  428.     ypos = LoadYPos(ldta->NumUsers, MaxUsers);
  429.     if( notmoved ) {
  430.         Move( Rp, WOx + i, ypos ) ;
  431.         notmoved = 0;
  432.     } else {
  433.         Draw( Rp, WOx + i, ypos ) ;
  434.     }
  435.     }
  436.     IFDEBUG(printf("done Drawing lines for Numusers \n"));
  437.  
  438.     /* draw curve for load 0 */
  439.     SetAPen(Rp, 1 );
  440.     notmoved = 1;
  441.     for (i = 0; i < NumLoadData; i++) {
  442.     if( (ldta = LoadElement(i)) == NULL) continue;
  443.     if(ldta->NumUsers  == -1) continue;
  444.     ypos = LoadYPos( ldta->Load1, LoadScale * 100 );
  445.     if(notmoved) {
  446.         Move( Rp, WOx + i, ypos ) ;
  447.         notmoved = 0;
  448.     } else {
  449.         Draw( Rp, WOx + i, ypos ) ;
  450.     }
  451.     }
  452.     IFDEBUG(printf("Done Drawing lines for Load \n"));
  453. }
  454.  
  455.  
  456. UpdateLoadWindow(){
  457.     struct LoadInfo *ptr1, *ptr2;
  458.     short Xpos, OldX, Ypos, OldY;
  459.     IFDEBUG(puts("UpdateLoadWindow"));
  460.  
  461.     ptr1 = LoadElement( UpdateIndex - 1 );
  462.     ptr2 = LoadElement( UpdateIndex );
  463.  
  464.     if(ptr1 == NULL || ptr2 == NULL ) return;
  465.  
  466.     if((ptr1->NumUsers == -1) ||(ptr2->NumUsers == -1)) {
  467.     IFDEBUG(printf("UpdateLoadWindow bad Numusers: %d, %d\n",ptr1->NumUsers, ptr2->NumUsers));
  468.     return;
  469.     }
  470.  
  471.     if(UpdateIndex >= NumLoadData - 1){
  472.     ScrollRaster(Rp, 1, 0, WOx, WOy, WOx + Ww + 1 , WOy + Wh );
  473.     }
  474.  
  475.     Xpos = WOx + UpdateIndex + 1 ;
  476.     OldX = WOx + UpdateIndex ;
  477.  
  478.     /* draw the load scale lines, if any */
  479.     if( LoadScale > 1 ){
  480.     short i, ypos;
  481.     IFDEBUG(printf("Updating Load scale lines Max: %d\n", LoadScale));
  482.         for(i=1;i< LoadScale;i++){
  483.         ypos = LoadYPos( i * 100, LoadScale * 100 );
  484.         SetAPen(Rp,  3 );
  485.         Move(Rp, OldX, ypos);
  486.         Draw(Rp, Xpos, ypos);
  487.     }
  488.     }
  489.  
  490.     /* update NumUsers */
  491.     OldY = LoadYPos(ptr1->NumUsers , MaxUsers);
  492.     Ypos = LoadYPos(ptr2->NumUsers , MaxUsers);
  493.     SetAPen(Rp, 3);
  494.     Move(Rp, OldX, OldY);
  495.     Draw(Rp, Xpos, Ypos);
  496.     IFDEBUG(printf("Users update: %d,%d to %d,%d\n", OldX, OldY, Xpos, Ypos));
  497.  
  498.     /* Update Load average */
  499.     OldY =  LoadYPos(ptr1->Load1 , LoadScale * 100);
  500.     Ypos =  LoadYPos(ptr2->Load1 , LoadScale * 100);
  501.     SetAPen(Rp, 1);
  502.     Move(Rp, OldX, OldY);
  503.     Draw(Rp, Xpos, Ypos);
  504.     IFDEBUG(printf("Load update: %d,%d to %d,%d\n", OldX, OldY, Xpos, Ypos));
  505.  
  506.     IFDEBUG(puts("UpdateLoadWindow done");) 
  507. }
  508.  
  509. DrawLoadWindow(){
  510.     /* for now, just do basic stuff */
  511.     IFDEBUG(puts("DrawLoadWindow()"));
  512.  
  513.     InitLoadData();
  514.  
  515.     DrawWindow();
  516. }
  517.  
  518. /*
  519.  *  uptime and load information held in string array Uptime[], in a format
  520.  *  something like this:
  521.  *
  522.  *  5:44pm up 2 days, 22:30, 37 users, load average: 5.98, 7.93, 7.97
  523.  *              7 mins,
  524.  *
  525.  *  this needs to be parsed...
  526.  */
  527.  
  528. /* Uptime will be parsed and stored into these : */
  529. char TimeStr[10];   /* the string holding the time.  i.e. 5:44pm */
  530. int  NumUsers;      /* the number of users */
  531. short Loads[3];     /* the 3 load averages.  Multiplied by 100 */
  532.  
  533. /* parse the Uptime string... */
  534. ParseUptime(){
  535.     char **tokens[20]; /* array of pointers to string arrays */
  536.     char ** ap = (char **) tokens;
  537.     char * val;
  538.     char * p;
  539.     int i;
  540.  
  541.     IFDEBUG(printf("Parsing Uptime:%s\n", Uptime));
  542.  
  543.     TimeStr[0]='\0';
  544.     NumUsers = -1;
  545.     Loads[1]=Loads[2]=Loads[3]=-1;
  546.  
  547.  
  548.     /* Fun with strsep, practically straight from the manpage! */
  549.     for( p = Uptime; p != NULL; ){
  550.     while((val = strsep(&p, " \t")) != NULL && *val == '\0');
  551.     /* IFDEBUG(printf("Separated string %s\n", val)); */
  552.     *ap++ = val;
  553.     }
  554.     *ap = 0;
  555.  
  556.     if(*tokens[0] != NULL){
  557.        strcpy(TimeStr, (char *)tokens[0]);
  558.     IFDEBUG(printf("TimeString parsed as \"%s\"\n", TimeStr));
  559.     }
  560.  
  561.     /* search for number of users token */
  562.     for(ap = (char **) tokens ; *ap != NULL; ap++){
  563.     if(strncmp(*ap, "users",4)) continue;
  564.     NumUsers = atoi( *(ap - 1));
  565.     IFDEBUG(printf("NumUsers parsed as %d\n", NumUsers));
  566.     break;
  567.     }
  568.  
  569.    /*  IFDEBUG(puts("Looking for loads...")); */
  570.  
  571.     /* now search out load average tokens */
  572.     for(ap = (char **) tokens ; *ap != NULL; ap++){
  573.     if(strncmp(*ap, "average",7)) continue;
  574.         /* IFDEBUG(puts("found \"average\"")); */
  575.     ap++;  if( *ap == NULL ) break;
  576.         /* IFDEBUG(printf("string for Load1 is %s\n", *ap ) ); */
  577.     Loads[0] = LoadParse( *ap );
  578.     ap++;  if( *ap == NULL ) break;
  579.         /* IFDEBUG(printf("string for Load2 is %s\n", *ap ) ); */
  580.     Loads[1] = LoadParse( *ap );
  581.     ap++;  if( *ap == NULL) break;
  582.     Loads[2] = LoadParse( *ap );
  583.     break;
  584.     }
  585.     IFDEBUG(printf("Loads parsed as %d %d %d\n", Loads[0], Loads[1], Loads[2]));
  586. }
  587.  
  588. /* LoadParse
  589. ** return load value parsed from string */
  590. int LoadParse(char * string){
  591.     char * strptr;
  592.     int loadval = 0;
  593.  
  594.     for(strptr = string; *strptr != '\0';strptr++){
  595.         if(*strptr == '.') continue;
  596.     if(*strptr >= '0' && *strptr <= '9'){
  597.         loadval = 10 * loadval + *strptr - '0';
  598.     } else 
  599.         break;
  600.     }
  601.     return loadval;
  602. }
  603.  
  604. /* return pointer to LoadInfo element for numbered 'index' */
  605. struct LoadInfo * LoadElement( int index){
  606.    int lindex;
  607.    struct LoadInfo *ptr;
  608.  
  609.    if(index < 0 || index >= NumLoadData) return NULL;
  610.    if(LoadData == NULL) return NULL;
  611.  
  612.    lindex = index + LoadStart;
  613.  
  614.    if( lindex >= NumLoadData) 
  615.        lindex -= NumLoadData;
  616.  
  617.    if(lindex < 0 || lindex >= NumLoadData){
  618.     IFDEBUG(printf("LoadElement() error, wacky lindex %d\n", lindex);)
  619.     IFDEBUG(printf("out of range 0-%d, sent %d, start %d\n", NumLoadData, index, LoadStart);)
  620.        return NULL;
  621.    }
  622.  
  623.    ptr= &(LoadData[lindex]);
  624.  
  625.    /* Way too much debugging info... 
  626.    IFDEBUG(printf("LoadElement(%d) is %x (of %x to %x)\n", index, ptr, LoadData, &(LoadData[NumLoadData -1]) ));
  627.    */
  628.  
  629.    return ptr;
  630. }
  631.  
  632.  
  633. /* add current load information to the stored LoadData  */
  634. UpdateLoadInfo(){
  635.    struct LoadInfo *addptr;
  636.  
  637.    UpdateIndex++;
  638.  
  639.    if(UpdateIndex >= NumLoadData -1){
  640.     LoadStart++;
  641.     if(LoadStart >= NumLoadData -1) LoadStart = 0;
  642.     UpdateIndex = NumLoadData -1 ;
  643.    }
  644.  
  645.    addptr = LoadElement(UpdateIndex);
  646.    if(addptr == NULL) return;
  647.  
  648.    addptr->NumUsers = NumUsers;
  649.    addptr->Load1 = Loads[0];
  650.    addptr->Load2 = Loads[1];
  651.    addptr->Load3 = Loads[2];
  652.  
  653. }
  654.  
  655. UpdateLoad()
  656. {
  657.     short d;
  658.     char refresh = 0;
  659.     short tmpscale = LoadScale * 100;
  660.  
  661.     IFDEBUG(puts("starting UpdateLoad()"));
  662.  
  663.     if(Uptime[0])
  664.         ParseUptime();
  665.     else
  666.         return;
  667.  
  668.     if( LoadData == NULL) {
  669.         InitLoadData();
  670.     if(LoadData == NULL){
  671.         puts("InitLoadData FAILED!");
  672.         return;
  673.     }
  674.     }
  675.  
  676.     UpdateLoadInfo();
  677.  
  678.     if(Loads[0] > tmpscale || Loads[1] > tmpscale || Loads[2] > tmpscale ||
  679.             NumUsers > MaxUsers ){
  680.         refresh = 1;
  681.     }
  682.  
  683.     if (refresh) {
  684.     DrawLoadWindow();
  685.     } else {
  686.         UpdateLoadWindow();
  687.     }
  688.  
  689. #ifdef HOZERS
  690.     sprintf(Title, "%s, %d hozers, Load: %2.2f %2.2f %2.2f", 
  691.         TimeStr, NumUsers, (double)Loads[0]/100, (double)Loads[1]/100, 
  692.     (double)Loads[2]/100);
  693. #else
  694.     snprintf(Title, sizeof(Title), "Load: %2.2f, %d users, %s", 
  695.         (double)Loads[0]/100, NumUsers, TimeStr);
  696. #endif
  697.     SetWindowTitles(Win, Title, (UBYTE *)-1);
  698.  
  699.  
  700.     IFDEBUG(puts("UpdateLoad() done"));
  701.     return;
  702. }
  703.  
  704.  
  705.  
  706. /* also used to re-init load data, when window sizes change */
  707. InitLoadData(){
  708.     struct LoadInfo * newloadarry = NULL;
  709.     int winwidth = 0;
  710.     int newscale;
  711.     int i;
  712.  
  713.     IFDEBUG(puts("InitLoadData() started "));
  714.  
  715.     if(Win != NULL)
  716.     winwidth = Win->Width - Win->BorderRight  
  717.         - Win->BorderLeft - 2 * LOADWINBORDER;  
  718.     if( winwidth < 0) winwidth = 0 ;
  719.  
  720.     if(winwidth != NumLoadData || LoadData == NULL){
  721.         newloadarry = (struct LoadInfo *) calloc( winwidth, 
  722.                             sizeof(struct LoadInfo));
  723.     IFDEBUG(printf("NewLoadarray is %x\n", newloadarry));
  724.     if(newloadarry == NULL) {
  725.         /* this is pretty serious. probably should go away */
  726.         return;
  727.     }
  728.  
  729.     /* 'clear the newloadarray */
  730.     for(i=0;i<winwidth;i++) 
  731.         newloadarry[i].NumUsers = -1;
  732.  
  733.     if( LoadData != NULL){
  734.         MapOldLoadDataOntoNew( winwidth, newloadarry);
  735.         IFDEBUG(printf("Freeing old LoadData at %x\n", LoadData));
  736.         free(LoadData);
  737.         LoadData = NULL;
  738.     }
  739.  
  740.     LoadStart = 0;
  741.     LoadData = newloadarry;
  742.     NumLoadData = winwidth;
  743.     if(UpdateIndex >= NumLoadData ) UpdateIndex = NumLoadData -1 ;
  744.     }
  745.  
  746.     GetLoadScale();
  747.     IFDEBUG(puts("InitLoadData() done "));
  748. }
  749.  
  750. #ifndef MAX
  751. #define MAX(a,b) ((a) > (b)? (a) : (b))
  752. #endif
  753.  
  754. /* return the largest load average within the known load data */
  755. int GetLoadScale(){
  756.    int i=0;
  757.    int maxload = 0;
  758.    int maxusers = 1;
  759.    struct LoadInfo * lp;
  760.    IFDEBUG(int lastload = maxload;)
  761.  
  762.    IFDEBUG(printf("GettingLoadScale() num elements:%d\n", UpdateIndex));
  763.    IFDEBUG(printf("Num: %d, Start: %d",NumLoadData, LoadStart));
  764.    for(i=0;i <= UpdateIndex;i++){
  765.        lp = LoadElement(i);
  766.     if(lp == NULL) continue;
  767. IFDEBUG(printf("Elem %d, #u: %d, ld %d\n",i, lp->NumUsers, lp->Load1));
  768.     if(lp->NumUsers == -1) continue;
  769.     maxusers = MAX(maxusers, lp->NumUsers);
  770.     maxload = MAX(maxload,  lp->Load1);
  771.     maxload = MAX(maxload,  lp->Load2);
  772.     maxload = MAX(maxload,  lp->Load3);
  773. #ifdef DEBUG
  774.     if(lastload != maxload) {
  775.         printf("New maxload %d at %d\n", maxload, i);
  776.         lastload = maxload;
  777.     }
  778. #endif
  779.    }
  780.    maxload = (int)(maxload / 100) +1;
  781.    LoadScale = maxload;
  782.    MaxUsers = maxusers;
  783.  
  784.    IFDEBUG(printf("GotLoadScale(%d) Load: %d  Users: %d \n",NumLoadData, LoadScale, MaxUsers) );
  785. }
  786.  
  787. /* copy over the old data to the new array 
  788. ** it has to start at 0 in the new array.
  789. */
  790. MapOldLoadDataOntoNew(int winwidth, struct LoadInfo * newloadarry){
  791.     int startindex, i;
  792.     int lindex;
  793.  
  794.     struct LoadInfo * ptr1;
  795.     struct LoadInfo * ptr2; 
  796.  
  797.     IFDEBUG(printf("MappingLoadData Old %d, New %d, Start %d, Num %d \n",NumLoadData, winwidth, LoadStart, UpdateIndex) );
  798.  
  799.     /* only keep most recent data if window is shrinking */
  800.     if( winwidth < UpdateIndex ){
  801.         startindex = UpdateIndex + 1 -  winwidth;
  802.     } else {
  803.         startindex = 0 ;
  804.     }
  805.  
  806.     for (i=startindex,lindex = 0; i <= UpdateIndex;i++){
  807.         ptr1 = LoadElement(i);
  808.     if(ptr1 == NULL) continue;
  809.  
  810.     ptr2 = &newloadarry[lindex];
  811.         IFDEBUG(if(lindex>=winwidth)printf("Map:lindex too big %d\n", lindex);)
  812.         lindex++;
  813.     memcpy( ptr2, ptr1, sizeof(struct LoadInfo));
  814.     }
  815. }
  816.  
  817.  
  818. /* we have a NewWindow structure that might have negative values in ts
  819. ** size or position fields
  820. ** we interpret these negative values to mean relative to relevant screen
  821. ** size.
  822. ** i.e. negative LeftEdge is that distance from screen's right edge
  823. */
  824. AdjustNewWindow( struct NewWindow * NewW){
  825.     int screenwidth = 320;
  826.     int screenheight = 200;
  827.     struct Screen *ScreenInfo;
  828.  
  829.     /* grab the default screen and hold it until we get info on it... */
  830.     if((ScreenInfo =LockPubScreen( NULL )) != NULL){
  831.     screenwidth = ScreenInfo->Width;
  832.     screenheight = ScreenInfo->Height;
  833.         UnlockPubScreen(NULL,ScreenInfo);
  834.     } else {
  835.         printf("Hrm, can\'t get information on default screen!\n");
  836.     }
  837.  
  838.     if(NewW->Height < 0){
  839.         NewW->Height = screenheight + NewW->Height;
  840.     if(NewW->Height < 0)  /* someone specified a way negative size? */
  841.         NewW->Height = screenheight;
  842.     } else if(NewW->Height == 0){
  843.         NewW->Height = screenheight / 5;   /* a sane default size? */
  844.     } else { /* newW->Height > 0 */
  845.         if(NewW->Height > screenheight ){  /* you really want a big window?? */
  846.         NewW->Height = screenheight;
  847.     }
  848.     }
  849.     if(NewW->Width < 0){
  850.         NewW->Width = screenwidth + NewW->Width;
  851.     if(NewW->Width < 0)  /* someone specified a way negative size? */
  852.         NewW->Width = screenwidth;
  853.     } else if(NewW->Width == 0){
  854.         NewW->Width = screenwidth / 5;   /* a sane default size? */
  855.     } else { /* newW->Width > 0 */
  856.         if(NewW->Width > screenwidth ){  /* you really want a big window?? */
  857.         NewW->Width = screenwidth;
  858.     }
  859.     }
  860.  
  861.     /* handle negative offsets for window positions */
  862.     if(NewW->LeftEdge < 0){
  863.         NewW->LeftEdge = screenwidth + NewW->LeftEdge;
  864.     } 
  865.     if(NewW->TopEdge < 0){
  866.         NewW->TopEdge = screenheight + NewW->TopEdge;
  867.     } 
  868.  
  869.     if(NewW->LeftEdge + NewW->Width > screenwidth){
  870.         NewW->LeftEdge = screenwidth - NewW->Width;
  871.     }
  872.     if(NewW->TopEdge + NewW->Height > screenheight){
  873.         NewW->TopEdge = screenheight - NewW->Height;
  874.     }
  875.  
  876. }
  877.  
  878. #ifdef TEST
  879.  
  880. #include <time.h>
  881.  
  882. char * NowClock(){
  883.   static char timebuf[10];
  884.   long curtime;
  885.   struct tm *tm;
  886.  
  887.   time(&curtime);
  888.   tm = (struct tm *)localtime(&curtime);
  889.   sprintf(timebuf, "%02d:%02d", tm->tm_hour, tm->tm_min);
  890.  
  891.   return timebuf;
  892. }
  893.  
  894. /* generate a random load -- fake a report from the other end */
  895. #define LOADSIZ 10
  896. #define LOADRANGE 3
  897. RandomLoadUpdate(){
  898.     static long FooLoad = -1;
  899.     static int LoadGens[LOADSIZ];
  900.     int numusers = 0;
  901.     int rnum;
  902.     int i;
  903.     int load;
  904.  
  905.  
  906.     if(FooLoad == -1) srandom(FindTask(NULL));
  907.  
  908.     FooLoad = random() % (100 * LOADRANGE) ;
  909.  
  910.     rnum = random() % LOADSIZ;
  911.  
  912.     LoadGens[rnum] = FooLoad;
  913.  
  914.     load= 0;
  915.     for(i=0;i<LOADSIZ;i++) {
  916.         load += LoadGens[i];
  917.     if( LoadGens[i] > LOADRANGE * 50) 
  918.         numusers++;
  919.     }
  920.  
  921.     load = load / LOADSIZ;
  922.  
  923.     sprintf( Uptime, 
  924.     " %s up 2 minutes, 0:23, %d users, load average: %2.2f %2.2f %2.2f", 
  925.     NowClock(), numusers, (double) load / 100, (double) load/100, 
  926.     (double) load/100);
  927.     IFDEBUG(printf("Faked uptime: %s\n", Uptime);)
  928. }
  929.  
  930. #endif /* TEST */
  931.