/*
**++
**  FACILITY:
**      NEWSHELP
**
**  ABSTRACT:
**      This module displays the NEWS help library on the screen using
**      SMG as the presentation manager
**
**  AUTHOR:
**      Geoff Huston
**
**  COPYRIGHT:
**      Copyright © 1988,1989,1990
**
**  Modification History:
**	V6.1b8  24-Jan-1994     Mark Martinec  mark.martinec@ijs.si
**	  - replace calls to smg$put_chars with calls to smg_put_chars 
**	  - check status returned from all calls to SMG$
**	V6.1b9	17-Aug-1994     Mark Martinec   mark.martinec@ijs.si
**	  - code cleanup to make it compile under gcc 2.6.0 with full
**	    warnings reporting turned on - with no or very few harmless warnings
**	V6.1b9	17-Sep-1994     Mark Martinec   mark.martinec@ijs.si
**	  - code cleanup to preserve the read-only nature of string literals
**	    (strategically placed 'const' attribute to string parameters)
**	V6.1b11 14-Apr-1997  Mark Martinec   mark.martinec@ijs.si
**	  - replace several calls to strcpy/strcat with safer strnncpy/strnncat
**--
**/

#ifdef vaxc
#module NEWSHELP "V6.2"
#endif

#define _NEWSHELP_C
#define module_name "NEWSHELP"

#include "newsinclude.h"
#include "newsextern.h"

#if NAKED_INCLUDES
#include hlpdef
#else
#include <hlpdef.h>
#endif

#define HELP_DISP_SIZE 500

static
int vd_created = 0,
    help_top_paste = 3,
    help_bot_paste = 4 - HELP_DISP_SIZE,
    help_cur_paste,
    start_itm,
    help_lines,
    disp_top,
    disp_bot,
    hhid,
    htid;

extern int lbr$output_help();

/*
 *  hlp_output
 *
 *  Place a line on the display - if this causes scrolling, move the display
 *  so as to maintain the item start line at the top of the display window
 */

static int hlp_output(out_str)
  struct dsc$descriptor_const_s *out_str;
{
  int status;
  int cols;

  _c$cks(smg$put_with_scroll(&htid,out_str,0,0,0,0,0));
  _c$cks(smg$return_cursor_pos(&htid,&help_lines,&cols));
  if (help_lines >= HELP_DISP_SIZE) {
    if (start_itm) {
      --start_itm;
      if (help_cur_paste < 3) {
        --disp_top;
        --disp_bot;
        ++help_cur_paste;
        _c$cks(smg$move_virtual_display(&htid,&pid,&help_cur_paste,c$ac(1),0));
        }
      }
    }
  return(1);
}

/*
 *  hlp_input
 *
 *  Get the text corresponding to the help prompt. Allow the screen to
 *  be scrolled using the screen movement keys
 */

static int hlp_input(get_str,prompt_str,out_len)
  struct dsc$descriptor_s *get_str;
  struct dsc$descriptor_const_s *prompt_str;
  unsigned short *out_len;
{
  int screen_size = (devrow - 5),
      status, c,
      n,j,
      act,
      repeat;
  char mprompt[80],
       get_line[80],
       resp[132];
  int resp_l, cmd_l;
  unsigned short trm;
  $DESCRIPTOR_CONST(mpr,mprompt);
  $DESCRIPTOR(get,get_line);

  for (;;) {
    act = 0;
    brdcst_col = 7;
    display_brdcst(3);
    brdcst_line = 3;
    if (help_lines > disp_bot) {
      strcpy(mprompt,"<RETURN for more>");
      smg_put_chars(trailer_vd,mprompt,2,1,1,SMG$M_REVERSE);
      }
    else _c$cks(smg$erase_line(&trailer_vd,c$ac(2),c$ac(1)));

 /* nasty LBR$OUTPUT_HELP puts nonprintable characters in the prompt (CR,LF) */
    mpr.dsc$w_length = 0;
    for (j = 0; j < sizeof mprompt && j < prompt_str->dsc$w_length; j++) {
      c = (unsigned char) prompt_str->dsc$a_pointer[j];
      if ((c >= ' ' && c < 127) || (c >= 161 && c < 255))
        mprompt[mpr.dsc$w_length++] = c;         /* printable characters only */
      }
    status = get_input_general(&get,&mpr,out_len,0,&trm,1,line_editing);
    if (((status == SS$_ABORT) || (status == SS$_CANCEL)) && news_lock_alarm) {
      closefiles();
      exit(1);
      }
    brdcst_line = 0;
    clear_err_line();
    if (status == SMG$_EOF) status = RMS$_EOF;
    if (status == RMS$_EOF) return(status);
    get_line[*out_len] = '\0';
    strnncpy(cmd,cmd_m, get_line,*out_len, &cmd_l);
    strncpy(get_str->dsc$a_pointer,get_line,*out_len);
    if ((help_lines > disp_bot) && !*out_len) trm = SMG$K_TRM_NEXT_SCREEN;
    if (  (!strcmp(get_line," "))
             ||(trm == SMG$K_TRM_NEXT_SCREEN) || (trm == SMG$K_TRM_DOWN)) {
      if (!strcmp(get_line," ")) n = screen_size;
      else {
        if (!*cmd) repeat = 1;
        else if (!sscanf(cmd,"%d",&repeat)) repeat = 1;
        if (!strcmp(cmd,"BOTTOM")) repeat = 1000;
        if (trm == SMG$K_TRM_DOWN) n = repeat;
        else n = screen_size * repeat;
        }
      if (n < (screen_size + 2)) {
        _c$cks(smg$end_pasteboard_update(&pid));
        act = 1;
        }
      for (; n; n--) {
        if ((help_cur_paste == help_bot_paste)||(help_lines <= disp_bot)) break;
        --help_cur_paste;
        ++disp_top;
        ++disp_bot;
        _c$cks(smg$move_virtual_display(&htid,&pid,&help_cur_paste,c$ac(1),0));
        }
      if (act) _c$cks(smg$begin_pasteboard_update(&pid));
      act = 0;
      }
    else if ((trm == SMG$K_TRM_PREV_SCREEN) || (trm == SMG$K_TRM_UP)) {
      if (!sscanf(cmd,"%d",&repeat)) repeat = 1;
      if (!strcmp(cmd,"TOP")) repeat = 1000;
      if (trm == SMG$K_TRM_UP) n = repeat;
      else n = screen_size * repeat;
      if (n < (screen_size + 2)) {
        _c$cks(smg$end_pasteboard_update(&pid));
        act = 1;
        }
      for (; n; n--) {
        if (help_cur_paste == help_top_paste) {
          smg_put_chars(trailer_vd,"<Top of Display>",3,1,1,SMG$M_REVERSE);
          break;
          }
        --disp_top;
        --disp_bot;
        ++help_cur_paste;
        _c$cks(smg$move_virtual_display(&htid,&pid,&help_cur_paste,c$ac(1),0));
        }
      if (act) _c$cks(smg$begin_pasteboard_update(&pid));
      act = 0;
      }
    else if (!*out_len) {
      _c$cks(smg$erase_line(&trailer_vd,c$ac(1),c$ac(1)));
      return(status);
      }
    else {
      start_itm = help_lines;
      help_cur_paste = help_top_paste - start_itm;
      disp_top = start_itm;
      disp_bot = start_itm + devrow - 6;
      _c$cks(smg$move_virtual_display(&htid,&pid,&help_cur_paste,c$ac(1),0));
      strnncpy(resp,sizeof(resp),
               prompt_str->dsc$a_pointer,prompt_str->dsc$w_length, &resp_l);
      strnncat(resp,sizeof(resp),resp_l, " ",1,  &resp_l);
      strnncat(resp,sizeof(resp),resp_l, cmd,cmd_l, &resp_l);
      hlp_output(c$dsc(resp));
      _c$cks(smg$erase_line(&trailer_vd,c$ac(1),c$ac(1)));
      return(status);
      }
    }
  news_assert_nonfatal(0); return(0);
}

/*
 *  do_help
 *
 *  Enter the help utility to interactively display all help on a module.
 */

static char help_filename[256] = {""};
static int nohelplib = 0;

static int hlp_last_resort(void)
{	/* look for NEWS.HLB in the same directory as current image */
  int status;
  char image_filename[255+1];
  $DESCRIPTOR(img_filnam_dsc,image_filename);
  long item = JPI$_IMAGNAME;
  unsigned short len = 0;

  if (lib$getjpi(&item,0,0,(long *)0,&img_filnam_dsc,&len) & 1) {
	struct FAB f = cc$rms_fab;
	struct NAM n = cc$rms_nam;
	f.fab$l_nam = &n;
	f.fab$b_fns = strlen( f.fab$l_fna = (char *) "NEWS.HLB;0" ); /* _target_ */
	f.fab$b_dns = len; f.fab$l_dna = image_filename;	/* defaults */
	n.nam$b_rss = min(sizeof help_filename - 1,0x00FF);
	n.nam$l_rsa = help_filename;
	if (sys$open(&f) & 1) {
	  sys_close(&f);
	  help_filename[n.nam$b_rsl] = '\0';
	  return 1;
	}
    }
  return 0;
}

int call_help(hlpline)
  const char *hlpline;
{
  int status;
  int line_len = devcol;

  if (!*help_filename) {
    strcpy(help_filename,"NEWS_HELPLIB");
    if (access(help_filename,0)) {
      strnncpy(help_filename,sizeof(help_filename), HELP_FILE,-1, 0);
      if (access(help_filename,0)) {
        strcpy(help_filename,"SYS$HELP:NEWS.HLB");
	if (access(help_filename,0) && !hlp_last_resort()) {
          nohelplib = 1;
	  err_line("NOHELP - Cannot locate NEWS Help library file");
	  return(0);
          }
	}
      }
    }
   
  if (!hlpline || !*hlpline) hlpline = "";

  if (smg_active) {
    if (!vd_created++) {
      _c$cks(smg$create_virtual_display(c$rfi(HELP_DISP_SIZE + devrow),&devcol,&htid,0,0,0));
      _c$cks(smg$set_display_scroll_region(&htid,c$ac(1),c$ac(HELP_DISP_SIZE)));
      _c$cks(smg$create_virtual_display(c$ac(2),c$ac(devcol),&hhid,0,0,0));
      }
    _c$cks(smg$erase_display(&htid));
    _c$cks(smg$erase_display(&hhid));
    smg_put_chars(hhid,"NEWS Help DISPLAY",1,1,0,SMG$M_BOLD);
    _c$cks(smg$paste_virtual_display(&htid,&pid,c$ac(3),c$ac(1)));
    _c$cks(smg$paste_virtual_display(&hhid,&pid,c$ac(1),c$ac(1)));
    _c$cks(smg$repaste_virtual_display(&trailer_vd,&pid,c$rfi(devrow - 2),c$ac(1)));
    start_itm = 1;
    help_cur_paste = 3;
    disp_top = 1;
    disp_bot = devrow - 5;
    help_lines = 0;
    lbr$output_help(hlp_output,&line_len,c$dsc(hlpline),c$dsc(help_filename), 
      c$ac(HLP$M_PROMPT), hlp_input);
    _c$cks(smg$erase_line(&trailer_vd,c$ac(1),c$ac(1)));
    _c$cks(smg$unpaste_virtual_display(&hhid,&pid));
    _c$cks(smg$unpaste_virtual_display(&htid,&pid));
    }
  else lbr$output_help(lib$put_output, &line_len,
			c$dsc(hlpline), c$dsc(help_filename),
			c$ac(HLP$M_PROMPT), lib$get_input);
  return(0);
}

int do_help(void)
{
  char rol[132],
       hlpline[132];
  unsigned short rol_len;
  $DESCRIPTOR(rol_dsc,rol);

  if (nohelplib) {
    err_line("NOHELP - Cannot locate NEWS Help library file");
    return(0);
    }
  strcpy(hlpline,"");
  if (cli$get_value(c$dsc("TOPIC"),&rol_dsc,&rol_len) & 1) {
    rol[rol_len] = '\0';
    strnncpy(hlpline,sizeof(hlpline), rol,rol_len, 0);
    }
  call_help(hlpline);
  return(0);
}
