<commit_before>/*
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <http://unlicense.org>
*/

#define _LARGEFILE64_SOURCE

#include "pfkutils_config.h"
#ifndef _GNU_SOURCE 
#define _GNU_SOURCE
#endif
#define _FILE_OFFSET_BITS 64

#include <stdio.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>

#ifdef HAVE_NCURSES_CURSES_H
#include <ncurses/curses.h>
#else
#ifdef HAVE_NCURSES_H
#include <ncurses.h>
#else
#ifdef HAVE_CURSES_H
#include <curses.h>
#else
#error need some kind of curses.h
#endif
#endif
#endif

#include "m.h"

#ifdef __CYGWIN__
/* wtf?? apparently no prototype in system headers. */
off_t _lseek64(int filedes, off_t offset, int whence);
#endif

#ifndef MAP_FAILED
#define MAP_FAILED -1
#endif

enum mark_op { SET_MARK, GOTO_MARK };
enum pointer_type { BIG_ENDIAN_PTR, LITTLE_ENDIAN_PTR };

static int         file_descriptor;
static char *      file_name;
static off_t       file_size;
static off_t       file_position;
static int         pos_width;
static int         cursor_line;
static int         charsperline;
static int         insert_mode;
static int         readonly;

static enum { ed_HEX, ed_TEXT } ed;
static enum { disp_HEX, disp_TEXTW, disp_TEXTL } disp;
static enum { ESC_NORMAL, ESC_GOT1B, ESC_GOT5B,
              ESC_GOT35,  ESC_GOT36 } esc_seq_state;

#define MAX_MARKS 26
static off_t mark_locations[ MAX_MARKS ];

static int    get_pos_width( void );
static void   update_screen( void );
static void   handle_character( int c );
static void   do_help( void );
static void   do_help_tty( void );
static int    ishex( int c );
static int    hex_to_dig( int c );
static void   go_offset( void );
static void   do_search( void );
static void   do_mark( enum mark_op op );
static void   do_rel_move( void );
static void   formula_initialize( void );
static void   deref_pointer( enum pointer_type );
static int    get_file_byte( off_t pos );
static void   get_file_data( off_t pos, unsigned char *data, int len );
static void   put_file_byte( off_t pos, int data );

#if 0
static FILE * debug_fd = NULL;
#define DEBUG(x) if ( debug_fd != NULL ) fprintf x
#define OPEN_TTY "/dev/pts/1"
#else
#define DEBUG(x)
#endif

int
he_main( int argc, char ** argv )
{
    struct stat sb;
    int i, c;
    int open_options;

    if ( argc != 2 )
    {
        do_help_tty();
        return 1;
    }

#ifdef OPEN_TTY
    debug_fd = fopen( OPEN_TTY, "w" );
    setlinebuf( debug_fd );
#endif

    formula_initialize();

    for ( i = 0; i < MAX_MARKS; i++ )
        mark_locations[ i ] = -1;

    readonly = 0;
    file_name = argv[1];
    open_options = 0;
#ifdef O_LARGEFILE
    open_options |= O_LARGEFILE;
#endif
    file_descriptor = open( file_name, open_options | O_RDWR );
    if ( file_descriptor < 0 )
    {
        file_descriptor = open( file_name, open_options | O_RDONLY );
        if ( file_descriptor < 0 )
        {
            perror( "open" );
            return 1;
        }
        readonly = 1;
    }

    initscr();
    move( 0, 0 );
    raw();
    noecho();

    fstat( file_descriptor, &sb );

    file_size = sb.st_size;
    pos_width = get_pos_width();
    file_position = 0;
    cursor_line = 0;
    ed = ed_HEX;
    disp = disp_HEX;
    insert_mode = FALSE;
    esc_seq_state = ESC_NORMAL;

    do {

        update_screen();
        c = getch();
        handle_character( c );

    } while ( c != 'q' );

    clear();
    refresh();
    endwin();

    return 0;
}

int
get_pos_width( void )
{
    off_t v = file_size;
    int width = 0;
    while (v != 0)
    {
        width++;
        v /= 16;
    }
    return width;
}

int
get_file_byte( off_t pos )
{
    unsigned char c;
    lseek( file_descriptor, pos, SEEK_SET );
    if ( read( file_descriptor, &c, 1 ) != 1 )
        return 0;
    return c;
}

void
get_file_data( off_t pos, unsigned char *data, int len )
{
    int rlen;

    if ( pos < 0 )
    {
        lseek( file_descriptor, 0, SEEK_SET );
        /* tricky!  recall that 'pos' is negative! */
        rlen = len + pos;
        data -= pos;
    }
    else
    {
#ifdef HAVE_LSEEK64
        lseek64( file_descriptor, pos, SEEK_SET );
#else
#ifdef HAVE__LSEEK64
        _lseek64( file_descriptor, pos, SEEK_SET );
#else
#ifdef HAVE_LSEEK
        lseek( file_descriptor, pos, SEEK_SET );
#else
#error no lseek definition
#endif
#endif
#endif
        rlen = len;
    }
    if (read( file_descriptor, data, rlen ) < 0)
    { /* quiet compiler */ }
}

void
put_file_byte( off_t pos, int data )
{
    unsigned char c = data;
    lseek( file_descriptor, pos, SEEK_SET );
    if (write( file_descriptor, &c, 1 ) < 0)
    { /* quiet compiler */ }
}

void
update_screen( void )
{
    int curs_x=0, curs_y=0;

    erase();
    move( 0, 0 );

    if ( disp == disp_TEXTL )
    {
        unsigned char * buff;
        off_t buffstart;
        int buffsize, middle, * newls, i, n;

        charsperline = COLS-16;
        buffsize = charsperline * (LINES-1) * 5;
        middle = (buffsize/2);
        buffstart = file_position - middle;

        buff = (unsigned char *)malloc( buffsize );
        newls = (int*)malloc( sizeof( int ) * LINES );

        DEBUG(( debug_fd, "buffsize = %d  charsperline = %d\n",
                buffsize, charsperline ));

        for ( i = 0; i < LINES; i++ )
            newls[i] = -1;

        if ( buffstart >= 0 )
        {
            get_file_data( buffstart, buff, buffsize );
        }
        else
        {
            int unused = -buffstart;
            memset( buff, 0, unused );
            get_file_data( 0, buff+unused, buffsize - unused );
        }

        for ( n = cursor_line, i = (middle-1); n >= 0 && i >= 0; i-- )
            if ( buff[i] == 10 )
                newls[n--] = i;
            else if ( i == -buffstart )
                newls[n--] = i-1;

        DEBUG(( debug_fd, "bailing out with i %d n %d bs %d mid %d\n",
                i, n, buffstart, middle ));
        if ( i == -1 && buffstart == -middle && n >= 0 )
        {
            DEBUG(( debug_fd, "special case\n" ));
            newls[n--] = middle-1;
        }

        for ( n = (cursor_line+1), i = middle;
              n < LINES && i < buffsize; i++ )
        {
            if ( buff[i] == 10 )
                newls[n++] = i;
        }

        for ( n = 0; n < (LINES-1); n++ )
        {
            DEBUG(( debug_fd, "line %d is at offset %d\n", n, newls[n] ));

            if ( newls[n] != -1 )
            {
                int pos = newls[n] + 1;
                off_t file_pos = file_position + pos - middle;

                printw( "%*s: ", pos_width,
                        m_dump_number( file_pos, 16 ));

                for ( i = 0; i < charsperline; i++, file_pos++ )
                {
                    int c;
                    if ( file_pos >= file_size )
                        break;
                    c = buff[pos+i];
                    if (( pos + i ) == middle )
                        getyx( stdscr, curs_y, curs_x );
                    if ( c == 10 )
                        break;
                    if (isprint(c))
                        printw( "%c", c );
                    else
                        printw( "." );
                }
            }

            printw( "\n" );
        }

        free( buff );
        free( newls );
    }
    else
    {
        off_t start_file_pos, end_file_pos, pos;
        unsigned char * file_buf;
        int readlen, readpos;

        if ( disp == disp_HEX )
        {
/* 
 * 1-10 chars for the number (pos_width)
 *  3 for colon and spaces
 *  1 space after every 4 byte group
 *  1 more space after every 8 byte group
 *  3 more spaces before text
 *  2 asterisks around text
 *  2 more spaces before end of line
 *  thus there are remaining :
 *  3.375 for each byte
 *
 *    (COLS - (12 + pos_width)) / 3.375     *note that 3.375 = 27 / 8
 */
            charsperline = (COLS - (12 + pos_width)) * 8 / 27;
            charsperline &= ~3;
        }
        else if ( disp == disp_TEXTW )
            charsperline = COLS-16;

        readlen = (LINES-1) * charsperline;

        start_file_pos =
            (file_position - (file_position % charsperline)) -
            (cursor_line * charsperline);

        end_file_pos = start_file_pos + readlen;

        file_buf = (unsigned char *)malloc( readlen );

        get_file_data( start_file_pos, file_buf, readlen );

        for ( readpos = 0; readpos < readlen; readpos += charsperline )
        {
            int byte;
            pos = start_file_pos + readpos;

            if (( pos < 0 ) || ( pos >= file_size ))<commit_msg>print he debug using inttypes PRI macros<commit_after>/*
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <http://unlicense.org>
*/

#define _LARGEFILE64_SOURCE
#define __STDC_FORMAT_MACROS

#include "pfkutils_config.h"
#ifndef _GNU_SOURCE 
#define _GNU_SOURCE
#endif
#define _FILE_OFFSET_BITS 64

#include <inttypes.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>

#ifdef HAVE_NCURSES_CURSES_H
#include <ncurses/curses.h>
#else
#ifdef HAVE_NCURSES_H
#include <ncurses.h>
#else
#ifdef HAVE_CURSES_H
#include <curses.h>
#else
#error need some kind of curses.h
#endif
#endif
#endif

#include "m.h"

#ifdef __CYGWIN__
/* wtf?? apparently no prototype in system headers. */
off_t _lseek64(int filedes, off_t offset, int whence);
#endif

#ifndef MAP_FAILED
#define MAP_FAILED -1
#endif

enum mark_op { SET_MARK, GOTO_MARK };
enum pointer_type { BIG_ENDIAN_PTR, LITTLE_ENDIAN_PTR };

static int         file_descriptor;
static char *      file_name;
static off_t       file_size;
static off_t       file_position;
static int         pos_width;
static int         cursor_line;
static int         charsperline;
static int         insert_mode;
static int         readonly;

static enum { ed_HEX, ed_TEXT } ed;
static enum { disp_HEX, disp_TEXTW, disp_TEXTL } disp;
static enum { ESC_NORMAL, ESC_GOT1B, ESC_GOT5B,
              ESC_GOT35,  ESC_GOT36 } esc_seq_state;

#define MAX_MARKS 26
static off_t mark_locations[ MAX_MARKS ];

static int    get_pos_width( void );
static void   update_screen( void );
static void   handle_character( int c );
static void   do_help( void );
static void   do_help_tty( void );
static int    ishex( int c );
static int    hex_to_dig( int c );
static void   go_offset( void );
static void   do_search( void );
static void   do_mark( enum mark_op op );
static void   do_rel_move( void );
static void   formula_initialize( void );
static void   deref_pointer( enum pointer_type );
static int    get_file_byte( off_t pos );
static void   get_file_data( off_t pos, unsigned char *data, int len );
static void   put_file_byte( off_t pos, int data );

#if 0
static FILE * debug_fd = NULL;
#define DEBUG(x) if ( debug_fd != NULL ) fprintf x
#define OPEN_TTY "/dev/pts/1"
#else
#define DEBUG(x)
#endif

int
he_main( int argc, char ** argv )
{
    struct stat sb;
    int i, c;
    int open_options;

    if ( argc != 2 )
    {
        do_help_tty();
        return 1;
    }

#ifdef OPEN_TTY
    debug_fd = fopen( OPEN_TTY, "w" );
    setlinebuf( debug_fd );
#endif

    formula_initialize();

    for ( i = 0; i < MAX_MARKS; i++ )
        mark_locations[ i ] = -1;

    readonly = 0;
    file_name = argv[1];
    open_options = 0;
#ifdef O_LARGEFILE
    open_options |= O_LARGEFILE;
#endif
    file_descriptor = open( file_name, open_options | O_RDWR );
    if ( file_descriptor < 0 )
    {
        file_descriptor = open( file_name, open_options | O_RDONLY );
        if ( file_descriptor < 0 )
        {
            perror( "open" );
            return 1;
        }
        readonly = 1;
    }

    initscr();
    move( 0, 0 );
    raw();
    noecho();

    fstat( file_descriptor, &sb );

    file_size = sb.st_size;
    pos_width = get_pos_width();
    file_position = 0;
    cursor_line = 0;
    ed = ed_HEX;
    disp = disp_HEX;
    insert_mode = FALSE;
    esc_seq_state = ESC_NORMAL;

    do {

        update_screen();
        c = getch();
        DEBUG((debug_fd, "got key %d\n", c));
        handle_character( c );

    } while ( c != 'q' );

    clear();
    refresh();
    endwin();

    return 0;
}

int
get_pos_width( void )
{
    off_t v = file_size;
    int width = 0;
    while (v != 0)
    {
        width++;
        v /= 16;
    }
    return width;
}

int
get_file_byte( off_t pos )
{
    unsigned char c;
    lseek( file_descriptor, pos, SEEK_SET );
    if ( read( file_descriptor, &c, 1 ) != 1 )
        return 0;
    return c;
}

void
get_file_data( off_t pos, unsigned char *data, int len )
{
    int rlen;

    if ( pos < 0 )
    {
        lseek( file_descriptor, 0, SEEK_SET );
        /* tricky!  recall that 'pos' is negative! */
        rlen = len + pos;
        data -= pos;
    }
    else
    {
#ifdef HAVE_LSEEK64
        lseek64( file_descriptor, pos, SEEK_SET );
#else
#ifdef HAVE__LSEEK64
        _lseek64( file_descriptor, pos, SEEK_SET );
#else
#ifdef HAVE_LSEEK
        lseek( file_descriptor, pos, SEEK_SET );
#else
#error no lseek definition
#endif
#endif
#endif
        rlen = len;
    }
    if (read( file_descriptor, data, rlen ) < 0)
    { /* quiet compiler */ }
}

void
put_file_byte( off_t pos, int data )
{
    unsigned char c = data;
    lseek( file_descriptor, pos, SEEK_SET );
    if (write( file_descriptor, &c, 1 ) < 0)
    { /* quiet compiler */ }
}

void
update_screen( void )
{
    int curs_x=0, curs_y=0;

    erase();
    move( 0, 0 );

    if ( disp == disp_TEXTL )
    {
        unsigned char * buff;
        off_t buffstart;
        int buffsize, middle, * newls, i, n;

        charsperline = COLS-16;
        buffsize = charsperline * (LINES-1) * 5;
        middle = (buffsize/2);
        buffstart = file_position - middle;

        buff = (unsigned char *)malloc( buffsize );
        newls = (int*)malloc( sizeof( int ) * LINES );

        DEBUG(( debug_fd, "buffsize = %d  charsperline = %d\n",
                buffsize, charsperline ));

        for ( i = 0; i < LINES; i++ )
            newls[i] = -1;

        if ( buffstart >= 0 )
        {
            get_file_data( buffstart, buff, buffsize );
        }
        else
        {
            int unused = -buffstart;
            memset( buff, 0, unused );
            get_file_data( 0, buff+unused, buffsize - unused );
        }

        for ( n = cursor_line, i = (middle-1); n >= 0 && i >= 0; i-- )
            if ( buff[i] == 10 )
                newls[n--] = i;
            else if ( i == -buffstart )
                newls[n--] = i-1;

        DEBUG(( debug_fd, "bailing out with i %d n %d "
                "bs %" PRIu64 " mid %d\n",
                i, n, buffstart, middle ));
        if ( i == -1 && buffstart == -middle && n >= 0 )
        {
            DEBUG(( debug_fd, "special case\n" ));
            newls[n--] = middle-1;
        }

        for ( n = (cursor_line+1), i = middle;
              n < LINES && i < buffsize; i++ )
        {
            if ( buff[i] == 10 )
                newls[n++] = i;
        }

        for ( n = 0; n < (LINES-1); n++ )
        {
            DEBUG(( debug_fd, "line %d is at offset %d\n", n, newls[n] ));

            if ( newls[n] != -1 )
            {
                int pos = newls[n] + 1;
                off_t file_pos = file_position + pos - middle;

                printw( "%*s: ", pos_width,
                        m_dump_number( file_pos, 16 ));

                for ( i = 0; i < charsperline; i++, file_pos++ )
                {
                    int c;
                    if ( file_pos >= file_size )
                        break;
                    c = buff[pos+i];
                    if (( pos + i ) == middle )
                        getyx( stdscr, curs_y, curs_x );
                    if ( c == 10 )
                        break;
                    if (isprint(c))
                        printw( "%c", c );
                    else
                        printw( "." );
                }
            }

            printw( "\n" );
        }

        free( buff );
        free( newls );
    }
    else
    {
        off_t start_file_pos, pos;
        unsigned char * file_buf;
        int readlen, readpos;

        if ( disp == disp_HEX )
        {
/* 
 * 1-10 chars for the number (pos_width)
 *  3 for colon and spaces
 *  1 space after every 4 byte group
 *  1 more space after every 8 byte group
 *  3 more spaces before text
 *  2 asterisks around text
 *  2 more spaces before end of line
 *  thus there are remaining :
 *  3.375 for each byte
 *
 *    (COLS - (12 + pos_width)) / 3.375     *note that 3.375 = 27 / 8
 */
            charsperline = (COLS - (12 + pos_width)) * 8 / 27;
            charsperline &= ~3;
        }
        else if ( disp == disp_TEXTW )
            charsperline = COLS-16;

        readlen = (LINES-1) * charsperline;

        start_file_pos =
            (file_position - (file_position % charsperline)) -
            (cursor_line * charsperline);

        file_buf = (unsigned char *)malloc( readlen );

        get_file_data( start_file_pos, file_buf, readlen );

        for ( readpos = 0; readpos < readlen; readpos += charsperline )
        {
            int byte;
            pos = start_file_pos + readpos;

            if (( pos < 0 ) || ( pos >= file_size ))
{'fraction_non_alphanumeric': 0.1074455205811138, 'fraction_numerical': 0.0129136400322841, 'mean_word_length': 2.040644171779141, 'pattern_counts': {'":': 0, '<': 62, '<?xml version=': 0, '>': 48, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1582335', 'n_tokens_mistral': 6915, 'n_tokens_neox': 6473, 'n_words': 2069}