/*
	Date: Wed, 25 Oct 89 21:37:46 EDT
	From: Tom Allebrandi <ta2%acci.com@murtoa.cs.mu.oz>
	To: gih900@csc0.anu.oz
	Subject: Callable editor

	Geoff -

	Following is my routine to invoke text editors similar to the way
	that mail does it. "Similar" because I derived the behavior from
	trail and example - my fiche listings for VMS are *** real *** old.
	(VMS 4.2) However, I think it's right.

	Enjoy, give a shout if you have any problems.

	--- Tom
	Tom Allebrandi  | Advanced Computer Consulting,Inc     Charlottesville, VA
	804 977 4272    | VMS User's Network Working Group -- The DECUS UUCP people
	Bix: ta2        | Internet: ta2@acci.com | Bitnet: ta2%esther@virginia.edu
	                | UUCP: ta2@esther.uucp    (...!uunet!virginia!esther!ta2)

**	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.1b10 17-Aug-1995	Mark Martinec   mark.martinec@ijs.si
**	  - removed '#include <nam.h>' since it is already included
**	    from  newsinclude.h --> rms.h
**	V6.1b11 14-Apr-1997	Mark Martinec   mark.martinec@ijs.si
**	  - replace several calls to strcpy/strcat with safer strnncpy/strnncat
*/

/*
 * invoke_editor.c
 *
 * invoke_editor(cmd_opt,Edit_Cmd,infileP,outfileP)
 *	int cmd_opt;
 *	char *Edit_Cmd;
 *	char *infileP;
 *	char *outfileP;	(or command string)
 *
 * VAX/VMS routine to invoke a text editor on the file named by outfileP, with
 * possible input from infileP. The attempt here is to invoke the editor
 * the same way that VMS MAIL, VMS NOTES, and others do.
 *
 * The Edit_Cmd string is checked. If its translation is of the form
 * CALLABLE_XXX, then SYS$SHARE:XXXSHR.EXE is invoked at the XXX$EDIT
 * entry point. If the Edit_Cmd string is not of that form, then a subprocess
 * is spawned. The subprocess receives a command of
 *
 *	Edit_Cmd infile outfile
 *
 * If you wish to invoke a command procedure ensure that there is a leading
 * "@" character in Edit_cmd
 *
 *****************************************************************************
 *
 * THIS SOFTWARE IS IN THE PUBLIC DOMAIN. However, it was developed
 * using the resources of Advanced Computer Consulting, Inc. ACCI
 * would really appreciate it if this acknowledgment were left intact!
 *
 *****************************************************************************
 *
 * History
 *	10-Jan-1989	TA2	Initial coding
 *	25-Oct-1989	TA2	Cleanup prior to public domain release.
 *      27-Mar-1990	GH	Adaption of the code for NEWS.
 *	12-Nov-1990	RQ	<reggers@uwovax.uwo.ca>
 *				Leading '@' no longer added automatically
 *				in subprocess command processing
 *	31-Oct-1991	PR	rankin@eql.caltech.edu
 *				Try harder to catch TPU signals;
 *				note:  it appears that if TPU runs out of
 *				memory (ie, exhausts PGFLQUO), it will not
 *				release any that it's used before signalling
 *				the problem, so we probably won't be able
 *				to recover...
 *	 3-Feb-1992	PR	rankin@eql.caltech.edu
 *				gcc modifications, and lint cleanup
 *	25-Feb-1992	PR	rankin@eql.caltech.edu
 *				changed to handle tpu$tpu as well as foo$edit
 *  6.1a4
 *	27-Apr-1992	PR	rankin@eql.caltech.edu
 *				fix problem with using EDT introduced by
 *				previous change
 *  6.1b9
 *	 8-Sep-1994	MM	gcc cleanup
 *
 * Author
 *	Tom Allebrandi	(TA2)
 *	Advanced Computer Consulting, Inc
 *	Charlottesville, VA, USA
 *	ta2@acci.com
 *	804-977-4272
 */

#ifdef vaxc
#module	NEWSCALLEDIT "V6.2"
#endif

#define _NEWSCALLEDIT_C
#define module_name "NEWSCALLEDIT"

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

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

  /*
   * - Maximum size of the entry point symbol for the editor. Since we will be
   * - invokeing XXX$EDIT from XXXSHR.EXE, the length of "XXX" cannot be more
   * - than 36 characters. So...
   */
#define	MAGIC_NUMBER_1	(36 + 5 /*strlen("$EDIT")*/ + 1 /*Trailing null*/ )

  /*
   * - Maximum length of the command line passed to lib$spawn when we have to
   * - invoke the editor that way. Purely arbitrary.
   */
#define	MAGIC_NUMBER_2	(512+1)

  /*
   * Macros
   *
   * - Shorthand
   */
#define	DESCR		struct dsc$descriptor_s
#define	DESCR_CONST	struct dsc$descriptor_const_s
#define	FILLIN(string,desc)	desc.dsc$w_length  = strlen(string);\
				desc.dsc$b_dtype   = DSC$K_DTYPE_T;\
				desc.dsc$b_class   = DSC$K_CLASS_S;\
				desc.dsc$a_pointer = string;

  /*
   * Local constants
   *
   * - Text strings for processing the editor logical translation
   */
#define callable_prefixP "callable_"
  /*
   * - Suffixes for accessing shareable images
   */
#define editor_suffixP "$EDIT"
#define image_suffixP  "SHR"

/* static int signal_handler(struct chf$signal_array *, struct chf$mech_array *); */
static int signal_handler(void *, void *);


int
invoke_editor(cmd_opt,Edit_Cmd,infileP,outfileP)
  int	cmd_opt;
  const char *Edit_Cmd;
  const char *infileP;
  const char *outfileP;
{
  int	(*editorP)();
  char	entry_pointA[MAGIC_NUMBER_1];
  DESCR_CONST entry_point_desc;
  char	image_nameA[NAM$C_MAXRSS+1];
  DESCR_CONST image_name_desc;
  DESCR_CONST infile_desc;
  DESCR_CONST outfile_desc;
  DESCR_CONST command_desc;
  char	spawn_commandA[MAGIC_NUMBER_2];
  int	status;
  int	t;
  const char *tP;
  const char *logicalP = (Edit_Cmd && *Edit_Cmd) ? Edit_Cmd : "callable_tpu";


    /* Should we try for a callable editor? Or, go for a subprocess? */
    /* Note:  EDT gets special handling for backwards compatability. */
  t = (strcmp(logicalP,"edt") == 0) ? 0 : strlen(callable_prefixP);
  if (strncmp(logicalP,callable_prefixP,t) == 0) {

      /*
       * Callable editor
       *
       * Create the sharable image name and the entry point symbol.
       */

      /* Point at the char after the prefix */
    tP = &logicalP[t];

      /* cmd_opt indicates whether we're passing a command string to tpu$tpu */
    if (cmd_opt && strcmp(tP,"tpu") != 0) {
      outfileP = "";
      cmd_opt = 0;
    }

    { int ll;
      strnncpy(image_nameA,sizeof(image_nameA), tP,-1, &ll);
      strnncat(image_nameA,sizeof(image_nameA),ll, image_suffixP,-1, 0);

      strnncpy(entry_pointA,sizeof(entry_pointA), tP,-1, &ll);
      strnncat(entry_pointA,sizeof(entry_pointA),ll,
               cmd_opt ? "$TPU" : "$EDIT", -1, 0);
    }

      /* Load up string descriptors for the image and entry */
    FILLIN(image_nameA,image_name_desc);
    FILLIN(entry_pointA,entry_point_desc);

      /* lib$find_image_symbol() is loud mouthed, it signals errors. Gag it! */
    establish_handler(signal_handler);

      /* Call upon VMS to map the editor image */
    status = lib$find_image_symbol(&image_name_desc,&entry_point_desc,&editorP);
    establish_handler(lib$sig_to_ret);

    if ($VMS_STATUS_SUCCESS(status)) {
      if (cmd_opt) {
	  /* Invoke tpu$tpu with a command line string (passed via outfileP) */
	FILLIN(outfileP,command_desc);
	status = (*editorP)(&command_desc);
	}
      else {
	  /* Make string descriptors for the input and output files */
	FILLIN(infileP,infile_desc);
	FILLIN(outfileP,outfile_desc);
	  /* Invoke the editor: FOO$EDIT(infile,outfile) */
	status = (*editorP)(&infile_desc,&outfile_desc);
	}
      }
    }
  else {

      /*
       * Invoke the editor by the named command
       *
       * Create the editor command. It is of the form:
       *
       *  verb INFILE OUTFILE
       */

    sprintf(spawn_commandA,"%s %s %s",Edit_Cmd,infileP,cmd_opt ? "" : outfileP);

      /* Load up the string descriptor and fire off the subprocess */

    status = lib$spawn(c$dsc(spawn_commandA),NULL,NULL,NULL,NULL,NULL,&t,
			NULL,NULL,0,NULL,NULL,NULL);

      /* If the lib$spawn call went ok, return the subprocess final status */
    if ($VMS_STATUS_SUCCESS(status)) status = t;
    }

    /* Return the status code to the caller */
  return(status);
}

/*
 * Ignore the signal
 */

static int
signal_handler(sigarrP,mecharrP)
  void *sigarrP;
  void *mecharrP;
  /* struct chf$signal_array *sigarrP;  */
  /* struct chf$mech_array   *mecharrP; */
{
  return(SS$_CONTINUE);
}
