/* fv is a binary file editor written by Chris Hooper (cdh@mtu.edu)
 *	on 6-2-91 and has gone through many revisions since then.
 *      Much inspiration was given by Bill Moore, the first real user!
 *
 *   Author:  CHRISTOPHER D HOOPER
 *
 *   fv source Copyright (c) 1992 - 1998  Chris Hooper
 *
 *   Modification and redistribution is strictly prohibited.
 *   Sale of this software above media cost is prohibited.
 *
 *   Except for above two restrictions, this software may be used for
 *       any purpose, commercial or private.
 *
 *   Disclaimer:  This product is fit for no use, foreign or domestic.
 *                Use implies knowledge you intend to destroy something.
 */

#include <stdio.h>
#include <curses.h>
#include "main.h"
#if !defined(Amiga) && !defined(OS9) && !defined(FreeBSD)
#	include <malloc.h>
#endif
#include "screen.h"
#include "pcurses.h"

#ifdef LINT
#	include "lint.h"
#endif

char *strdup();

char *help_main = "\
              Main Display Keyboard Mappings (brief)			\n\
-------------------------------------------------------------------	\n\
         0G()   = Start/End/Top/Bottom					\n\
         hjkl   = Scrolling, HJKL moves buffer view			\n\
         {Enter}= Edit string or hex					\n\
         {Tab}  = Toggle string/hex edit mode				\n\
         wq^X   = Finished editing 					\n\
         m'     = Set/Go to mark						\n\
         twc    = Toggle hex/dec,word,character modes			\n\
         a+-    = Toggle address mode,change columns			\n\
         /?nN   = Search forward/backward/next				\n\
         g      = Go to (jump) to hex address				\n\
         []{}   = Location/Range display address divisor		\n\
         AC     = Append/Create file from cursor to mark		\n\
         udfb   = Half Up/Down, Full Forward/Back page			\n\
         t<>    = Type (hex,dec,flt,dbl) Alignment up/down		\n\
									\n\
									\n\
===================================================================	\n\
									\n\
									\n\
             Main Display Keyboard Mappings (detailed)			\n\
-------------------------------------------------------------------	\n\
0-9      Enter number of times to perform command			\n\
a        Address display on/off						\n\
A        Append from current cursor position until mark to file		\n\
b        Back one full display page					\n\
^B       Back one full display page					\n\
c        Character display on/off					\n\
C        Copy from current cursor position until mark to file		\n\
^C       Exit (do not ask to save)					\n\
d        Down one half display page					\n\
^D       Down one half display page					\n\
f        Forward one full display page					\n\
F        Select new file from list given on command line		\n\
^F       Forward one full display page					\n\
g        Go to specific byte position (hex) in file			\n\
G        Go to bottom of file						\n\
^G       Show current filename and cursor position in file		\n\
h        Cursor left							\n\
H        Buffer window left (fix cursor at file position)		\n\
^H       Provide Help screen, ? is Help Screen in other modes		\n\
^I       {tab}  Change word search mode (string or hex/dec)		\n\
j        Cursor down							\n\
J        Buffer window down (fix cursor at file position)		\n\
^J       Edit at word (same as Return, either String or Hex)		\n\
k        Cursor up							\n\
K        Buffer window up (fix cursor at file position)			\n\
l        Cursor right							\n\
L        Buffer window right (fix cursor at file position)		\n\
^L       Redraw screen							\n\
m        Set mark at current file position (type mark character)	\n\
M        Move cursor to middle of screen				\n\
^M       Edit at word (same as Return, either String or Hex)		\n\
n        Search for next occurrence in current direction		\n\
N        Reverse direction of search and look again			\n\
o        Change character that shows for non-ASCII			\n\
O        Change character that shows for zero				\n\
q        Exit (ask to save if modified)					\n\
Q        Exit (do not ask to save)					\n\
r        Reread buffer and redisplay					\n\
R        Change Read-only mode						\n\
s        Change byte swapping mode (off, word, long)			\n\
S        Toggle byte swapping cursor motion relative to chars/words	\n\
t        Toggle word display type (hex, decimal)			\n\
T        Cycle word display type (hex, decimal, float, or double)	\n\
u        Up one half display page					\n\
^U       Up one half display page					\n\
w        Toggle word display on/off					\n\
W        Write current buffer contents to file				\n\
^W       Write current buffer contents to file				\n\
x        Exit (ask to save if modified)					\n\
^X       Exit (ask to save if modified)					\n\
z        Set current line of display at top \"z<CR>\"; middle \"z.\"; 	\n\
         bottom \"z-\"; or force bottom to top \"z+\" of display	\n\
0        Beginning page of file / location zero of file			\n\
/        Search forward for String or Hex (depending on '^I' mode)	\n\
?        Search backward for String or Hex (depending on '^I' mode)	\n\
         ? is used in other modes to provide help			\n\
^        Go to beginning of current display row				\n\
$        Go to end of current display row				\n\
+        Add more display columns (up to screen size)			\n\
=        Add more display columns (up to screen size)			\n\
-        Subtract display columns (down to a single word column)	\n\
_        Subtract display columns (down to a single word column)	\n\
'        Go to mark (type mark character)				\n\
`        Go to mark (type mark character)				\n\
(        Go to top / left of screen					\n\
)        Go to bottom / right of screen					\n\
<        Increase cursor alignment (1, 2, 4, 8 bytes)			\n\
>        Decrease cursor alignment (8, 4, 2, 1 bytes)			\n\
[        Double lower status address display divisor / modulus		\n\
]        Halve lower status address display divisor / modulus		\n\
{        Double left address display divisor / modulus ('a' mode)	\n\
}        Halve left address display divisor / modulus ('a' mode)	\n\
\"        Toggle status range address modify between div and mod	\n\
~        Toggle left address modify between divisor & modulator		\n\
.        Go to string edit mode and repeat last session commands	\n\
:        Enter colon mode command                                       \n\
";


char *help_hex = "\
                Hex Edit Mode			\n\
---------------------------------------------	\n\
^B	Move cursor left			\n\
^F	Move cursor right			\n\
h	Move cursor left			\n\
j	Move cursor down			\n\
k	Move cursor up				\n\
l	Move cursor right			\n\
<CR>	Store word in file (same as ^M)		\n\
q	Quit editing the string, do not store	\n\
^X	Quit editing the string, do not store	\n\
<Del>	Move cursor left			\n\
0-9	Enter Hex digit 0-9			\n\
a-f	Enter Hex digit a-f			\n\
^	Jump to start of line			\n\
?	Display this help			\n\
";


char *help_string = "\
                     String Edit Mode				\n\
-------------------------------------------------------------	\n\
                         ESC Mode:				\n\
a    Add after cursor position, enter insert mode		\n\
A    Add at end of string, enter insert mode			\n\
b    Go to previous word					\n\
c    f   Delete including character, insert mode		\n\
c    t   Delete to character, put in insert mode		\n\
c    w   Delete word, put in insert mode			\n\
c    ^   Delete to beginning of string, put in insert mode	\n\
c    0   Delete to beginning of string, put in insert mode	\n\
c    $   Delete to end of string, put in insert mode		\n\
C    Change to end of string					\n\
d    f   Delete including character				\n\
d    t   Delete to character					\n\
d    w   Delete word						\n\
d    ^   Delete to beginning of string				\n\
d    0   Delete to beginning of string				\n\
d    $   Delete to end of string				\n\
D    Delete to end of string					\n\
e    Go to end of this word or next				\n\
f    Go to next character typed					\n\
G    Go to end of string					\n\
h    Cursor left (same as backspace key)			\n\
^H   Cursor left (same as backspace key)			\n\
i    Insert at cursor position, enter insert mode		\n\
I    Insert at beginning of string, enter insert mode		\n\
j    Cursor down						\n\
k    Cursor up							\n\
l    Cursor right						\n\
q    Quit editing the string, do not store			\n\
r    Replace single character					\n\
R    Replace multiple characters (overstrike)			\n\
s    Substitute for single character				\n\
t    Go to character before next typed character		\n\
T    Go to character before next typed character		\n\
u    Undo last change						\n\
U    Undo all changes to string					\n\
w    Go to next word						\n\
x    Erase single character					\n\
0    Go to beginning of string					\n\
$    Go to end of string					\n\
~    Switch case of current alphabetic character		\n\
.    Repeat last edit command					\n\
^    Go to beginning of string					\n\
^M   Finished editing (same as return)				\n\
^X   Quit editing the string, do not store			\n\
?    Display this help information				\n\
ESC  Enter ESC command mode					\n\
								\n\
                     Insert Mode only:				\n\
^H	Delete left of cursor (same as backspace key)		\n\
^V	Add next raw character to string			\n\
";


char *help_prompt = "\
        File name prompt editor			\n\
----------------------------------------	\n\
a    = Add after current cursor position	\n\
A    = Add at end of name			\n\
c    = Change w=word t=to (character)		\n\
d    = Delete w=word t=to (character)		\n\
h    = Cursor Left				\n\
i    = Insert at current cursor position	\n\
I    = Insert at beginning of name 		\n\
j    = Cursor Right				\n\
k    = Cursor Left				\n\
l    = Cursor Right				\n\
r    = Replace single character			\n\
s    = Substitute for single character		\n\
0    = Go to beginning of name			\n\
^    = Go to beginning of name			\n\
$    = Go to end of name			\n\
u    = Undo last edit				\n\
U    = Undo all edits to name			\n\
^H   = Delete left of cursor			\n\
^U   = Erase line				\n\
^V   = Next character is raw			\n\
ESC  = Escape (command mode) from insert	\n\
";


char *help_select = "\
       Select file help			\n\
-------------------------------		\n\
b     = Move cursor left		\n\
f     = Move cursor right		\n\
h     = Move cursor left		\n\
l     = Move cursor right		\n\
q     = Quit without selecting		\n\
<CR>  = Select new file to edit		\n\
$     = Go to last file			\n\
0     = Go to first file		\n\
^     = Go to first file		\n\
%     = Go to current file		\n\
<Tab> = Go to next file (wraps)		\n\
?     = Display this help		\n\
^L    = Refresh (redraw) screen		\n\
";

#ifdef COLON_MODE
char *help_colon = "\
             Colon prompt help 			\n\
------------------------------------------	\n\
    :e  = Edit new filename(s)			\n\
    :h  = This help information			\n\
    :n  = Go to next file			\n\
    :p  = Go to previous file			\n\
    :q  = Quit fv				\n\
    :q! = Quit fv without saving		\n\
    :r  = Go to first file			\n\
    :w  = Write current buffer			\n\
    :wq = Write current buffer and exit		\n\
    :x  = Exit and write if needed		\n\
						\n\
Press ^H in main editor for keystroke help	\n\
";
#endif

char *help_oops = "\
FV has detected an internal error, #            \n\
						\n\
Please report this to the author, including	\n\
a brief description of what you were attempting	\n\
to do and which mode the editor was in.		\n\
";

WINDOW *help_window = NULL;
void help_me_text();


void help_me(which)
int which;
{
	if (noscreen)
		return;

	switch (which) {
	    case 0:		/* main */
		help_me_text(help_main);
		break;
	    case 1:		/* hex editor */
		help_me_text(help_hex);
		break;
	    case 2:		/* string editor */
		help_me_text(help_string);
		break;
	    case 3:		/* prompt string */
		help_me_text(help_prompt);
		break;
	    case 4:		/* file selector */
		help_me_text(help_select);
		break;
#ifdef COLON_MODE
	    case 5:		/* colon mode */
		help_me_text(help_colon);
		break;
#endif
	    default:
		{
		char *buf;
		buf = strdup(help_oops);
		sprintf(buf + 36, "%d.", which);
		/* get rid of sprintf's '\0' */
		buf[strlen(buf)] = ' ';
		help_me_text(buf);
		free(buf);
		break;
		}
	}
}

void help_me_text(str)
char *str;
{
	int row;
	int col;
	int rows = 0;
	int cols = 0;
	int ccols = 1;
	int scols = 0;
	int srows = 0;
	int index;
	int temp;
	int SCOLS;
	int SLINES;
	int ch;
	char *ptr;
	WINDOW *help_window;

	for (ptr = str; *ptr != '\0'; ptr++) {
	    ch = *ptr;
	    switch (ch) {
		case '\n':
		    rows++;
		    if (ccols > cols)
			cols = ccols;
		    ccols = 0;
		    scols = 0;
		    break;
		case '\t':
		    scols += 8 - ((ccols + scols) & 7);
		    break;
		case ' ':
		    scols++;
		    break;
		default:
		    ccols += scols + 1;
		    scols = 0;
	    }
	}

	recalc_screen:
	SCOLS = COLS;
	SLINES = LINES;
	if (rows > SLINES - 6)
	    srows = SLINES - 6;
	else
	    srows = rows;

	if (cols > SCOLS - 6)
	    scols = SCOLS - 6;
	else
	    scols = cols;

	help_window = xnewwin(srows + 2, scols + 2,
                              (SLINES - srows - 2) / 2, (SCOLS - scols - 2) / 2);
#ifdef STAT_COLOR
	wattron(help_window, STAT_COLOR);
#endif
	box(help_window, '|', '-');
#ifdef CRSR_COLOR
	wattron(help_window, CRSR_COLOR);
	leaveok(help_window, TRUE);
#else
	leaveok(help_window, FALSE);
#endif

	col = 0;
	row = 0;
	do {
		/* move to start row in string */
		for (ptr = str, index = 0; index < row; index++) {
		    for (; (ch = *ptr) != '\n'; ptr++)
			if (ch == '\0')
			    break;
		    ptr++;
		}

		/* display up to srows rows from here */
		for (index = 0; index < srows; index++) {
		    xmove(help_window, index + 1, 1);
		    for (temp = 0; (ch = *ptr) != '\n'; ptr++) {
			if ((ch == '\0') || (temp >= col))
			    break;
			else if (ch == '\t')
			    temp += 8 - (temp & 7);
			else
			    temp++;
			if (temp > col)
			    break;
		    }
		    ccols = 0;
		    for (; (ch = *ptr) != '\n'; ptr++) {
			if (ch == '\0')
			    break;
			if (ch == '\t') {
			    temp = 8 - ((ccols + col) & 7);
			    while (temp--)
				if (ccols++ < scols)
				    xaddch(help_window, ' ');
			} else {
			    if (ccols++ < scols)
				xaddch(help_window, ch);
			}
		    }
		    for (; ccols < scols; ccols++)
			xaddch(help_window, ' ');
		    ptr++;
		}
		xmove(help_window, srows + 1, scols + 1);
		xrefresh(help_window);
		ch = get_key();
		if ((COLS != SCOLS) || (LINES != SLINES)) {
			unget_key(ch);
			delwin(help_window);
			touchwin(main_window);
			xrefresh(main_window);
			goto recalc_screen;
		}

		switch (ch) {
#ifndef EMACS_FEEL
		    case 2:	/* ^B */
#endif
		    case 'b':
			row -= srows;
			if (row < 0)
			    row = 0;
			break;
		    case 4:	/* ^D */
			row += srows / 2;
			if (row > rows - srows)
			    row = rows - srows;
			break;
		    case ' ':
			if (row == rows - srows)
			    ch = 13;
#ifndef EMACS_FEEL
		    case 6:	/* ^F */
#endif
		    case 'f':
			row += srows;
			if (row > rows - srows)
			    row = rows - srows;
			break;
		    case 'h':
		    case 'H':
#ifdef EMACS_FEEL
		    case 2:	/* ^B */
#endif
#ifdef KEY_LEFT
		    case KEY_LEFT:
#endif
			if (col > 0)
			    col--;
			break;
		    case 'j':
		    case 'J':
		    case 14:	/* ^N */
#ifdef KEY_DOWN
		    case KEY_DOWN:
#endif
			if (row < rows - srows)
			    row++;
			break;
		    case 'k':
		    case 'K':
		    case 16:	/* ^P */
#ifdef KEY_UP
		    case KEY_UP:
#endif
			if (row > 0)
			    row--;
			break;
		    case 12:	/* ^L */
			xclear(stdscr);
			xmove(stdscr, 0, 0);
			xclrtobot(stdscr);
			xtouchwin(main_window);
			xtouchwin(status_window);
			xtouchwin(help_window);
			xrefresh(stdscr);
			xrefresh(main_window);
			xrefresh(status_window);
			xrefresh(help_window);
			break;
		    case 'l':
		    case 'L':
#ifdef EMACS_FEEL
		    case 6:	/* ^F */
#endif
#ifdef KEY_RIGHT
		    case KEY_RIGHT:
#endif
			if (col < cols - scols)
			    col++;
			break;
		    case 'G':
			row = rows - srows;
			if (row < 0)
			    row = 0;
			break;
		    case 21:	/* ^U */
			row -= srows / 2;
			if (row < 0)
			    row = 0;
			break;
		    case 24:	/* ^X */
		    case 13:	/* ^M */
		    case 10:	/* ^R */
		    case 27:	/* ESC */
		    case 'q':
		    case 'x':
			ch = 13;
			break;
		    case '0':
			row = 0;
			break;
		}
	} while (ch != 13);	/* ^M */

	delwin(help_window);
}
