/*
 *                  LFGrabPath v1.0
 *
 *                      © LFSoft 1994
 *
 *  Purpose:
 *  ~~~~~~~~
 *       Grab global shell path. For use w/ shell that doesn't herite path,
 *      ( shells lauched by Workbench's process, as DiceConfig 2.x slave
 *      shell ).
 *
 *
 *  Legal stuffs:
 *  ~~~~~~~~~~~~~
 *       This usefull tools is a CARTE-WARE that meed you *must* send me a
 *      post carte to say that you like my work.
 *       On the other hand, I ( Laurent FAILLIE ) don't assume any warranty
 *      of any king. Use it at your only own risk.
 *
 *       Some parts of this code is based on my very own LFSystemBinder 1.0
 *      and CSH 5.31's sources code by Andreas M. Kirchwitz.
 *      CAUTION: CSH 5.xx have a bug that crach your Amiga if you do a
 *      "path -gr" because global path ( stored in "WorkBench" CLI-Structure )
 *      isn't allocated by DOS by AllocVec() but by a simple AllocMem(). This
 *      was fixed for LFSystemBinder ...
 *
 *  Others:
 *  ~~~~~~~
 *       LFGrabPath was developped and tested on my Amiga 4000, 68040, 6Mb RAMs,
 *      KS 39.106,WB 39.29, and on my old ( but lovely !! ) Amiga 1000, 68010,
 *      6 Mb RAMs, KS 37.210, WB 38.35.
 *
 *       It was compiled using REGISTERED version of Dice ( © Matt. DILLON ),
 *      v 2.07.54R, and this is a PURE commands.
 *
 *  Notes:
 *  ~~~~~~
 *      - This sources code is for information only as some aspect are Dice
 *     dependant and some functions call my very own LF.lib.
 *
 *      - Currently, Workbench must running as global path is taken from
 *     Workbench's CLI struture...
 *
 *  Thanks to:
 *  ~~~~~~~~~~
 *      - M.Dillon for Dice,
 *      - SomeWare for distribution of Dice in FRANCE,
 *      - My betha-testers: Frank Geider, Bruno Antoine, Animage production,
 *          and Sebastien Bouchex.
 *      - Andreas M. Kirchwitz for CSH 5.20+
 *      - AmigaNews,
 *      - and alls who registers my tools,
 *      - Fred Fish & CAM for DPs libraries,
 *      - Couleur3 for music
 *
 *      A very BIG TANKS to BABETH...
 *
 *  DEBUG:
 *  ~~~~~~
 *      9 Doesn't touch our path
 *      8 Display global path
 *
 *      Warning : If DEBUG > 7, multitaching is enabled when we are looking for
 *          the workbench's path. The system may crach if another process modify
 *          path list (ether our path or workbench's path) at the same time.
 *
 *  History:
 *  ~~~~~~~~
 *      22/07/1994: First Version
 *
 *  Write to:
 *  ~~~~~~~~~
 *           Laurent FAILLIE
 *            "Les Vuardes"
 *          74930 Pers-Jussy
 *              FRANCE
 *
 *          ------< Sorry for my (very ?) bad english >-----
 */

#include <LF.h>     // For my very own LF.lib
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <exec/memory.h>
#include <dos/dosextens.h>
#include <proto/dos.h>
#include <dos/dostags.h>
#include <clib/alib_protos.h>
#include <proto/exec.h>

void OS2_0( void ); // Because this function isn't prototyped anywhere !!

struct PathList {           // From CSH 5.31 source's code
        BPTR pl_NextPath;
        BPTR pl_PathLock;
};
#define BPTR_TO_C(strtag, var)  ((struct strtag *)(BADDR( (ULONG) var)))
#define CLI(proc)               (BPTR_TO_C(CommandLineInterface, proc->pr_CLI))


struct CommandLineInterface *ourcli;

BOOL adddir(BPTR np){
    /* Add given dir to our path
     * Fail if this dir is already in the path ...
     */

    struct PathList *pl,*last,*new_pl;
    BPTR dup_lock;

    if(!(dup_lock = DupLock(np))){
        puts(" Error: Can't duplicate a Lock ( no mémories ? )");
        exit(10);
    }


            /*  Look for the end of our PathList and test if this entry
             * isn't already included.
             */

    last = pl = BPTR_TO_C(PathList,ourcli->cli_CommandDir);
    while(pl){
        last = pl;
        if (pl->pl_PathLock) {
            if (SameLock(pl->pl_PathLock,dup_lock)==LOCK_SAME) {
                UnLock(dup_lock);
                #if DEBUG > 7
                    puts(" already in path list !!");
                #endif
                return FALSE;
            }
        }
        pl = (struct PathList *)BADDR(pl->pl_NextPath);
    }

    #if DEBUG > 7
        puts(" added .");
    #endif

    #if DEBUG < 9   // Don't touch our path if DEBUG == 9


            /* Allocate and add this new entry */

    if (new_pl=AllocVec(sizeof(struct PathList),MEMF_CLEAR|MEMF_PUBLIC)) {
        new_pl->pl_NextPath = NULL;
        new_pl->pl_PathLock = dup_lock;
        if (last)
            last->pl_NextPath = MKBADDR(new_pl);
        else
            ourcli->cli_CommandDir = MKBADDR(new_pl);
        return TRUE;
    } else  // Can't allocate a new entry
        UnLock(dup_lock);
    #endif

    return FALSE;
}

void main( void ){
    struct PathList *pl;
    struct Process *wbench;

    puts("\tLFGrabPath 1.0 © LFSoft 1994\n Grab the system's global path stored in the WorkBench Structure...");
    OS2_0();    // Exit if not runing on 2.0+

        /* Get our CLI */
    if(!(ourcli = Cli())){
        puts("Error : Can't take our CLI structure");
        exit(10);
    }

        /* Find Workbench, where global path is stored */
    Forbid();

    if(!(wbench=(struct Process *)FindTask("Workbench"))){
        Permit();
        fputs("Can't find WorkBench",stderr);
        exit(10);
    }

    if(!wbench->pr_CLI){
        Permit();
        fputs("WorkBench doesn't have a CLI struture !!",stderr);
        exit(10);
    }

    pl=(struct PathList *)BADDR(CLI(wbench)->cli_CommandDir);

    #if DEBUG > 7
        Permit();
    #endif

    while (pl) {
            if (pl->pl_PathLock) {
                    #if DEBUG > 7
                        char buf[256];

                        NameFromLock(pl->pl_PathLock,buf,255L);
                        printf("%s ",buf);
                    #endif

                    adddir(pl->pl_PathLock);
            }
            pl = (struct PathList *)BADDR(pl->pl_NextPath);
    }

    #if DEBUG < 8
        Permit();
    #else
        putchar('\n');
    #endif
}
