              <<< VAXAXP::NOTES$:[NOTES$LIBRARY]VMSNOTES.NOTE;1 >>>
               -< VAX and Alpha VMS - Digital Internal Use Only >-
================================================================================
Note 19.12                 RECALL/OUT from a comfile?                   12 of 12
CSC64::BLAYLOCK "If at first you doubt,doubt again" 214 lines  10-JAN-1996 20:26
                    -< You may as well use a real language >-
--------------------------------------------------------------------------------
/*

    Read the command lines from the recall buffer and optionally
    place them into a file.  Ugly points given for the choice
    of access method for the DCL symbols.

    Build procedure:

    $ CC /DECC /STANDARD = RELAX RECALL_OUT
    $ IF F$GETSYI("ARCH_NAME") .EQS. "VAX"
    $ THEN
    $   LINK RECALL_OUT + SYS$SYSTEM:SYS.STB/SELECTIVE + DCLDEF /SELECTIVE
    $ ELSE
    $   LINK /SYSEXE RECALL_OUT + SYS$LOADABLE_IMAGES:DCLDEF.STB /SELECTIVE
    $ ENDIF
    $ RECALL_OUT :== $'F$ENVIRONMENT("DEFAULT")'RECALL_OUT

    Parameters:

        recall_out file-name limit r

            file-name is a vms file name (can be "")
            limit is a numeric value default is -1
            r is reverse - all others or not specified recall forward.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <perror.h>

#include <ssdef.h>

//
// The following value is obtained by linking with LINK /SYSEXE
//
#pragma extern_model save
#pragma extern_model strict_refdef

extern int ctl$ag_clidata ;    // Actually a pointer to a PRC ...
//
// The following are obtained with LINK 
...+sys$loadable_images:dcldef.stb/sel
//
extern char ppd$l_prc, prc_l_recallptr, prc_g_commands, prc_c_cmdbufsiz ;
#pragma extern_model restore


void write_recall_buffer( FILE *fd, int limit, int forward ) ;

int main(int argc, char *argv[])
{

    FILE *fd = NULL ;
    int limit = -1, forward = 1 ;

    fd = stdout ;           // Default device

    if (argc > 1)
    {
        
        if (strlen(argv[1]) > 0)
            fd = fopen((const char*) argv[1], "w") ;
        if (fd == NULL)
            perror("Error opening file for write"), exit(2) ;
    }
    if (argc > 2)
    {
        limit = atol((const char*)argv[2]) ;
        if (limit == 0) limit = -1 ;
    }
    if (argc == 4)
    {
        if (strcmp(argv[3], "r") == 0)
            forward = 0 ;
    }

    write_recall_buffer( fd, limit, forward ) ;

    if(fd != stdout)
        fclose( fd ) ;

    return 1 ;

}

void write_recall_buffer( FILE *file_desc, int limit, int forward ) 
{
/*
    The recall buffer is a seris of (up 255 byte) strings in
    memory.  They are contained within a structure known as
    the PRC region within dcl.  This region is pointed to by
    the ppd$l_prc field in the PPD structure pointed to by
    CTL$AG_CLIDATA.  This is all user read data (no write).
*/
    char *cli_data, *temp ;
    char *recall_ptr, *current_string, *command_buffer ;
    char *ptr, *command ;
    char *end_buffer ;
    char length;
    char *prc ;
    int wrap = 0;

    temp = &ppd$l_prc ;
    cli_data = (char *) &ctl$ag_clidata ;
    prc =  (char*)(*(int *)(cli_data + (int)temp)) ;

#ifdef DEBUG
    printf("The PRC address is %x\n", prc ) ;
#endif

    temp = &prc_l_recallptr ;
    recall_ptr = (char *)((*(int *)(prc + (int)temp))) ;
    ptr = recall_ptr ;
#ifdef DEBUG
    printf("The recall_ptr address is %x\n", recall_ptr ) ;
#endif
    temp = &prc_g_commands ;
    command_buffer = (char*)(prc + (int)temp) ;

    end_buffer = command_buffer + (int)&prc_c_cmdbufsiz ;
    
    if (forward) 
    {
        while (*ptr == 0 )
        {
        //
        // Advance through the null characters until we find the
        // oldest command
        //
            ptr++ ;
            if (ptr > end_buffer) ptr = command_buffer ;
            if (ptr == recall_ptr) 
            {
            //
            // We have gone through the entire buffer, just return
            //
                return ;
            }
        }
        ptr-- ;
    }
    if (forward)
    {
        ptr++;
        if (ptr > end_buffer)
        {
            ptr = command_buffer ;
            wrap = 1 ;
        }
    }
    else // backwards search
    {
        ptr-- ;
        if (ptr < command_buffer)
        {
            ptr = end_buffer - 1;
            wrap = 1 ;
        }
    }
    while (((length = *ptr) != 0) && limit--)
    {

        if (forward)
        {
            current_string = ptr + 1 ;
            if (current_string > end_buffer)
                current_string = command_buffer ;
        }
        else
        {
            current_string = ptr - length ;
            if (current_string < command_buffer)
            {
                current_string = end_buffer - (int)(ptr - length) ;
            }
        }
        if (forward)
        {
            ptr = ptr + 1 + length + 1;
            if (ptr >= end_buffer) ptr = command_buffer ;
        }
        else
        {
            ptr = ptr - 1 - length - 1 ;
        }
        fprintf(file_desc, "$ ") ;
        if ((current_string + length) >= end_buffer)
        {
            int tmp_len = end_buffer - current_string ;
            length = length - tmp_len ;
            fprintf(file_desc, "%.*s", tmp_len, current_string) ;
            current_string = command_buffer ;
            ptr = ptr + length ;
        }
        fprintf(file_desc, "%.*s\n", length, current_string) ;

        if (ptr == recall_ptr)  // Finished with the commands
            break ;

        if (forward)
        {
            ptr++ ;
            if (ptr >= end_buffer) ptr = command_buffer ;
        }
        else
        {
            ptr-- ;
            if (ptr < command_buffer)
                ptr = end_buffer - 1 ;
        }
    }
    
}

