/*  025  31-May-87  ovcmd.c

        Copyright (c) 1987 by Blue Sky Software.  All rights reserved.
*/

#include <stdio.h>
#include <process.h>
#include "ov.h"
#include "overr.h"
#include "direct.h"
#include "strmem.h"

static char cantexe[] = "can't execute!";
static char str2big[] = "Expanded string is too large!";

extern WINDOW cw;
extern FILE_ENT files[];
extern PAG_ENT pag_tbl[];
extern UDK_ENT udk_tbl[];

char *strrchr(), *strchr();

#ifdef LINT_ARGS
int is_macro(char *, char *);
char *expand_macro(char *, FILE_ENT *);
char *cpyexp(char *, char *, char *);
char *cpynoext(char *, char *, char *);
#else
int is_macro();
char *expand_macro(), *cpyexp(), *cpynoext();
#endif


/******************************************************************************
 **                         D O _ C M D                                      **
 *****************************************************************************/

do_cmd() {             /* read and execute a single dos command */

   char *cmd;

   cmd = prompt(NULL,"Enter a single DOS command to execute",NULL,0,MAX_REPLY);
   if (strlen(cmd) == 0)
      return;

   run_cmd(cmd,TRUE,FALSE);     /* execute the command, pause, don't reload */
}


/******************************************************************************
                             E X E C U T E
 ******************************************************************************/

execute() {            /* execute the current file */

   char title[MAX_NAMELEN+10], *fn, *ext, *cmd, *fnbuf;

   /* make sure the file looks like its executable */

   if (files[cw.curidx].flags & DIR)
      show_error(0,NO_EXE_DIR,1,"Can't execute a directory!");

   if ((ext = strrchr(fn = files[cw.curidx].name,'.')) == NULL ||
       strlen(ext) < 4 || strstr(".EXE .COM .BAT",ext) == NULL) {
      do_pagcmd(fn,ext);
      return;
   }

   fnbuf = fname(&files[cw.curidx]);   /* put cmd less ext into buffer */
   *strrchr(fnbuf,'.') = '\0';
   strcpy(title,"Execute ");
   strcat(title,fn);

   cmd = prompt(title,"Add parameters to command, return to execute.",
         fnbuf,strlen(fnbuf),MAX_REPLY);

   free(fnbuf);                        /* free fname() space */

   if (strlen(cmd) == 0)               /* user can cancel by clearing line */
      return;

   run_cmd(cmd,TRUE,FALSE);            /* run command, pause, don't reload */
}


/******************************************************************************
                           D O _ P A G C M D
 *****************************************************************************/

static int
do_pagcmd(fn,ext)      /* execute a Point-and-Go cmd for given extension */
char *fn, *ext;
{
   int i;
   register PAG_ENT *pp;

   if (ext)                    /* on input, is either NULL (file name has */
      ext++;                   /* no extension) or it points to the '.'   */
   else                        /* just prior to the extension. we don't   */
      ext = "";                /* want to see the period or the NULL.     */

   /* try to find a matching extension in the extcmdtbl */

   for (i = 0, pp = pag_tbl; i < NUM_PAG; i++, pp++)

      if (pp->used && stricmp(ext,pp->ext) == 0) { /* matching ext? */
         run_cmd(pp->cmd,pp->pause,pp->reload);    /* yes, run command */
         return;
      }

   /* didn't find a matching extension, tell user */

   show_error(0,NO_EXT,3,fn," does not have a known extension, ",cantexe);
}


/*****************************************************************************
                              D O _ U D K
 *****************************************************************************/

do_udk(udk_key)        /* execute UDK for given key */
int udk_key;
{
   register UDK_ENT *up = &udk_tbl[udk_key - UDK_START];

   if (up->used)
      run_cmd(up->cmd,up->pause,up->reload);
   else
      show_error(0,BAD_UDK,2,"That UDK is not defined, ",cantexe);
}


/******************************************************************************
 **                          R U N _ C M D                                   **
 *****************************************************************************/

run_cmd(cmd,pause,reload)      /* execute a dos command via command.com */
char *cmd;
int pause, reload;
{
   char *expcmd;
   int has_tagged, i;
   register FILE_ENT *fp;

   /* make sure there are tagged files if user want's tagged file names
      as a command macro */

   if ((has_tagged = (is_macro(cmd,"t") || is_macro(cmd,"xt"))) && cw.num_tagged == 0)
      show_error(0,NONE_TAGGED,2,"No files tagged, ",cantexe);

   clr_scr();                          /* home the cursor and clear screen */
   showcursor();                       /* let user see the cursor */

   /* if there are tagged files, do the command once for each tagged file */

   if (has_tagged) {
      for (i = 0, fp = files; i < cw.nfiles && !brkout(); i++, fp++)
         if (fp->flags & TAGGED) {
            expcmd = expand_macro(cmd,fp);
            system(expcmd);
            free(expcmd);
         }

    } else {   /* otherwise just do the command once for current file */

       expcmd = expand_macro(cmd,&files[cw.curidx]);
       system(expcmd);
       free(expcmd);
    }

   if (pause) {
      putstr("\r\nPress any key to return to OVERVIEW.");
      getchr();
   }

   /* who knows what state things might be after a DOS command, restart
      everything from scratch */

   reinit_tty();                       /* make sure the tty is setup right */
   if (reload)
      renew();                         /* read load files[], redo screen, etc */
   else {
      setup_file_scr();                /* display the static screen image */
      update_header();                 /* update header info */
      refresh_screen(0);               /* redisplay all file data */
   }
}


/******************************************************************************
 **                      S P A W N _ C L I                                   **
 *****************************************************************************/

void
spawn_cli() {          /* spawn a copy of the command interpeter */

   char comspec[MAX_PATHLEN+1], *ep, *getenv();

   clr_scr();                          /* home cursor, clear screen */
   showcursor();                       /* show user the cursor */

   putstr("\r\nEnter the command 'EXIT' to return to OVERVIEW.\r\n");

   if (ep = getenv("COMSPEC"))         /* use COMSPEC env variable if defined */
      strcpy(comspec,ep);
   else
      strcpy(comspec,"\COMMAND.COM");  /* otherwise hope its in the root dir */

   spawnl(P_WAIT,comspec,NULL);        /* run a copy of command.com */

   /* who knows what state things might be after going to DOS, restart
      everything from scratch */

   reinit_tty();                       /* make sure tty is setup right */
   setup_file_scr();                   /* display the static screen image */
   update_header();                    /* update header info */
   refresh_screen(0);                  /* redisplay all file data */
}


/******************************************************************************
                               I S _ M A C R O
 ******************************************************************************/

static int
is_macro(str,type)     /* return TRUE if str contains macro of "type" */
register char *str, *type;
{
   while (str = strchr(str,'$'))                       /* macros start with $ */
      if (strnicmp(str+1,type,strlen(type)) == 0)      /* right type?         */
         return(TRUE);                                 /*   found it          */
      else
         if (*(str+1) == '$')                  /* not a macro if $$   */
            str += 2;
         else
            str++;                             /* skip over this $    */

   return(FALSE);                              /* not found */
}


/*****************************************************************************
                          E X P A N D _ M A C R O
 ****************************************************************************/

static char *
expand_macro(str,fp)   /* expand any macros in str */
char *str;
FILE_ENT *fp;
{
#define MAXSTR 150
   char expstr[MAXSTR+1];
   register char *cp = str, *ep = expstr;

   /* make a quick exit if no macro in string */

   if (strchr(str,'$') == NULL)
      return(Strdup(str));

   /* now expand the macros */

   while (*cp && ep - expstr <= MAXSTR) {

      if (*cp == '$') {                /* possible macro?   */

         if (*(cp+1) == '$') {         /* not a macro if $$ */
            *ep++ = '$';
            cp += 2;

         } else {                      /* maybe a macro     */

            switch (tolower(*(cp+1))) {
               case 'c':               /* current file name */
                  ep = cpyexp(ep,expstr,files[cw.curidx].name);
                  break;
               case 'd':               /* current drive     */
                  *ep++ = *cw.dirbuf;
                  break;
               case 'p':               /* file's pathname   */
                  ep = cpyexp(ep,expstr,fp->dirp);
                  break;
               case 't':               /* tagged file name  */
                  ep = cpyexp(ep,expstr,fp->name);
                  break;
               case 'x':               /* file name without extension */
                  if (tolower(*(cp+2)) == 'c') {
                     ep = cpynoext(ep,expstr,files[cw.curidx].name);
                     cp++;
                  } else if (tolower(*(cp+2)) == 't') {
                     ep = cpynoext(ep,expstr,fp->name);
                     cp++;
                  }
                  break;
               default:
                  show_error(0,0,1,"Unknown macro in string!");
                  return(Strdup(""));
            }
            cp += 2;                   /* skip over macro */
         }

      } else                           /* normal char, just copy */
         *ep++ = *cp++;
   }

   if (*cp) {                                  /* should be at EOS */
      show_error(0,0,1,str2big);
      return(Strdup(""));
   }

   *ep = '\0';                 /* terminate expanded string */

   return(Strdup(expstr));     /* return a copy to caller */
}


/******************************************************************************
                          C P Y E X P / N O E X T
 *****************************************************************************/

static char *
cpyexp(ep,estr,mstr)   /* copy macro text to expanded string */
char *ep, *estr, *mstr;
{
   if (ep - estr + strlen(mstr) <= MAXSTR) {   /* add it on if it will fit */
      strcpy(ep,mstr);
      return(ep+strlen(mstr));                 /* return EOS address */
   } else
      return(ep);
}


static char *
cpynoext(ep,estr,mstr) /* copy macro text (filename) without extension */
char *ep, *estr, *mstr;
{
   char *extp, fn[MAX_NAMELEN+1];

   strcpy(fn,mstr);                    /* cut off any extension of file name */
   if (extp = strchr(fn,'.'))
      *extp = '\0';

   return(cpyexp(ep,estr,fn));
}
