/*
 * Lower - run a command at a nice, possibly lower, priority.
 *         AmigaDOS equivalent of UNIX nice.
 *
 * Version 37.1 =TP= 16-Jan-92
 * Compile with SAS/C 5.10 and link without startup code:
 *      lc -cqfist -v -b0 -rr -O -ms Lower
 *      blink Lower.o to Lower sd sc
 *      protect Lower +p
 *
 * Copyright (c) 1992 Torsten Poulin
 *
 * Torsten Poulin
 * Banebrinken 99, 2, lejlighed 77
 * DK 2400  København NV
 * DENMARK
 */

/****** English:LOWER *****************************************************
*
*   FORMAT
*       LOWER [BY <value>] [STACK <size>] [COMMAND] <command line>
*
*   TEMPLATE
*       BY/K/N,STACK/K/N,COMMAND/F/A
*
*   PURPOSE
*       To run a command at a nice, possibly lower, priority.
*
*   SPECIFICATION
*       Since the Amiga is multitasking, it uses priority numbers to
*       determine the order in which current tasks should be serviced.
*       Normally, most tasks have a priority of 0, and the time and
*       instruction cycles of the CPU are divided equally among them.
*
*       LOWER executes the specified command line with the priority
*       lowered by <value>.  If no BY option is specified a default
*       value of 1 is used.  If a negative value is specified the
*       priority will be raised instead.  The resulting priority will
*       be between -128 and +10.  This is enforced silently.
*
*       The STACK option sets the stack size of the command to be
*       executed.  Default is to use the current stack size.
*
*       The <command line> is any valid shell command line; i.e. it
*       is possible to use redirection, aliases, resident commands
*       etc.
*
*       LOWER leaves the value of the executed command in the
*       condition flags RC and Result2.  Ctrl-C, D, E, and F are
*       sent to the executed command.
*
*       In short, the use of LOWER is tranparent.
*
*   EXAMPLES
*       To print the file Text at lower priority, type:
*
*           1> LOWER COPY Text TO PRT:
*
*       And to search, in the background, for occurences of the
*       string "foo", in the S: directory, you might issue
*       the following:
*
*           1> RUN LOWER BY 2 SEARCH S: "foo" TO MyOutputFile
*
*   SEE ALSO
*       CHANGETASKPRI, STACK, STATUS
*
***************************************************************************
*
*/
/****** dansk:LOWER *******************************************************
*
*   FORMAT
*       LOWER [BY <værdi>] [STACK <størrelse>]
*             [COMMAND] <kommandlinje>
*
*   SKABELON
*       BY/K/N,STACK/K/N,COMMAND/F/A
*
*   FORMÅL
*       At udføre en kommando med en rar, muligvis lavere, prioritet.
*
*   SPECIFIKATION
*       Da Amigaen er et samkørselssystem bruger den prioritetstal
*       til at afgøre i hvilken orden de nuværende opgaver skal
*       betjenes.  Normalt har de fleste opgaver prioriteten 0, og
*       centralenhedens tid deles lige mellem dem.
*
*       LOWER udfører den angivne kommandolinje med prioriteten
*       sænket med <værdi>.  Hvis der ikke er angivet nogen værdi
*       med BY, bruges 1 som standardværdi.  Hvis en negativ værdi
*       angives vil prioriteten blive hævet istedet.  Den
*       resulterende prioritet skal være mellem -128 og +10.  Dette
*       bliver håndhævet tavst.
*
*       Argumentet STACK sætter stakstørrelsen for den kommando der
*       skal udføres.  Standard er at beholde den nuværende
*       størrelse.
*
*       Argumentet <kommandolinje> kan være enhver tilladt shell-
*       kommandolinje.  Dvs. at det er muligt at benytte omdiri-
*       gering, aliaser, residente kommandoer osv.
*
*       LOWER efterlader resultaterne af den udførte kommando
*       i tilstandsflagene RC og Result2.  Ctrl-C, D, E og F
*       sendes til kommandoen der er ved at blive udført.
*
*       Kort sagt, brugen af LOWER er transparent.
*
*   EKSEMPLER
*       Skriv
*
*          1> LOWER COPY Tekst TO PRT:
*
*       for at udskrive filen Tekst på skriveren.
*       Og for at søge, i baggrunden, efter forekomster af tegn-
*       følgen "foo", i kataloget S:, kan man gøre følgende:
*
*           1> RUN LOWER BY 2 SEARCH S: "foo" TO MinUddatafil
*
*   SE OGSÅ
*       CHANGETASKPRI, STACK, STATUS
*
***************************************************************************
*
*/


#include <exec/types.h>
#include <exec/tasks.h>
#include <exec/libraries.h>
#include <libraries/dos.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <proto/exec.h>
#include <proto/dos.h>

static LONG MySystemTags(struct DosLibrary *DOSBase,
                         UBYTE *command, ULONG firsttag, ...);

char const *version = "\0$VER: Lower 37.1 (16.1.92) ©1992 Torsten Poulin";

int entrypoint(void)
{
    struct RDArgs     *args;
    struct DosLibrary *DOSBase;
    struct Library    *SysBase;
    LONG niceval, stack;
    LONG arg[3];
    LONG rc = RETURN_OK;

    SysBase = *(struct Library **) 4L;
    if(!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
        return RETURN_FAIL;

    arg[0] = arg[1] = arg[2] = 0L;
    
    if(args = ReadArgs("BY/K/N,STACK/K/N,COMMAND/F/A", arg, NULL))
    {
        niceval = (FindTask(NULL))->tc_Node.ln_Pri;
        if(arg[0])
            niceval -= *(LONG *) arg[0];
        else
            niceval--;
        if(niceval < -128L) niceval = -128L;
        else if(niceval > 10L) niceval = 10L;

        if(arg[1])
            stack = (*(LONG *) arg[1]) < 1600L ? 1600L : *(LONG *) arg[1];
        else
            stack = (Cli())->cli_DefaultStack << 2;
               
        rc = MySystemTags(DOSBase, (UBYTE *) arg[2],
                          SYS_UserShell, TRUE,
                          NP_Priority,   niceval,
                          NP_StackSize,  stack,
                          TAG_DONE);
        if(rc == -1)
            rc = RETURN_ERROR;

        FreeArgs(args);
    }
    else
    {
        LONG err = IoErr();
        PrintFault(err, "Lower");
        rc = RETURN_ERROR;
    }
    CloseLibrary((struct Library *) DOSBase);
    return rc;
}


static LONG MySystemTags(struct DosLibrary *DOSBase,
                         UBYTE *command, ULONG firsttag, ...)
{
    return SystemTagList(command, (struct TagItem *) &firsttag);
}
