/* stat.c An enhanced version of the AmigaDOS command STATUS.
 *
 * Copyright 1986 by James M Synge. Sept. 2, 1986.
 * Permission is granted for unlimited non-commercial use.
 *
 * Compiled using Aztec C, but it shouldn't be that hard to change
 * for Lattice C
 *
 * The makefile file is very short:
 *------------------------------
 *  stat: stat.o
 *     ln -v stat.o -lc
 *------------------------------
 * UUCP: uw-beaver!geops!uw-atm!james
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/tasks.h>

#include <libraries/dosextens.h>

char buf1[32], buf2[32];

/* DOSBase is already set up (by _main?) */
extern struct DosLibrary *DOSBase;

/* Need a macro to translate a BPTR to an APTR */
#ifdef BADDR
#undef BADDR
#endif
#define BADDR(bptr) (((long)bptr) << 2)

/* By experimentation I determined that the command line arguments are */
/* located at (tc_SPLower + 0x280).  This may change in the future. */
/* If STAT starts printing garbage for the args, just comment out this: */
#define ARGS_OFFSET 0x280

main(argc, argv)
int argc;
char *argv[];
{
       int i, tasknum, pri, strncmp(); char *msg, *index();
       long process, processes, *ta;
       struct Process *pr;
       struct RootNode *rn;
       struct CommandLineInterface *cli;

       /* Find the RootNode */
       rn = (struct RootNode *)(DOSBase->dl_Root);

       /* ta points to the array of tasks. The first location is the */
       /* maximum number of processes, followed by that many pointers. */
       /* Each pointer points to the MsgPort within the Process data */
       /* structure of each AmigaDos process, otherwise its value is 0L. */
       /* The AmigaDOS Technical Reference Manual calls these pointers */
       /* process ids. */

       ta = (long *) BADDR(rn->rn_TaskArray);

       /* How many AmigaDOS processes are there? */

       processes = *ta++;

       /* Print the title line. */
       printf("Task Pri  Address Command\t\t\t   Directory\n");

       /* Loop through each live process, printing info. */

       for (process = 0; process < processes; process++ ) {

               /* Get the next process id (i.e. struct MsgPort *) */
               msg = (char *)(*ta++);
               if (!msg) continue; /* No associated Process? */

               /* Pointer to struct Process */
               pr = (struct Process *)(msg - sizeof(struct Task));

               /* CLIs have small positive task numbers */
               tasknum = (int)(pr->pr_TaskNum);

               /* The priority of the task is in the Node structure */
               pri = (int)(pr->pr_Task.tc_Node.ln_Pri);

               cli = (struct CommandLineInterface *) BADDR(pr->pr_CLI);

               if (cli) {
                   moveBSTR(cli->cli_CommandName, buf1, 32);
                   if (!buf1[0]) strcpy(buf1, "Waiting for a command");
#ifdef ARGS_OFFSET
                   else {
                       msg = (char *)(pr->pr_Task.tc_SPLower) + ARGS_OFFSET;
                       if (*msg && *msg != '\n') {
                           strncat(buf1, " ", 32);
                           strncat(buf1, msg, 32);
                           msg = index(buf1, '\n');  /* Look for a \n */
                           if (msg) *msg = '\0';
                       }
                   }
#endif
                   moveBSTR(cli->cli_SetName, buf2, 32);
               } else {
                       strcpy(buf1, "Not a CLI");
                       buf2[0] = 0;
               }

               printf("%3d %4d %8lx %-32s %s\n",
                       tasknum, pri, pr, buf1, buf2);
       }
       exit(0);
}

/* moveBSTR copies a BSTR to a C char string. */
moveBSTR(bptr, buffer, maxlen)
BSTR bptr;
char *buffer;
int maxlen; /* size of buffer[] */
{
       register char *ptr;
       register unsigned int len, i;
       unsigned char l;

       ptr = (char *) BADDR(bptr); /* Make a char* to the length */

       l = (unsigned int) (*ptr++); /* Get the length and increment ptr */

       if (!(len = l)) {
               *buffer = '\0'; /* Mark the end of the string. */
               return;
       }
       if (len > maxlen) len = maxlen;
       for(i = 0; i < len; i++) *buffer++ = *ptr++; /* Copy it. */

       if (i < maxlen) *buffer = '\0'; /* If there is room, mark the end */
       return;
}

