Logo Search packages:      
Sourcecode: hat version File versions  Download package

hat-anim.c

/* hat-anim: animates the progress of a haskell evaluation
* Thomas Davie, Student, University of York
* Original version November 2003
*/

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <curses.h>
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

#include "art.h"  
#include "animnode.h"
#include "list.h"
#include "nodelist.h"
#include "nodehash.h"
#include "stack.h"

#define ANYEXP    22
#define ANYATOM   23
#define HEADER    29
#define INVALID   30
#define BEYOND    31

#define NONZERO 0
#define MAYBEZERO 1
#define MAYBELAMBDA 4

#define OPEN_HASH_SIZE 211

#define MAX_U_LONG 2147483647

#define COMMAND_BUFFER_SIZE 256
#define MAX_REDUCTION_LENGTH 36636

#define MAX_BUF   1024

/* FUNCTION PROTOTYPES */
// The main recursion structure.
char getPrintedNode (nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes, char *reductionBuffer, char showWhenUnevaluated, char showResult, char trusted, char shouldBracket);
char tryGetPrintedNode (nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes, char *reductionBuffer, char showWhenUnevaluated, char showResult, char trusted, char shouldBracket);
unsigned long findNextDisplayingNode(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes);

// Specific sections of the file structure.
node *findAtomNode(nodehash *fileNodes, unsigned long offset, nodelist *visitedNodes);
char getExpValueApp(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes, char *reductionBuffer, char showWhenUnevaluated, char showResult, char trusted, char shouldBracket);
char getExpApp(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes, char *reductionBuffer, char showWhenUnevaluated, char showResult, char trusted, char shouldBracket);
char getListPrettyPrinted(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes, char *reductionBuffer, char showWhenUnevaluated, char showResult, char trusted);
char isMoreList(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset);
char isString(nodehash *fileNodes, unsigned long offset);
char canBePrettyPrinted(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset);

char* tag2str(int k);

int strends(char *e, char *s);
void badUsage(void);

void repaint(stack *redexTrail, char *command, char *debugStr);
void printReduction(int lineNo, char *reduction);
void doCommand(char *command);
unsigned long reloadCache(nodehash *fileHash, unsigned long maxOffset);

void displayHelp(void);

unsigned long startOffset,
              currentOffset,
              lastMaxOffset,
              scrollPos;
bool exiting = false;
char stringMode = false;

list *trustees;
stack *redexTrail = NULL;

int main (int argc, char *argv[])
{
    char *filename;
    node *theNode;
    nodehash *fileHash;
    unsigned long nextOffset;
    char input;
    nodelist *visitedNodes;
    char commandBuffer[COMMAND_BUFFER_SIZE];
    int commandBufferPos;
    bool commandMode = false;
    char *reductionBuffer;
    char debugReductionBuffer[MAX_REDUCTION_LENGTH];
    char somewhere;
    char debugStr[128];
    
    initscr();
    raw();
    noecho();
    nodelay(stdscr, false);
    
    trustees = list_newEmptyList();
    
    /* File open and version check taken from hat-check */
    if (argc < 2)
    {
        badUsage();
    }

    if (strends(".hat", argv[1]))
    {
        filename = (char *)malloc(strlen(argv[1]) * sizeof(char));
    }
    else
    {
        filename = (char *)malloc((strlen(argv[1]) + 4) * sizeof(char));
    }
    strcpy(filename, argv[1]);
    if (!strends(".hat", filename))
    {
        strcat(filename, ".hat");
    }
    if (fileHash = nodehash_newByOpeningFile(filename))
    {
        if (argc >= 3)
        {
            sscanf(argv[2], "%d", &startOffset);
        }
        else
        {
            startOffset = 0;
            printf("hat-anim: no offset provided, assuming 0x0\n");
        }
        lastMaxOffset = currentOffset = startOffset;
        
        if (startOffset >= fileHash->filesize)
        {
            fprintf(stderr, "hat-anim (error: 0x%x is beyond end of trace file\n", startOffset);
            endwin();
            exit(1);
        }
        
        scrollPos = 0;
        nextOffset = reloadCache(fileHash, startOffset);
        while(!exiting)
        {
            repaint(redexTrail, (commandMode ? commandBuffer : ""), NULL);
            input = getch();
            if (!commandMode)
            {
                if (input == '\n' && nextOffset != MAX_U_LONG) // return advances the trail.
                {
                    nextOffset = reloadCache(fileHash, nextOffset);
                }
                else if (input == '\b')
                {
                    nextOffset = reloadCache(fileHash, lastMaxOffset);
                }
                else if (input == '.')
                {
                    scrollPos += (COLS - 10);
                }
                else if (input == ',')
                {
                    if (scrollPos > COLS - 10)
                    {
                        scrollPos -= (COLS - 10);
                    }
                    else
                    {
                        scrollPos = 0;
                    }
                }
                else if (input == ':') // Colon characters put us into command mode.
                {
                    commandMode = true;
                    strcpy(commandBuffer, ":");
                    commandBufferPos = 1;
                }
            }
            else
            {
                if (input == '\n') // When in command mode, return executes the command
                {
                    doCommand(commandBuffer);
                    commandMode = false;
                    nextOffset = reloadCache(fileHash, currentOffset);
                    repaint(redexTrail, (commandMode ? commandBuffer : ""), NULL);
                }
                else if (input == '\b') // backspace should delete.
                {
                    commandBufferPos--;
                    commandBuffer[commandBufferPos] = '\0';
                }
                else // Otherwise we add to the command buffer.
                {
                    if (commandBufferPos < COMMAND_BUFFER_SIZE - 1)
                    {
                        commandBuffer[commandBufferPos] = input;
                        commandBufferPos++;
                        commandBuffer[commandBufferPos] = '\0';
                    }
                    mvprintw(20, 0, commandBuffer);
                }
            }
        }
        
        stack_delete(redexTrail);
        nodehash_delete(fileHash);
    }
    
    list_delete(trustees);
    
    endwin();
    
    return 0;
}

char getPrintedNode (nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes, char *reductionBuffer, char showWhenUnevaluated, char showResult, char trusted, char shouldBracket)
{
    node *theNode = NULL;
    node *atomNode;
    int  argIndex;
    char showedSomething = false;
    char showedArg = false;
    char returnVal = false;
        
    theNode = nodehash_getNode (fileNodes, offset);
    
    nodelist_push(visitedNodes, theNode);
    
    /*char *temp;
    asprintf(&temp, "(0x%x, %s)", theNode->offset, tag2str(theNode->nodeType));
    strncat(reductionBuffer, temp, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
    free(temp);*/
    switch (theNode->nodeType)
    {
#pragma mark AtomAbstact
        case AtomAbstract:
            strncat(reductionBuffer, theNode->params.atomAbstract.value, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            returnVal = true;
            break;
#pragma mark AtomConstructor
        case AtomConstructor:
            strncat(reductionBuffer, theNode->params.atomConstructor.name, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            returnVal = true;
            break;
#pragma mark AtomVariable
        case AtomVariable:
            strncat(reductionBuffer, theNode->params.atomVariable.name, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            returnVal = true;
            break;
#pragma mark ExpApp
        case ExpApp:
        {
            returnVal = getExpApp(fileNodes, offset, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
            break;
        }
#pragma mark ExpCase
        case ExpCase:
            if (findNextDisplayingNode(fileNodes, theNode->params.expCase.condition, lastMaxOffset, visitedNodes) != MAX_U_LONG)
            {
                if (shouldBracket)
                {
                    strncat(reductionBuffer, "(", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
                strncat(reductionBuffer, "case ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expCase.condition, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
                if (findNextDisplayingNode(fileNodes, theNode->params.expCase.condition, maxOffset, visitedNodes) != MAX_U_LONG)
                {
                    strncat(reductionBuffer, " then _", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
                else
                {
                    strncat(reductionBuffer, " then ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                    showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expCase.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
                    showedSomething = true;
                }
                if (shouldBracket)
                {
                    strncat(reductionBuffer, ")", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
            }
            else
            {
                showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expCase.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
                showedSomething = true;
            }

            returnVal = showedSomething;
            break;
#pragma mark ExpChar
        case ExpChar:
        {
            char temp[2];
            sprintf(temp, "%c", theNode->params.expChar.value);
            if (!stringMode)
            {
                strncat(reductionBuffer, "\'", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            }
            strncat(reductionBuffer, temp, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            if (!stringMode)
            {
                strncat(reductionBuffer, "\'", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            }
            returnVal = true;
            break;
        }
#pragma mark ExpConstDef
        case ExpConstDef:
            returnVal = tryGetPrintedNode (fileNodes, theNode->params.expConstDef.result, maxOffset, visitedNodes, reductionBuffer, false, showResult, trusted, shouldBracket);
            if (!returnVal)
            {
                returnVal = tryGetPrintedNode (fileNodes, theNode->params.expConstDef.var, maxOffset, visitedNodes, reductionBuffer, false, showResult, trusted, shouldBracket);
            }
            break;
#pragma mark ExpConstUse
        case ExpConstUse:
            returnVal = tryGetPrintedNode(fileNodes, theNode->params.expConstUse.value, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
            break;
#pragma mark ExpDouble
        case ExpDouble:
        {
            char *temp=(char*)malloc(MAX_BUF*sizeof(char)); /*asprintf*/
            sprintf(temp, "%f", theNode->params.expDouble.value);
            strncat(reductionBuffer, temp, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            free(temp);
            returnVal = true;
            break;
        }
#pragma mark ExpFieldUpdate
        case ExpFieldUpdate:
            showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expFieldUpdate.result, maxOffset, visitedNodes, reductionBuffer, false, showResult, trusted, shouldBracket);
            
            if (!showedSomething)
            {
                showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expFieldUpdate.arg, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
                strncat(reductionBuffer, "{", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                if (showedSomething)
                {
                    for (argIndex = 0; argIndex < theNode->params.expFieldUpdate.arity - 1; argIndex++)
                    {
                        showedArg = tryGetPrintedNode(fileNodes, theNode->params.expFieldUpdate.binders[argIndex], maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
                        strncat(reductionBuffer, "=", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                        showedArg = tryGetPrintedNode(fileNodes, theNode->params.expFieldUpdate.bindees[argIndex], maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
                        strncat(reductionBuffer, ", ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                    }
                    showedArg = tryGetPrintedNode(fileNodes, theNode->params.expFieldUpdate.binders[theNode->params.expFieldUpdate.arity], maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
                    strncat(reductionBuffer, "=", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                    showedArg = tryGetPrintedNode(fileNodes, theNode->params.expFieldUpdate.bindees[theNode->params.expFieldUpdate.arity], maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
                    strncat(reductionBuffer, "}", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
            }
            returnVal = showedSomething;
            break;
#pragma mark ExpFloat
        case ExpFloat:
        {
            char *temp=(char*)malloc(MAX_BUF*sizeof(char)); /*asprintf*/
            sprintf(temp, "%f", theNode->params.expFloat.value);
            strncat(reductionBuffer, temp, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            free(temp);
            returnVal = true;
            break;
        }
#pragma mark ExpForward
        case ExpForward:
            returnVal = tryGetPrintedNode(fileNodes, theNode->params.expForward.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
            break;
#pragma mark ExpGuard
        case ExpGuard:
            if (findNextDisplayingNode(fileNodes, theNode->params.expGuard.condition, lastMaxOffset, visitedNodes) != MAX_U_LONG)
            {
                if (shouldBracket)
                {
                    strncat(reductionBuffer, "(", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
                strncat(reductionBuffer, " guard ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expGuard.condition, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
                if (findNextDisplayingNode(fileNodes, theNode->params.expGuard.condition, maxOffset, visitedNodes) != MAX_U_LONG)
                {
                    strncat(reductionBuffer, " then _ otherwise _", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
                else
                {
                    if (!strncmp(reductionBuffer + strlen(reductionBuffer) - 5, "False", 5))
                    {
                        strncat(reductionBuffer, " then _ otherwise ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                        showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expGuard.result, maxOffset, visitedNodes, reductionBuffer, true, showResult, trusted, true);
                        showedSomething = true;
                    }
                    else
                    {
                        strncat(reductionBuffer, " then ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                        showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expGuard.result, maxOffset, visitedNodes, reductionBuffer, true, showResult, trusted, true);
                        showedSomething = true;
                        strncat(reductionBuffer, " otherwise _", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                    }
                }
                if (shouldBracket)
                {
                    strncat(reductionBuffer, ")", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
            }
            else
            {
                showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expGuard.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
                showedSomething = true;
            }

            returnVal = showedSomething;
            break;
#pragma mark ExpHidden
        case ExpHidden:
            returnVal = tryGetPrintedNode (fileNodes, theNode->params.expHidden.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
            break;
#pragma mark ExpIf
        case ExpIf:
            if (findNextDisplayingNode(fileNodes, theNode->params.expIf.condition, lastMaxOffset, visitedNodes) != MAX_U_LONG)
            {
                if (shouldBracket)
                {
                    strncat(reductionBuffer, "(", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
                strncat(reductionBuffer, "if ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expIf.condition, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
                if (findNextDisplayingNode(fileNodes, theNode->params.expIf.condition, maxOffset, visitedNodes) != MAX_U_LONG)
                {
                    strncat(reductionBuffer, " then _ else _", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
                else
                {
                    if (!strncmp(reductionBuffer + strlen(reductionBuffer) - 5, "False", 5))
                    {
                        strncat(reductionBuffer, " then _ else ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                        showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expIf.result, maxOffset, visitedNodes, reductionBuffer, true, showResult, trusted, true);
                        showedSomething = true;
                    }
                    else
                    {
                        strncat(reductionBuffer, " then ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                        showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expIf.result, maxOffset, visitedNodes, reductionBuffer, true, showResult, trusted, true);
                        showedSomething = true;
                        strncat(reductionBuffer, " else _", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                    }
                }
                if (shouldBracket)
                {
                    strncat(reductionBuffer, ")", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
            }
            else
            {
                showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expIf.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
                showedSomething = true;
            }
            
            returnVal = showedSomething;
            break;
#pragma mark ExpInt
        case ExpInt:
        {
            char *temp=(char*)malloc(MAX_BUF*sizeof(char)); /*asprintf*/
            sprintf(temp, "%ld", theNode->params.expInt.value);
            strncat(reductionBuffer, temp, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            free(temp);
            returnVal = true;
            break;
        }
#pragma mark ExpInteger
        case ExpInteger:
        {
            char *temp=(char*)malloc(MAX_BUF*sizeof(char)); /*asprintf*/
            sprintf(temp, "%s", theNode->params.expInteger.value);
            strncat(reductionBuffer, temp, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            free(temp);
            returnVal = true;
            break;
        }
#pragma mark ExpProjection
        case ExpProjection:
            returnVal = tryGetPrintedNode(fileNodes, theNode->params.expProjection.exp, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
            break;
#pragma mark ExpRat
        case ExpRat:
        {
            char *temp=(char*)malloc(MAX_BUF*sizeof(char)); /*asprintf*/
            sprintf(temp, "%d/%d", theNode->params.expRat.numerator, theNode->params.expRat.denominator);
            strncat(reductionBuffer, temp, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            free(temp);
            returnVal = true;
            break;
        }
#pragma mark ExpRational
        case ExpRational:
        {
            char *temp=(char*)malloc(MAX_BUF*sizeof(char)); /*asprintf*/
            sprintf(temp, "%d/%d", theNode->params.expRational.numerator, theNode->params.expRational.denominator);
            strncat(reductionBuffer, temp, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            free(temp);
            returnVal = true;
            break;
        }
#pragma mark ExpValueApp
        case ExpValueApp:
            returnVal = getExpValueApp(fileNodes, offset, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
            break;
#pragma mark ExpValueUse
        case ExpValueUse:
            if (!theNode->params.expValueUse.isLambda)
            {
                returnVal = tryGetPrintedNode(fileNodes, theNode->params.expValueUse.value, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
            }
            else 
            {
                strncat(reductionBuffer, "\\..", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            }
            break;
    }
    
    nodelist_pop(visitedNodes);
    
    shouldBracket = true;
    //fprintf(stderr, "Finished evaluating %s.\n", tag2str(theNode->nodeType));
    
    return returnVal;
}

char tryGetPrintedNode(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes, char *reductionBuffer, char showWhenUnevaluated, char showResult, char trusted, char shouldBracket)
{
    node *theNode;
    
    theNode = nodehash_getNode (fileNodes, offset);
    // Check that we're still ahead of the file limit - ExpHidden, ExpForward and ExpProjection don't count.
    if (offset <= maxOffset || theNode->nodeType == ExpForward || theNode->nodeType == ExpHidden || theNode->nodeType == ExpProjection || trusted)
    {
        //Check we haven't visited the node already.
        if (!nodelist_contains(visitedNodes, offset))
        {
            // Display the node
            return getPrintedNode(fileNodes, offset, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, shouldBracket);
        }
        else // If we've visited the node already then we can't show it, so show an underscore.
        {
            if (showWhenUnevaluated)
            {
                strncat(reductionBuffer, "_", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            }
            return false;
        }
    }
    else // If we're beyond the limit then display only the function calls - no results.
    {
        if (showWhenUnevaluated)
        {
            return getPrintedNode(fileNodes, offset, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, false, false, shouldBracket);
        }
        
        return false;
    }
}

char getExpValueApp(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes, char *reductionBuffer, char showWhenUnevaluated, char showResult, char trusted, char shouldBracket)
{
    node *atomNode;
    node *theNode = nodehash_getNode (fileNodes, offset);
    fixPri fix;
    char *name;
    int  argIndex;
    char showedSomething = false;
    char showedArg = false;
    
    /* Find out what kind of function this is - we need to know if it is a special case.
       There are two special cases - the "," function and the ":" function
       these represent the tuple construction and the list construction in turn. */
    atomNode = findAtomNode(fileNodes, theNode->params.expValueApp.function, visitedNodes);
    if (atomNode)
    {
        if (atomNode->nodeType == AtomConstructor)
        {
            fix = atomNode->params.atomConstructor.fix;
            name = atomNode->params.atomConstructor.name;
        }
        else if (atomNode->nodeType == AtomVariable)
        {
            fix = atomNode->params.atomVariable.fix;
            name = atomNode->params.atomVariable.name;
        }
    }
    else
    {
        fix.fix = defaultFix;
        fix.something = theNode->params.expValueApp.arity;
        name = " ";
    }
    
    if (!strcmp(name, ",")) // Special case: The tuple function - start with an open bracket.
    {
        fix.fix = infixl;
    }
    if (!strcmp(name, ":"))
    {
        if (canBePrettyPrinted(fileNodes, offset, maxOffset))
        {
            if (!isString(fileNodes, offset))
            {
                strncat(reductionBuffer, "[", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                showedSomething = getListPrettyPrinted(fileNodes, offset, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
                strncat(reductionBuffer, "]", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            }
            else
            {
                strncat(reductionBuffer, "\"", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                stringMode = true;
                showedSomething = getListPrettyPrinted(fileNodes, offset, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
                stringMode = false;
                strncat(reductionBuffer, "\"", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            }
        }
    }

    if (!showedSomething)
    {
        if (shouldBracket || !strcmp(name, ","))
        {
            strncat(reductionBuffer, "(", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
        }
        if (fix.fix == defaultFix) // If the function is not infix, start with it's function name.
        {
            showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expValueApp.function, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
            strncat(reductionBuffer, " ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
        }
        // Either the function is not infix and we have shown it's name, or we have already
        // found it's name - in this case we know we can display it, so it's safe to continue.
        if (showedSomething || fix.fix != defaultFix)
        {
            showedSomething = true;
            for (argIndex = 0; argIndex < theNode->params.expValueApp.arity - 1; argIndex++)
            {
                showedArg = tryGetPrintedNode(fileNodes, theNode->params.expValueApp.args[argIndex], maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
                if (fix.fix != defaultFix)
                {
                    strncat(reductionBuffer, name, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
                else
                {
                    strncat(reductionBuffer, " ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                }
            }
            showedArg = tryGetPrintedNode(fileNodes, theNode->params.expValueApp.args[theNode->params.expValueApp.arity - 1], maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
        }
        if (shouldBracket || !strcmp(name, ","))
        {
            strncat(reductionBuffer, ")", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
        }
    }

    return showedSomething;
}

char getExpApp(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes, char *reductionBuffer, char showWhenUnevaluated, char showResult, char trusted, char shouldBracket)
{
    node *theNode = nodehash_getNode(fileNodes, offset);
    node *atomNode;
    fixPri fix;
    char *name;
    int  argIndex;
    char showedSomething = false;
    char showedArg = false;
    
    // If we have evaluated something about the function, display it
    /*char *temp;
    asprintf(&temp, "0x%x", theNode->offset);
    strncat(reductionBuffer, temp, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
    free(temp);*/
    if (showResult)
    {
        showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expApp.result, maxOffset, visitedNodes, reductionBuffer, false, showResult, trusted, shouldBracket);
    }
    
    
    // If we haven't done any evaluation, find out what we know about the function and display it.
    if (!showedSomething)
    {
        /* Find out what kind of function this is - we need to know if it is a special case.
        There are two special cases - the "," function and the ":" function
        these represent the tuple construction and the list construction in turn. */
        atomNode = findAtomNode(fileNodes, theNode->params.expApp.function, visitedNodes);
        if (atomNode)
        {
            if (atomNode->nodeType == AtomConstructor)
            {
                fix = atomNode->params.atomConstructor.fix;
                name = atomNode->params.atomConstructor.name;
            }
            else if (atomNode->nodeType == AtomVariable)
            {
                fix = atomNode->params.atomVariable.fix;
                name = atomNode->params.atomVariable.name;
            }
        }
        else
        {
            fix.fix = defaultFix;
            fix.something = theNode->params.expApp.arity;
            name = " ";
        }
        
        if (list_contains_string(trustees, name))
        {
            showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expApp.result, maxOffset, visitedNodes, reductionBuffer, false, showResult, true, shouldBracket);
        }
        else
        {
            if (shouldBracket)
            {
                strncat(reductionBuffer, "(", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            }
            if (fix.fix == defaultFix) // If the function is not infix, start with it's function name.
            {
                showedSomething = tryGetPrintedNode(fileNodes, theNode->params.expApp.function, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
                strncat(reductionBuffer, " ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            }        
            
            if (showedSomething || fix.fix != defaultFix)
            {
                showedSomething = true;
                for (argIndex = 0; argIndex < theNode->params.expApp.arity - 1; argIndex++)
                {
                    showedArg = tryGetPrintedNode(fileNodes, theNode->params.expApp.args[argIndex], maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
                    if (fix.fix != defaultFix)
                    {
                        strncat(reductionBuffer, " ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                        strncat(reductionBuffer, name, MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                        strncat(reductionBuffer, " ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                    }
                    else
                    {
                        strncat(reductionBuffer, " ", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                    }
                }
                showedArg = tryGetPrintedNode(fileNodes, theNode->params.expApp.args[theNode->params.expApp.arity - 1], maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, true);
            }
            if (shouldBracket)
            {
                strncat(reductionBuffer, ")", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
            }
        }
    }
    
    return showedSomething;    
}

char getListPrettyPrinted(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes, char *reductionBuffer, char showWhenUnevaluated, char showResult, char trusted)
{
    node *theNode = nodehash_getNode(fileNodes, offset);
    node *testNode;
    char showedArg = false;
    
    if (theNode->offset <= maxOffset || theNode->nodeType == ExpHidden || theNode->nodeType == ExpForward || theNode->nodeType == ExpProjection)
    {
        switch (theNode->nodeType)
        {
            case ExpApp:
                return getListPrettyPrinted(fileNodes, theNode->params.expApp.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
            case ExpCase:
                return getListPrettyPrinted(fileNodes, theNode->params.expCase.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
            case ExpConstDef:
                return getListPrettyPrinted(fileNodes, theNode->params.expConstDef.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
            case ExpConstUse:
                return getListPrettyPrinted(fileNodes, theNode->params.expConstUse.value, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
            case ExpFieldUpdate:
                return getListPrettyPrinted(fileNodes, theNode->params.expFieldUpdate.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
            case ExpForward:
                return getListPrettyPrinted(fileNodes, theNode->params.expForward.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
            case ExpGuard:
                return getListPrettyPrinted(fileNodes, theNode->params.expGuard.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
            case ExpHidden:
                return getListPrettyPrinted(fileNodes, theNode->params.expHidden.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
            case ExpIf:
                return getListPrettyPrinted(fileNodes, theNode->params.expIf.result, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
            case ExpProjection:
                return getListPrettyPrinted(fileNodes, theNode->params.expProjection.exp, maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
            case ExpValueApp:
                showedArg = tryGetPrintedNode(fileNodes, theNode->params.expValueApp.args[0], maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted, false);
                if (isMoreList(fileNodes, theNode->params.expValueApp.args[1], maxOffset))
                {
                    if (!isString(fileNodes, offset))
                    {
                        strncat(reductionBuffer, ",", MAX_REDUCTION_LENGTH - 1 - strlen(reductionBuffer));
                    }
                    showedArg = getListPrettyPrinted(fileNodes, theNode->params.expValueApp.args[1], maxOffset, visitedNodes, reductionBuffer, showWhenUnevaluated, showResult, trusted);
                }
            case ExpValueUse:
                showedArg = true;
            default:
                showedArg = true;
        }
    }
    return showedArg;
}

char isMoreList(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset)
{
    node *theNode = nodehash_getNode(fileNodes, offset);

    if (theNode->offset <= maxOffset || theNode->nodeType == ExpHidden || theNode->nodeType == ExpForward || theNode->nodeType == ExpProjection)
     {
        switch (theNode->nodeType)
        {
            case ExpApp:
                return isMoreList(fileNodes, theNode->params.expApp.result, maxOffset);
            case ExpCase:
                return isMoreList(fileNodes, theNode->params.expCase.result, maxOffset);
            case ExpConstDef:
                return isMoreList(fileNodes, theNode->params.expConstDef.result, maxOffset);
            case ExpConstUse:
                return isMoreList(fileNodes, theNode->params.expConstUse.value, maxOffset);
            case ExpFieldUpdate:
                return isMoreList(fileNodes, theNode->params.expFieldUpdate.result, maxOffset);
            case ExpForward:
                return isMoreList(fileNodes, theNode->params.expForward.result, maxOffset);
            case ExpGuard:
                return isMoreList(fileNodes, theNode->params.expGuard.result, maxOffset);
            case ExpHidden:
                return isMoreList(fileNodes, theNode->params.expHidden.result, maxOffset);
            case ExpIf:
                return isMoreList(fileNodes, theNode->params.expIf.result, maxOffset);
            case ExpProjection:
                return isMoreList(fileNodes, theNode->params.expProjection.exp, maxOffset);
            case ExpValueApp:
                return true;
            default:
                return false;
        }
    }
}

char isString(nodehash *fileNodes, unsigned long offset)
{
    node *theNode = nodehash_getNode(fileNodes, offset);
    node *itemNode = nodehash_getNode(fileNodes, theNode->params.expValueApp.args[0]);
    
    if (itemNode->nodeType == ExpChar)
    {
        return true;
    }
    else
    {
        return false;
    }
}

char canBePrettyPrinted(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset)
{
    node *theNode = nodehash_getNode(fileNodes, offset);
    node *testNode;

    if (theNode->offset > maxOffset && !(theNode->nodeType == ExpHidden || theNode->nodeType == ExpForward || theNode->nodeType == ExpProjection))
    {
        return false;
    }

    switch (theNode->nodeType)
    {
        case ExpApp:
            return canBePrettyPrinted(fileNodes, theNode->params.expApp.result, maxOffset);
        case ExpCase:
            return canBePrettyPrinted(fileNodes, theNode->params.expCase.result, maxOffset);
        case ExpConstDef:
            return canBePrettyPrinted(fileNodes, theNode->params.expConstDef.result, maxOffset);
        case ExpConstUse:
            return canBePrettyPrinted(fileNodes, theNode->params.expConstUse.value, maxOffset);
        case ExpFieldUpdate:
            return canBePrettyPrinted(fileNodes, theNode->params.expFieldUpdate.result, maxOffset);
        case ExpForward:
            return canBePrettyPrinted(fileNodes, theNode->params.expForward.result, maxOffset);
        case ExpGuard:
            return canBePrettyPrinted(fileNodes, theNode->params.expGuard.result, maxOffset);
        case ExpHidden:
            return canBePrettyPrinted(fileNodes, theNode->params.expHidden.result, maxOffset);
        case ExpIf:
            return canBePrettyPrinted(fileNodes, theNode->params.expIf.result, maxOffset);
        case ExpProjection:
            return canBePrettyPrinted(fileNodes, theNode->params.expProjection.exp, maxOffset);
        case ExpValueApp:
            if (!strcmp(nodehash_getNode(fileNodes, theNode->params.expValueApp.function)->params.atomVariable.name, ":"))
            {
                return canBePrettyPrinted(fileNodes, theNode->params.expValueApp.args[1], maxOffset);
            }
            return false;
        case ExpValueUse:
            testNode = nodehash_getNode(fileNodes, theNode->params.expValueUse.value);
            if (testNode->nodeType == AtomConstructor)
            {
                return !strcmp(testNode->params.atomConstructor.name, "[]");
            }
            return false;
        default:
            return false;
    }

    return false;
}


unsigned long findNextDisplayingNode(nodehash *fileNodes, unsigned long offset, unsigned long maxOffset, nodelist *visitedNodes)
{
    node *theNode = NULL;
    int  argIndex;
    unsigned long testOffset;
    unsigned long workingOffset = MAX_U_LONG;
    
    theNode = nodehash_getNode(fileNodes, offset);
    
    nodelist_push(visitedNodes, theNode);
    
    //fprintf(stderr, "<%s offset=\"0x%x\">\n", tag2str(theNode->nodeType), offset);
    
    switch (theNode->nodeType)
    {
        case AtomAbstract:
        case AtomConstructor:
        case AtomVariable:
            workingOffset = offset;
            break;
        case ExpApp:
            if (offset > maxOffset)
            {
                workingOffset = offset;
            }
            else
            {
                node *atomNode = findAtomNode(fileNodes, theNode->params.expApp.function, visitedNodes);
                char *name;
                
                
                if (atomNode->nodeType == AtomConstructor)
                {
                    name = atomNode->params.atomConstructor.name;
                }
                else if (atomNode->nodeType == AtomVariable)
                {
                    name = atomNode->params.atomVariable.name;
                }
                // Check if this is a trusted function.
                if (!list_contains_string(trustees, name))
                {
                    // Check the function arguments
                    for (argIndex = 0; argIndex < theNode->params.expApp.arity; argIndex++)
                    {
                        if (!nodelist_contains(visitedNodes, theNode->params.expApp.args[argIndex]))
                        {
                            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expApp.args[argIndex], maxOffset, visitedNodes);
                            if (testOffset > maxOffset && testOffset < workingOffset)
                            {
                                workingOffset = testOffset;
                            }
                        }
                    }
                    
                    // Check for the whole function being evaluated.
                    if (!nodelist_contains(visitedNodes, theNode->params.expApp.result))
                    {
                        testOffset = findNextDisplayingNode(fileNodes, theNode->params.expApp.result, maxOffset, visitedNodes);
                        if (testOffset > maxOffset && testOffset < workingOffset)
                        {
                            workingOffset = testOffset;
                        }
                    }
                }
            }
            break;
        case ExpCase:
            // Check when the condition is evaluated.
            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expCase.condition, maxOffset, visitedNodes);
            if (testOffset > maxOffset)
            {
                workingOffset = testOffset;
            }
                
            // Check when the result is evaluated.
            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expCase.result, maxOffset, visitedNodes);
            if (testOffset > maxOffset && testOffset < workingOffset)
            {
                workingOffset = testOffset;
            }
            break;
        case ExpChar:
            workingOffset = offset;
            break;
        case ExpConstDef:
            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expConstDef.var, maxOffset, visitedNodes);
            if (testOffset > maxOffset)
            {
                workingOffset = testOffset;
            }
                
            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expConstDef.result, maxOffset, visitedNodes);
            if (testOffset > maxOffset && testOffset < workingOffset)
            {
                workingOffset = testOffset;
            }
            break;
        case ExpConstUse:
            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expConstUse.value, maxOffset, visitedNodes);
            break;
        case ExpDouble:
            workingOffset = offset;
            break;
        case ExpFieldUpdate:
            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expFieldUpdate.arg, maxOffset, visitedNodes);
            if (testOffset <= maxOffset)
            {
                for (argIndex = 0; argIndex < theNode->params.expFieldUpdate.arity; argIndex++)
                {
                    testOffset = findNextDisplayingNode(fileNodes, theNode->params.expFieldUpdate.binders[argIndex], maxOffset, visitedNodes);
                    if (testOffset > maxOffset && testOffset < workingOffset)
                    {
                        workingOffset = testOffset;
                    }
                    testOffset = findNextDisplayingNode(fileNodes, theNode->params.expFieldUpdate.bindees[argIndex], maxOffset, visitedNodes);
                    if (testOffset > maxOffset && testOffset < workingOffset)
                    {
                        workingOffset = testOffset;
                    }
                }
            }
            else
            {
                workingOffset = testOffset;
            }
            
            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expFieldUpdate.result, maxOffset, visitedNodes);
            if (testOffset < workingOffset && testOffset > maxOffset)
            {
                workingOffset = testOffset;
            }
                
            break;
        case ExpFloat:
            workingOffset = offset;
            break;
        case ExpForward:
            workingOffset = findNextDisplayingNode(fileNodes, theNode->params.expForward.result, maxOffset, visitedNodes);
            break;
        case ExpGuard:
            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expGuard.condition, maxOffset, visitedNodes);
            if (testOffset > maxOffset)
            {
                workingOffset = testOffset;
            }
                
            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expGuard.result, maxOffset, visitedNodes);
            if (testOffset > maxOffset && testOffset < workingOffset)
            {
                workingOffset = testOffset;
            }
            break;
        case ExpHidden:
            workingOffset = findNextDisplayingNode(fileNodes, theNode->params.expHidden.result, maxOffset, visitedNodes);
            break;
        case ExpIf:
            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expIf.condition, maxOffset, visitedNodes);
            if (testOffset > maxOffset)
            {
                workingOffset = testOffset;
            }
                
            testOffset = findNextDisplayingNode(fileNodes, theNode->params.expIf.result, maxOffset, visitedNodes);
            if (testOffset > maxOffset && testOffset < workingOffset)
            {
                workingOffset = testOffset;
            }
            break;
        case ExpInt:
        case ExpInteger:
            workingOffset = offset;
            break;
        case ExpProjection:
            workingOffset = findNextDisplayingNode(fileNodes, theNode->params.expProjection.exp, maxOffset, visitedNodes);
            break;            
        case ExpRat:
        case ExpRational:
            workingOffset = offset;
            break;
        case ExpValueApp:
            // Check for each argument being evaluated.
            if (offset > maxOffset)
            {
                workingOffset = offset;
            }
            else
            {
                for (argIndex = 0; argIndex < theNode->params.expValueApp.arity; argIndex++)
                {
                    if (!nodelist_contains(visitedNodes, theNode->params.expValueApp.args[argIndex]))
                    {
                        testOffset = findNextDisplayingNode(fileNodes, theNode->params.expValueApp.args[argIndex], maxOffset, visitedNodes);
                        if (testOffset > maxOffset && testOffset < workingOffset)
                        {
                            workingOffset = testOffset;
                        }
                    }
                }
            }
            
            break;
        case ExpValueUse:
            if (!theNode->params.expValueUse.isLambda)
            {
                workingOffset = findNextDisplayingNode(fileNodes, theNode->params.expValueUse.value, maxOffset, visitedNodes);
            }
            else
            workingOffset = offset;
            break;
    }
    
    nodelist_pop (visitedNodes);
    
    //fprintf(stderr, "</%s>", tag2str(theNode->nodeType));

    return (workingOffset < offset ? offset : workingOffset);
}

node *findAtomNode(nodehash *fileNodes, unsigned long offset, nodelist *visitedNodes)
{
    node *theNode = NULL;
    node *foundNode = NULL;
    
    theNode = nodehash_getNode(fileNodes, offset);
    
    nodelist_push(visitedNodes, theNode);
    
    switch (theNode->nodeType)
    {
        case AtomAbstract:
        case AtomConstructor:
        case AtomVariable:
            foundNode = theNode;
            break;
        case ExpApp:
            foundNode = findAtomNode(fileNodes, theNode->params.expApp.result, visitedNodes);
            break;
        case ExpCase:
            foundNode = findAtomNode(fileNodes, theNode->params.expCase.result, visitedNodes);
            break;
        case ExpConstDef:
            foundNode = findAtomNode(fileNodes, theNode->params.expConstDef.var, visitedNodes);
            break;
        case ExpConstUse:
            foundNode = findAtomNode(fileNodes, theNode->params.expConstUse.value, visitedNodes);
            break;
        case ExpFieldUpdate:
            foundNode = findAtomNode(fileNodes, theNode->params.expFieldUpdate.result, visitedNodes);
            break;
        case ExpForward:
            foundNode = findAtomNode(fileNodes, theNode->params.expForward.result, visitedNodes);
            break;
        case ExpGuard:
            foundNode = findAtomNode(fileNodes, theNode->params.expGuard.result, visitedNodes);
            break;
        case ExpHidden:
            foundNode = findAtomNode(fileNodes, theNode->params.expHidden.result, visitedNodes);
            break;
        case ExpIf:
            foundNode = findAtomNode(fileNodes, theNode->params.expIf.result, visitedNodes);
            break;
        case ExpProjection:
            foundNode = findAtomNode(fileNodes, theNode->params.expProjection.exp, visitedNodes);
            break;
        case ExpValueApp:
            foundNode = findAtomNode(fileNodes, theNode->params.expValueApp.function, visitedNodes);
            break;
        case ExpValueUse:
            foundNode = findAtomNode(fileNodes, theNode->params.expValueUse.value, visitedNodes);
            break;
    }
    
    nodelist_pop (visitedNodes);
    
    return foundNode;
}

/* strings for symbolic constants - taken from hat-check */
char* tag2str (int k)
{
    switch (k)
    {
        case Module:
            return "Module";
        case SrcPos:
            return "SrcPos";
        case ExpApp:
            return "ExpApp";
        case ExpValueApp:
            return "ExpValueApp";
        case ExpChar:
            return "ExpChar";
        case ExpInt:
            return "ExpInt";
        case ExpInteger:
            return "ExpInteger";
        case ExpRat:
            return "ExpRat";
        case ExpRational:
            return "ExpRational";
        case ExpFloat:
            return "ExpFloat";
        case ExpDouble:
            return "ExpDouble";
        case ExpValueUse:
            return "ExpValueUse";
        case ExpConstUse:
            return "ExpConstUse";
        case ExpConstDef:
            return "ExpConstDef";
        case ExpGuard:
            return "ExpGuard";
        case ExpCase:
            return "ExpCase";
        case ExpIf:
            return "ExpIf";
        case ExpFieldUpdate:
            return "ExpFieldUpdate";
        case ExpProjection:
            return "ExpProjection";
        case ExpHidden:
            return "ExpHidden";
        case ExpForward:
            return "ExpForward";
        case ExpDoStmt:
            return "ExpDoStmt";
        case AtomVariable:
            return "AtomVariable";
        case AtomConstructor:
            return "AtomConstructor";
        case AtomAbstract:
            return "AtomAbstract";
            
        case ANYEXP:
            return "Exp";
        case ANYATOM:
            return "Atom";
        case HEADER:
            return "HEADER";
        case INVALID:
            return "INVALID";
        case BEYOND:
            return "beyond end of file";
            
        default:
            return "unknown/unused";
    }
}

/**
 * Taken from hat-check.
 * Checks if the end of a string ends in a certain way.
 * 
 * @return |true| iff e ends with s. \
 *         |false| otherwise.
 */
int strends (char *e, char *s)
{
    int d = strlen(s) - strlen(e);
    return d>=0 && strcmp(s+d, e)==0;
}

/**
 * Displays the usage string.
 */
void badUsage (void)
{
    fprintf(stderr,"usage: hat-anim prog-name [offset]\n");
    endwin();
    exit(1);
}

void repaint(stack *redexTrail, char *command, char *debugStr)
{
    int redexTrailSize = 0,
        redexTrailWindowLine,
        trailSpace = LINES - 3,
        colNum;
    stack *redexTrailBackup = stack_newByCopyingStack(redexTrail);
    
    erase();
    
    // Print a heading.
    attron(A_BOLD);
    mvprintw(0, 0, "Animation:");
    attroff(A_BOLD);
    mvprintw(0, 10, " ------- file.hs line: ? col: ? -");
    for (colNum = 43; colNum < COLS; colNum++)
    {
        mvprintw(0, colNum, "-");
    }

    redexTrailSize = stack_size(redexTrailBackup);
    
    redexTrailWindowLine = (redexTrailSize > trailSpace ? trailSpace : redexTrailSize);
    while (redexTrailWindowLine > 2)
    {
        mvprintw(redexTrailWindowLine, 0, "->");
        printReduction(redexTrailWindowLine, stack_pop(redexTrailBackup));
        redexTrailWindowLine--;
    }
    
    if (stack_size(redexTrailBackup) == 2)
    {
        mvprintw(2, 0, "-> ");
        printReduction(2, stack_pop(redexTrailBackup));
    }
    else if (stack_size(redexTrailBackup) > 2)
    {
        mvprintw(2, 0, "-> . . .");
        while (stack_size(redexTrailBackup) > 1)
        {
            stack_pop(redexTrailBackup);
        }
    }
    mvprintw(1, 0, "   ");
    printReduction(1, stack_pop(redexTrailBackup));
    for (colNum = 0; colNum < COLS; colNum++)
    {
        mvprintw(LINES - 2, colNum, "-");
    }
    mvprintw(LINES - 1, 0, command);
    
    if (debugStr)
    {
        mvprintw(LINES - 2, 2, debugStr);
    }
    
    stack_delete(redexTrailBackup);
}

void printReduction(int lineNo, char *reduction)
{
    char *line = (char *)malloc(sizeof(char) * COLS - 2);
    
    if (scrollPos < strlen(reduction))
    {
        if (scrollPos == 0)
        {
            if (strlen((char *)((int)reduction + scrollPos)) > COLS - 3)
            {
                strncpy(line, (char *)((int)reduction + scrollPos), COLS - 6);
                line[COLS - 6] = '.';
                line[COLS - 5] = '.';
                line[COLS - 4] = '.';
                line[COLS - 3] = '\0';
                mvprintw(lineNo, 3, "%s", line);
            }
            else
            {
                mvprintw(lineNo, 3, "%s", reduction);
            }
        }
        else
        {
            line[0] = '.';
            line[1] = '.';
            line[2] = '.';
            if (strlen((char *)((int)reduction + scrollPos)) > COLS - 6)
            {
                strncpy((char *)((int)line + 3), (char *)((int)reduction + scrollPos), COLS - 6);
                line[COLS - 6] = '.';
                line[COLS - 5] = '.';
                line[COLS - 4] = '.';
                line[COLS - 3] = '\0';
                mvprintw(lineNo, 3, "%s", line);
            }
            else
            {
                strcpy((char *)((int)line + 3), (char *)((int)reduction + scrollPos));
                mvprintw(lineNo, 3, "%s", line);
            }
        }
    }
    else
    {
        mvprintw(lineNo, 3, "...");
    }
}

void doCommand(char *command)
{
    if (!strcmp(command, ":q") || !strcmp(command, ":quit"))
    {
        exiting = true;
    }
    else if (!strcmp(command, ":help"))
    {
        displayHelp();
    }
    else if (!strncmp(command, ":trust ", 7))
    {
        char *newString = (char *)malloc((strlen(command) - 6) * sizeof(char));
        
        strcpy(newString, command+7);
        list_add(trustees, newString);
    }
    else if (!strncmp(command, ":untrust ", 9))
    {
        char *newString = (char *)malloc((strlen(command) - 8) * sizeof(char));
        
        strcpy(newString, command+9);
        list_remove_string(&trustees, newString);
        free(newString);
    }
    else if (!strcmp(command, ":untrust_all"))
    {
        list_delete(trustees);
        trustees = list_newEmptyList();
    }
}

unsigned long reloadCache(nodehash *fileHash, unsigned long maxOffset)
{
    unsigned long nextOffset;
    nodelist *visitedNodes;
    char *reductionBuffer;
    char debugReductionBuffer[MAX_REDUCTION_LENGTH];
    
    //fprintf(stderr, "offset: %x", startOffset);
    //scanf("%c", debugReductionBuffer);
    currentOffset = startOffset;
    if (redexTrail)
    {
        stack_delete(redexTrail);
    }
    redexTrail = stack_newEmptyStack();
    nextOffset = MAX_U_LONG;
    reductionBuffer = (char *)malloc(sizeof(char) * MAX_REDUCTION_LENGTH);
    reductionBuffer[0] = '\0';
    visitedNodes = nodelist_newEmptyList();
    getPrintedNode(fileHash, startOffset, currentOffset, visitedNodes, reductionBuffer, true, true, false, false);
    nodelist_delete(visitedNodes);
    visitedNodes = nodelist_newEmptyList();
    nextOffset = findNextDisplayingNode(fileHash, startOffset, currentOffset, visitedNodes);
    if (nextOffset == startOffset)
    {
        nextOffset = MAX_U_LONG;
    }
    nodelist_delete(visitedNodes);
    stack_push(redexTrail, reductionBuffer);
    while(currentOffset < maxOffset)
    {
        lastMaxOffset = currentOffset;
        currentOffset = nextOffset;
        nextOffset = MAX_U_LONG;
        reductionBuffer = (char *)malloc(sizeof(char) * MAX_REDUCTION_LENGTH);
        reductionBuffer[0] = '\0';
        debugReductionBuffer[0] = '\0';
        visitedNodes = nodelist_newEmptyList();
        //getPrintedNode(fileHash, startOffset, currentOffset, visitedNodes, debugReductionBuffer, true, true, false, false);
        //fprintf(stderr, "Getting next node.\n");
        getPrintedNode(fileHash, startOffset, currentOffset, visitedNodes, reductionBuffer, true, true, false, false);
        nodelist_delete(visitedNodes);
        visitedNodes = nodelist_newEmptyList();
        //fprintf(stderr, "Finding next node.\n");
        nextOffset = findNextDisplayingNode(fileHash, startOffset, currentOffset, visitedNodes);
        //fprintf(stderr, "found next node.\n");
        if (nextOffset == startOffset)
        {
            nextOffset = MAX_U_LONG;
        }
        nodelist_delete(visitedNodes);
        //sprintf(reductionBuffer, "%x - %s", nextOffset, debugReductionBuffer);
        stack_push(redexTrail, reductionBuffer);
    }
    
    return nextOffset;
}

void displayHelp(void)
{
    erase();

    // Print a heading.
    attron(A_BOLD);
    mvprintw( 0, 0, "hat-anim - Help");
    attroff(A_BOLD);
    mvprintw( 1, 0, "hat-anim is a forward tracer that animates Haskell programs.");
    mvprintw( 2, 0, "Commands may be entered by pressing ':'.");
    mvprintw( 3, 0, "Commands:");
    mvprintw( 4, 0, "help         Brings up this help screen");
    mvprintw( 5, 0, "trust <f>    Trusts a function with name <f>.");
    mvprintw( 6, 0, "             Applications of this function will not be shown.");
    mvprintw( 7, 0, "untrust <f>  Un-trusts a function with name <f>.");
    mvprintw( 8, 0, "             Reverses the effect of trust, does nothing if <f>");
    mvprintw( 9, 0, "             is not trusted.");
    mvprintw(10, 0, "untrust_all  Untrusts all functions.");
    mvprintw(11, 0, "q or quit    Exits hat-anim.");
    while (getch() != '\n')
    {

    }
}

Generated by  Doxygen 1.6.0   Back to index