Table of Contents

About

This is a small program that will print out any files or directories starting with a path supplied by the command-line arguments. The program makes partial use of a Wizardry and Steamworks string-stack implementation for AmigaOS.

In order to compile using SAS/C, issue:

sc link depthTraversal.c

After that, you can issue for example:

depthTraversal RAM:

which will result in output similar to:

Specified path: RAM:
Dirs: RAM:T
Dirs: RAM:Clipboards
File: RAM:Disk.info
Dirs: RAM:T/UCC
Dirs: RAM:T/FMS
File: RAM:T/AmiTCP.log
File: RAM:T/FMS/Unit4
File: RAM:T/FMS/Unit3
File: RAM:T/FMS/Unit2
File: RAM:T/FMS/Unit1
File: RAM:T/FMS/Unit0

Related

Code

depthTraversal.c
/*************************************************************************/
/*    Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3    */
/*************************************************************************/
/*                                                                       */
/*  depthTraversal                                                       */
/*                                                                       */
/*  Traverses a directory path starting from the current directory.      */
/*                                                                       */
/*  This program uses a stack implementation for Amiga OS found at:      */
/*  http://grimore.org/amiga/development/data_structures/stacks/strings  */
/*                                                                       */
/*  Amiga OS using SAS/C and issuing: sc link depthTraversal.c           */
/*                                                                       */
/*************************************************************************/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
 
#include <proto/exec.h>
#include <proto/dos.h>
 
/*************************************************************************/
/*          Wizardry and Steamworks' string stack implementation.        */
/*************************************************************************/
 
/* The stringStack structure with top being the index of the next element 
 * to be inserted in stack (the top-most element to be found at top - 1).
 */
typedef struct {
   ULONG size;
   UBYTE **store;
   ULONG top;
} stringStack;
 
/*
 * Creates a new stringStack with a given size.
 */
stringStack* stringStackCreate(ULONG size) {
   stringStack *s = (stringStack*)AllocMem(
       sizeof(stringStack), 
       MEMF_ANY|MEMF_CLEAR
   );
   if ((s->store = (UBYTE**)AllocMem(
       size * sizeof(UBYTE **), 
       MEMF_ANY|MEMF_CLEAR
       )) == NULL) return NULL;
   s->size = size;
   s->top = 0;
   return s;
}
 
/*
 * Takes as parameter a stringStack and returns 1 if the stack is empty
 * or 0 if the stack is not empty.
 */
BOOL stringStackIsEmpty(stringStack *s) {
    return (BOOL)(s->top == 0);
}
 
/*
 * Pushes an element onto the stringStack.
 */
void stringStackPush(stringStack *s, UBYTE *e) {
    UBYTE **sStore;
    if (s->top > s->size - 1) { // realloc for AmigaOS
        sStore = (UBYTE **)AllocMem(
            (s->size + 1) * sizeof(UBYTE **), 
            MEMF_ANY|MEMF_CLEAR
        );
        CopyMem(s->store, sStore, s->size * sizeof(UBYTE **));
        FreeMem(s->store, sizeof(s->store));
        s->store = sStore;
        ++s->size;
    }
    s->store[s->top] = (UBYTE *)AllocMem(
            strlen(e) * sizeof(UBYTE *) + 1, 
            MEMF_ANY|MEMF_CLEAR
    );
    CopyMem(e, s->store[s->top], strlen(e) * sizeof(UBYTE *) + 1);
    ++s->top;
}
 
/*
 * Pops an element off the stringStack or returns NULL in case the
 * stack is empty.
 */
UBYTE *stringStackPop(stringStack *s) {
   UBYTE *e;
   if (stringStackIsEmpty(s))
       return NULL;
   --s->top;
   e = (UBYTE *)AllocMem(
       strlen(s->store[s->top]) * sizeof(UBYTE *) + 1, 
       MEMF_ANY|MEMF_CLEAR
   );
   CopyMem(
       s->store[s->top], 
       e, 
       strlen(s->store[s->top]) * sizeof(UBYTE *) + 1
   );
   return e;
}
 
/*
 * Prints out the elements of the stringStack.
 */
void stringStackPrint(stringStack *s) {
    LONG i;
    if (stringStackIsEmpty(s)) {
        Printf("Stack is empty.\n");
        return;
    }
    Printf("Elements in the stack: ");
    i = s->top - 1;
    do {
        Printf("%s ", s->store[i]);
    } while (--i > -1);
    Printf("\n");
}
 
/*************************************************************************/
/*        Version string used for querrying the program version.         */
/*************************************************************************/
GLOBAL TEXT version_string[] = 
    "\0$VER: depthTraversal 1.0 (29 Jul 2015) by Wizardry and Steamworks";
 
/*************************************************************************/
/*              Amiga OS command-line arguments parameters.              */
/*************************************************************************/
STATIC CONST TEXT template[] = "PATH/A";
enum {
    PATH,
    NUM_ARGS
};
 
/*************************************************************************/
/*    Traverses a stack of paths and prints out files and directories.   */
/*************************************************************************/
LONG TraversePath(stringStack *dirStack) {
    struct FileInfoBlock *FIB = NULL;
    UBYTE *path;
    BPTR lock = NULL;
    UBYTE *nextPath;
    ULONG nextSize;
    jmp_buf env;
    LONG error;
 
    /* jump: Free any resources before returning an error. */
    error = setjmp(env);
    if(error != 0) {
        /* Free the file information block. */
        if(FIB != NULL) FreeDosObject(DOS_FIB, FIB);
        /* Release the lock. */
        if(lock != NULL) UnLock(lock);
        /* And return the error. */
        return error;
    }
 
    /* The directory stack is empty so return. */
    if(stringStackIsEmpty(dirStack))
        return 0;
 
    /* Pop the top element in the stack. */
    path = stringStackPop(dirStack);
 
    /* Lock the path. */
    if((lock = Lock(path, ACCESS_READ)) == NULL) {
        Printf("Unable to acquire a read lock to the specified path.\n");
        longjmp(env, RETURN_ERROR);
    }
 
    /* Create a new file information block to scan the path. */
    if((FIB = (struct FileInfoBlock *)
        AllocDosObject(DOS_FIB, NULL)) == NULL) {
        Printf("Unable to allocate file information block.\n");
        longjmp(env, RETURN_ERROR);
    }
 
    if(Examine(lock, FIB)) {
        /* Examine the rest of the entries in the directory. */
        while(ExNext(lock, FIB)) {
            /* check for Ctrl-C */
            if(CheckSignal(SIGBREAKF_CTRL_C) != FALSE)
                longjmp(env, RETURN_WARN);
            nextSize = strlen(path) + 
                strlen(FIB->fib_FileName) * 
                sizeof(UBYTE *) + 1;
            if((nextPath = (UBYTE*)
                AllocMem(nextSize, MEMF_ANY|MEMF_CLEAR)) == NULL) {
                Printf("Unable to allocate memory for path.\n");
                longjmp(env, RETURN_ERROR);
            }
            CopyMem(path, nextPath, nextSize);
            if(AddPart(nextPath, FIB->fib_FileName, nextSize) == FALSE) {
                Printf("Unable to add the file to the path.\n");
                longjmp(env, RETURN_ERROR);
            }
            /* Check whether the path is a file or a directory. */
            switch(FIB->fib_DirEntryType > 0) {
                case TRUE: // We have a directory.
                    Printf("Dirs: %s\n", nextPath);
 
                    // So we push it onto the stack.
                    stringStackPush(dirStack, nextPath);
 
                    break;
                default: // We have a file.
                    Printf("File: %s\n", nextPath);
                    break;
            }
        }
    }
 
    /* Free the file information block. */
    if(FIB != NULL) FreeDosObject(DOS_FIB, FIB);
 
    /* Release the lock. */
    if(lock != NULL) UnLock(lock);
 
    /* DEBUG: print the stack. */
    /* stringStackPrint(dirStack); */
 
    /* Recurse over the stack till it is empty. */
    return TraversePath(dirStack);
}
 
/*************************************************************************/
/*                          Program entry.                               */
/*************************************************************************/
int main(int argc, char **argv) {
    stringStack *dirStack = NULL;
    struct FileInfoBlock *FIB = NULL;
    BPTR lock = NULL;
    LONG size;
    jmp_buf env;
    LONG error;
 
    /* Setup command-line arguments to retrieve path.*/
    LONG *arg_array;
    struct RDArgs *rdargs;
    UBYTE *path;
 
    /* jump: Free any resources before returning an error. */
    error = setjmp(env);
    if(error != 0) {
        /* Free the file information block. */
        if(FIB != NULL) FreeDosObject(DOS_FIB, FIB);
        /* Release the lock. */
        if(lock != NULL) UnLock(lock);
        /* And return the error. */
        return error;
    }
 
    /* Allocate memory for arg array. */
    if((arg_array = AllocMem(NUM_ARGS, MEMF_ANY|MEMF_CLEAR)) == NULL) {
        Printf("Unable to allocate memory for command-line arguments.\n");
        longjmp(env, RETURN_ERROR);
    }
 
    /* Read command-line arguments */
    if((rdargs = ReadArgs(template, arg_array, NULL)) == NULL) {
        FreeArgs(rdargs);
        longjmp(env, RETURN_ERROR);
    }
    /* Allocate memory for the path name as the product between the lengh 
     * of the path name and the size of UBYTE plus a termination character. 
     */
    size = strlen((STRPTR)arg_array[PATH]) * sizeof(UBYTE) + 1;
    /* Allocate memory for path name. */
    if((path = AllocMem(size, MEMF_ANY|MEMF_CLEAR)) == NULL) {
        Printf("Unable to allocate memory for path name.\n");
        longjmp(env, RETURN_ERROR);
    }
    /* Copy path name to be able to free the command-line arguments. */
    CopyMem((STRPTR)arg_array[PATH], path, size);
    FreeArgs(rdargs);
 
    Printf("Specified path: %s\n", path);
 
    /* Lock the path. */
    if((lock = Lock(path, ACCESS_READ)) == NULL) {
        Printf("Unable to acquire a read lock to the specified path.\n");
        longjmp(env, RETURN_ERROR);
    }
 
    /* Create a new file information block to scan the path. */
    if((FIB = (struct FileInfoBlock *)
        AllocDosObject(DOS_FIB, NULL)) == NULL) {
        Printf("Unable to allocate file information block.\n");
        longjmp(env, RETURN_ERROR);
    }
 
    /* Attempt to examine the path. */
    if(!Examine(lock, FIB)) {
        Printf("Unable to examine %s\n", path);
        longjmp(env, RETURN_ERROR);
    }
 
    /* If the specified path is a file bail out. */
    if(FIB->fib_DirEntryType < 0) {
        Printf("Specified path is a file.\n");
        longjmp(env, RETURN_ERROR);
    }
 
    /* Free the file information block. */
    if(FIB != NULL) FreeDosObject(DOS_FIB, FIB);
 
    /* Release the lock. */
    if(lock != NULL) UnLock(lock);
 
    /* Allocate a new stack. */
    dirStack = stringStackCreate(1);
    /* Push the specified path onto the stack. */
    stringStackPush(dirStack, path);
 
    /* Now traverse the path and return any errors. */
    return TraversePath(dirStack);
}

amiga/development/algorithms/path_traversal/depth-first.txt ยท Last modified: 2022/04/19 08:28 by 127.0.0.1

Access website using Tor Access website using i2p Wizardry and Steamworks PGP Key


For the contact, copyright, license, warranty and privacy terms for the usage of this website please see the contact, license, privacy, copyright.