/*
 This file is part of MOST.

 Copyright (c) 1991, 1999, 2002, 2005-2018, 2019 John E. Davis

 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the Free
 Software Foundation; either version 2 of the License, or (at your option)
 any later version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along
 with this program; if not, write to the Free Software Foundation, Inc., 675
 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "config.h"

/* editor functions */
#include <stdio.h>
#include <string.h>

#ifdef VMS
# include <ssdef.h>
# include <rmsdef.h>
# include <dvidef.h>
# include <jpidef.h>
/* #include <libdef.h> */
# include <descrip.h>
# include <iodef.h>
# include <ttdef.h>
#endif

#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif

#include <slang.h>

#include "most.h"
#include "edit.h"
#include "window.h"
#include "file.h"
#include "sysdep.h"

/* quote_char is one of: 0, ", or '.  It represents the character
 * that will be used to quote the filename.
 */
char *most_escape_filename (char *file, char quote_char)
{
   char *efile, *e;

   if (NULL == (efile = SLmalloc (5 + 2*strlen(file))))
     return NULL;

   e = efile;

#ifndef VMS
   if (quote_char == 0)
     {
	/* No quote char was used for the filename command.  Add it here. */
	*e++ = '"';
     }
   else if (quote_char == '\'')
     {
	/* Suppose the file is Bob's Notes.  With ' as the quote, when passed
	 * to the shell, it would look like 'Bob's Notes'.  Unfortunately, this
	 * would produce an unmatched single quote when processed by the shell.
	 * So, the following escaped form will be used:
	 *    ''"Bob's Notes"''
	 */
	*e++ = '\'';
	*e++ = '"';
     }
#endif

   while (1)
     {
	char ch = *file++;
	switch (ch)
	  {
	   case 0:
#ifndef VMS
	     if (quote_char == 0)
	       *e++ = '"';
	     else if (quote_char == '\'')
	       {
		  *e++ = '"';
		  *e++ = '\'';
	       }
#endif
	     *e = 0;
	     return efile;
#ifndef VMS
	     /* For a double-quoted string, only the following characters
	      * may be escaped with a backslash.  Unfortunately, escaping
	      * others such as &, *, |, etc will not work.
	      */
	   case '\\': case '$': case '"': case '`': case '\n':
	     *e++ = '\\';
	     *e++ = ch;
	     break;
#endif
	   default:
	     *e++ = ch;
	  }
     }
}

static int create_edit_command (char *edit, char *cmd, unsigned int sizeof_cmd, char *file)
{
   int d, s;
   char ch, *p = edit;
   char *efile;
   char quote_char = '"';
   /* Look for %d and %s */

   d = s = 0;

   while (0 != (ch = *p++))
     {
	char q = 0;

	if (((ch == '\'') || (ch == '"'))
	    && (*p == '%'))
	  {
	     q = ch;
	     ch = '%';
	     p++;
	  }
	if (ch != '%') continue;

	ch = *p++;
	if (!d && (ch == 'd'))
	  {
	     if (s == 0) d = 1; else d = 2;
	  }
	else if (!s && (ch == 's'))
	  {
	     if (d == 0) s = 1; else s = 2;
	     if (q && (q != *p))
	       {
		  most_message ("Unmatched quote character in editor definition", 1);
		  return -1;
	       }
	     quote_char = q;
	  }
	else
	  {
	     most_message ("Invalid editor definition.", 1);
	     return -1;
	  }
     }

   if (NULL == (efile = most_escape_filename (file, quote_char)))
     return -1;

   if ((d == 0) && (s == 0))
     {
	/* No %d, %s */
	_pSLsnprintf (cmd, sizeof_cmd, "%s \"%s\"", edit, efile);
	SLfree (efile);
	return 0;
     }

   if (d == 0)
     {
	(void) _pSLsnprintf (cmd, sizeof_cmd, edit, efile);
	SLfree (efile);
	return 0;
     }

   if (d && s)
     {
	if (d == 1)
	  (void) _pSLsnprintf (cmd, sizeof_cmd, edit, Most_C_Line, efile);
	else
	  (void) _pSLsnprintf (cmd, sizeof_cmd, edit, efile, Most_C_Line);

	SLfree (efile);
	return 0;
     }

   most_message ("Unsupported Editor definition", 1);
   SLfree (efile);
   return -1;
}

#ifdef VMS
int call_edt_tpu(int tpu, char *file)
{
   char the_file[MAX_PATHLEN], *strp;
   extern void edt$edit();
   extern void tpu$tpu();
   struct dsc$descriptor_s  file_desc;

   if (tpu == 1)  /* tpu */
     _pSLsnprintf (the_file, sizeof(the_file), "TPU /START=%d ", Most_C_Line);
   else
     the_file[0] = '\0';

   strcat(the_file, file);

   /*  lose the version number */
   strp = the_file;
   while((*strp != '\0') && (*strp != ';')) strp++;
   *strp = '\0';

   file_desc.dsc$w_length = strlen(the_file);
   file_desc.dsc$a_pointer = the_file;
   file_desc.dsc$b_class = DSC$K_CLASS_S; /* scalar, string type */
   file_desc.dsc$b_dtype = DSC$K_DTYPE_T; /* ascii string */

   if (tpu == 1)
     tpu$tpu(&file_desc);
   else
     edt$edit(&file_desc);

   return 1;
}
#endif

void most_edit_cmd(void)
{
   char *editor;
   char cmd[2*MAX_PATHLEN + 30];
#ifdef VMS
   int tpu = -1;
#endif
   char *file;

   file = Most_Buf->file;

   if ((0 == *file) || ('*' == *file))
     return;

   if (Most_Secure_Mode)
     {
	most_message ("Editing not permitted in secure mode.", 1);
	return;
     }

   if ((NULL == (editor = getenv("MOST_EDITOR")))
       && (NULL == (editor = getenv("SLANG_EDITOR")))
       && (NULL == (editor = getenv("EDITOR"))))
#ifdef VMS
     editor = "EDT";
#else
   editor = "vi";
#endif

#ifdef VMS
   if (!strcmp(editor,"EDT")) tpu = 0;
   else if (!strcmp(editor,"TPU")) tpu = 1;
   else
#endif
     if (-1 == create_edit_command(editor, cmd, sizeof(cmd), file))
       return;

   most_reset_tty ();
   most_reset_display ();

#ifdef VMS
   if (tpu != -1) (void) call_edt_tpu(tpu, file);
   else
#endif
     SLsystem (cmd);

   most_reread_file ();
   most_init_tty ();
   most_init_display ();
   most_redraw_display ();
}

