/*{{{  about this file*/
/*
  ST_UTILS.C
  ST-specific routines for ORIGAMI / Turbo C
  (C) 1991 M. Schwingen
*/
/*}}}  */
/*{{{  #includes*/
#include <stdio.h>
#include <stdlib.h>
#include <ext.h>
#include <string.h>
#include <tos.h>
#include <vdi.h>
#include <aes.h>
#include "ori_rsc.h"

#define ST_UTIL_C
#include "local\bool.h"
#include "..\origami\origami.h"
/*}}}  */

/*{{{  extern GEM variables*/
extern int work_in[12],work_out[57],
           phys_handle,handle,ap_id,
           wind_handle,
           gl_hchar,gl_wchar,gl_hbox,gl_wbox,
           wind_x,wind_y,wind_w,wind_h,
           _x,_y;
/*}}}  */
/*{{{  extern ressource structures and init routine, defined in ORI_RSC.C*/
extern OBJECT *rs_trindex[];
void rsrc_init(void);
/*}}}  */

/*{{{  void st_redraw(void) - init mouse & redraw menu bar*/
void st_redraw(void)
{
  menu_bar(rs_trindex[MENU],0);
  menu_bar(rs_trindex[MENU],1);
  graf_mouse(ARROW,NULL);
}
/*}}}  */
/*{{{  void pre_shell(void) - prepare shell system call*/
void pre_shell(void)
{
  int xy[4];

  menu_bar(rs_trindex[MENU],0); /* remove menu bar */
  /* it seems we have to close our window to avoid system hangups */
  wind_close(wind_handle);
  graf_mouse(M_ON,NULL);        /* display mouse */
  wind_update(END_UPDATE);      /* enable AES screen update */
  /*{{{  clear complete screen*/
  wind_get(0,WF_WORKXYWH,&xy[0],&xy[1],&xy[2],&xy[3]);
  xy[2] += xy[0];
  xy[3] += xy[1];
  xy[0] = xy[1] = 0;
  vr_recfl(handle,xy);
  /*}}}  */
  /*{{{  initialize GEMDOS and BIOS cursor to upper left corner*/
  Cconws("\033H\012");
  Bconout(2,27);
  Bconout(2,'H');
  Bconout(2,10);
  /*}}}  */
}
/*}}}  */
extern int first_redraw_request;
/*{{{  void post_shell(void) - actions after shell call*/
void post_shell(void)
{
  graf_mouse(M_OFF,NULL);       /* disable mouse */
  graf_mouse(ARROW,NULL);
  wind_update(BEG_UPDATE);      /* disable AES screen update */
  menu_bar(rs_trindex[MENU],1); /* re-draw menu bar */
  /* re-open window (closed in pre_shell) - window handle is still
     allocated! */
  first_redraw_request = TRUE;
  wind_open(wind_handle,wind_x-1,wind_y-1,wind_w+2,wind_h+2);
}
/*}}}  */
/*{{{  void newsystem(char *command) - replacement for lib. system() call*/
void newsystem(char *command)
{
  pre_shell();
  system(command);
  Cconws("[END]");
  post_shell();
}
/*}}}  */
/*{{{  void newexit (int status) - replacement for library exit() function*/
void newexit (int status)
{
  /*
     it seems that we first have to get our messages before quitting the
     program in order to avoid problems - so we use get_raw_key() instead
     of Cconin()
  */
  if (status != 0)
    while(get_raw_key() != 13)
      ;
  exit(status);
}
/*}}}  */
extern long vbl_disable( void );
/*{{{  void st_exit(void)*/
void st_exit(void)
{
  Supexec(vbl_disable);
  menu_bar(rs_trindex[MENU],0);
  /*{{{  close & delete window*/
  if (wind_handle >=0)
  {
    wind_close(wind_handle);
    wind_delete(wind_handle);
  }
  /*}}}  */
  wind_update(END_UPDATE);
  graf_mouse(M_ON,NULL);
  v_clsvwk(handle);
  appl_exit();
}
/*}}}  */
/*{{{  void st_init(int *argc, char **argv[])*/
void st_init(int *argc, char **argv[])
{
  /*{{{  variables*/
  register int i;
  int xyarray[4];
  static char *_argv[22];
  char linebuf[255];
  char *p,*p2;
  FILE *f;
  /*}}}  */

  ap_id = appl_init();
  /*{{{  complain if appl_init failed*/
  if (ap_id <0)
  {
    Cconws("\nGEM error at appl_init()\nprogram aborted.\n");
    exit(1);
  }
  /*}}}  */
  /*{{{  open VDI virtual workstation*/
  handle = work_in[0] = graf_handle(&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox);
  for (i = 1; i < 10; work_in[i++] = 1 )
    ;
  work_in[10] = 2; /* 2 = RC */
  v_opnvwk( work_in, &handle, work_out );
  /*{{{  if handle == 0: complain & exit*/
  if (handle == 0)
  {
    form_alert(1,"[1][error at v_opnvwk!][OK]");
    appl_exit();
    exit(1);
  }
  /*}}}  */
  /*}}}  */
  atexit(st_exit);
  /*{{{  initialize VDI parameters: writemode, clip etc.*/
  vswr_mode(handle,MD_REPLACE);
  vst_color(handle,1);
  vst_effects(handle,0);
  vsf_interior(handle,FIS_SOLID);
  vsf_style(handle,7);
  vsf_perimeter(handle,0);
  vsf_color(handle,0);
  vsl_color(handle,1);
  vsl_type(handle,1);
  vsl_width(handle,1);
  vsl_ends(handle,0,0);
  xyarray[0] = xyarray[1] = 0;
  xyarray[2] = work_out[0];
  xyarray[3] = work_out[1];
  vs_clip(handle,1,xyarray);
  vst_alignment(handle,0,5,xyarray,xyarray);
  /*}}}  */
  /*{{{  initialization*/
  /* get size of background window */
  wind_get(0,WF_WORKXYWH,&wind_x,&wind_y,&wind_w,&wind_h);
  /* initialize ressource */
  rsrc_init();
  menu_bar(rs_trindex[MENU],1);
  graf_mouse(ARROW,NULL);
  graf_mouse(M_OFF,NULL);
  wind_update(BEG_UPDATE);
  /*}}}  */
  /*{{{  open window*/
  /* open window, size = full screen, border is invisible (out of screen)
     this is necessary to get redraw messages */
  if ((wind_handle = wind_create(0,wind_x-1,wind_y-1,wind_w+2,wind_h+2)) <0)
  /*{{{  complain & exit*/
  {
    form_alert(1,"[1][Cannot create window.][OK]");
    exit(1);
  }
  /*}}}  */
  wind_open(wind_handle,wind_x-1,wind_y-1,wind_w+2,wind_h+2);
  /*}}}  */
  /*{{{  if no arguments were given: scan file ORIGAMI.OPT for arguments*/
  /*
     if no arguments were passed: read file .\ORIGAMI.OPT or
     $HOME\ORIGAMI.OPT and treat contents of first line as arguments
  */
  if (*argc == 1)
  {
    /*{{{  open file, first ".", then $HOME*/
    /* first try current directory */
    f = fopen("origami.opt","r");
    /* if that does not work -> look in $HOME if present */
    if (f == 0)
    {
      p = getenv("HOME");
      if (p)
      {
        strcpy(linebuf,p);
        strcat(linebuf,"\\origami.opt");
        f = fopen(linebuf,"r");
      }
    }
    /*}}}  */
    if (f != 0)
    {
      fgets(linebuf,254,f);
      fclose(f);
      _argv[0] = *argv[0];
      /*{{{  break up line, build _argv[], increment *argc*/
      p = linebuf;
      while (*p && *argc < 20)
      {
        p2 = p;
        while (*p && *p != ' ' && *p != '\n')
          p++;
        if (*p == 0)
          p[1] = 0;
        *p = '\0';
        _argv[(*argc)++] = strdup(p2);
        p++;
      }
      /*}}}  */
      *argv = _argv;
    }
  }
  /*}}}  */
  *argv[0] = "origami";
}
/*}}}  */

/*{{{  void fileselect(char *str) - GEM fileselect box*/
void fileselect(char *str)
{
  char *p;
  int button;
  static char fs_name[20] = "";
  static char fs_path[256] = "";

  /*{{{  no path from previous call: get current GEMDOS path*/
  if (*fs_path == 0)
  {
    fs_path[0] = Dgetdrv() + 'A';
    fs_path[1] = ':';
    Dgetpath(fs_path+2,0);
    strcat(fs_path,"\\*.*");
  }
  /*}}}  */
  graf_mouse(M_ON,NULL);
  wind_update(END_UPDATE);
  if (fsel_input(fs_path,fs_name,&button) == 0 || button==0)
  /*{{{  error or 'cancel' selected -> return empty string*/
  {
    graf_mouse(M_OFF,NULL);
    wind_update(BEG_UPDATE);
    *fs_path = 0;
    *fs_name = 0;
    *str = 0;
    return;
  }
  /*}}}  */
  graf_mouse(M_OFF,NULL);
  wind_update(BEG_UPDATE);
  /*{{{  no file selected -> return empty string*/
  if (*fs_name == 0)
  {
    *str = 0;
    return;
  }
  /*}}}  */
  /*{{{  build complete file*/
  strcpy(str,fs_path);
  p = str;
  while (*p) p++;
  while (*--p != '\\')
    ;
  *++p = 0;
  strcat(str,fs_name);
  /*}}}  */
}
/*}}}  */
/*{{{  fileprompt - replacement for function in misc.c - supports fileselect box*/
#ifdef STD_C
char *fileprompt(char n[_POSIX_PATH_MAX+1])
#else
char *fileprompt(n) char n[_POSIX_PATH_MAX+1];
#endif
{
  readprompt(n,M_FILENAME,_POSIX_PATH_MAX);
  if (*n == '\0' && !aborted)
    fileselect(n);
  strlwr(n);             /* mode macros assume lower-case filenames */
  return(n);
}
/*}}}  */
/*{{{  int access(char *file, int flag)*/
#define READONLY 0x01
#define HIDDEN   0x02
#define SYSTEM   0x04
#define VOLUME   0x08
#define SUBDIR   0x10
#define ARCHIVE  0x20
int access(char *file, int flag)
{
  int result;

  result = Fattrib(file,0,0);
  if (result < 0)
    return -1; /* file does not exist */
  if (result & (VOLUME | SUBDIR))
    return -1; /* exists, but is volume / subdir -> no access */

  if ((flag & W_OK) && (result & READONLY))
    return -1; /* no write access */

  return 0;
}
/*}}}  */
/*{{{  void putenv(char *string) - set environment variables*/
/*
   This implementation of putenv simply does a system("setenv  ...").  This
   works well with MUPFEL, it should also work with other shells which stay
   resident in the background while executing  ORIGAMI  and  which maintain
   one global environment for  all  sub-shells. Has anyone a better idea of
   how to do this ?
*/
void putenv(char *string)
{
  char buf[256];
  char *p=buf;

  /* build command: setenv var "value" from string var=value */
  strcpy(buf,"setenv ");
  while (*p)
    p++;
  while (*string && *string != '=')
    *p++ = *string++;
  string++;
  *p++ = ' ';
  *p++ = '"';
  while (*string)
    *p++ = *string++;
  *p++ = '"';
  *p = 0;
  system(buf);
}
/*}}}  */
int no_bak_files = 0; /* global, set by cmd line argument */
/*{{{  FILE *newfopen(const char *filename, const char *mode)*/
FILE *newfopen(const char *filename, const char *mode)
{
  FILE *stream;
  char name2[_POSIX_PATH_MAX], *p;

  if (*mode == 'w' && no_bak_files == 0)
  {
    /*{{{  generate name of bak file*/
    p = strcpy(name2,filename);
    while (*p) p++;
    while (*--p != '.' && *p != '\\' && p>name2)
      ;
    if (*p == '\\' || p==name2)
      strcat(p,".bak");
    else
    {
      *++p = 'b';
      *++p = 'a';
      *++p = 'k';
    }
    /*}}}  */
    /*{{{  if file exists: delete old bak file, rename file to bak file*/
    if(Fsfirst(filename,0x27) == 0)
    {
      unlink(name2);
      rename(filename,name2);
    }
    /*}}}  */
  }
  stream = fopen(filename,mode);
  if (stream != NULL)
    setvbuf(stream,NULL,_IOFBF,10240L);
  else
    if (*mode == 'w' && no_bak_files == 0)
      rename(name2,filename);
  return stream;
}
/*}}}  */
