/* 
   Copyright 1994-2003 Free Software Foundation, Inc.

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

   This library 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
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
   USA

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <process.h>
#include <wchar.h>
#include <locale.h>
#include "libp.h"
#include <dpmi.h>

struct sb {
	short envseg;
	short ocomtail;
	short scomtail;
	short ofcb1,sfcb1;
	short ofcb2,sfcb2;
	short reserved[2 + 2];
};
struct sb32 {
   int oenv;
   short senv;
   int ocomtail;
	short scomtail;
   int ofcb1;
   short sfcb1;
   int ofcb2;
   short sfcb2;
   short reserved[2 + 4];
};
extern UWORD _dtaseg;
extern SELECTOR _dtasel;
extern int _pmodew;

extern char _RTL_DATA **_environ ;

static char *fcbstring = "                ";

static char *createenviron(char **env, int *elen, char *file)
{
   int len = 0 ;
   char **dummy,*rv=0 ;
   if (!env)
      env = _environ ;
   dummy = env ;
   while (*dummy) {
      len += strlen(*dummy) + 1 ;
      dummy++ ;
   }
   len += strlen(file) +4;
   if (len) {
      len += 1 ;
	  len += 15;
	  len &= ~15;
      rv = malloc (len) ;
      if (rv) {
         char *p = rv ;
		 if (!*env)
			 *p++ = 0;
         else while(*env) {
            strcpy(p,*env) ;
            p+= strlen(p)+ 1 ;
            env++ ;
         }
         *p++ = 0 ;
		 *p++ = 1;
		 *p++ = 0;
		 strcpy(p, file);
      }
   }
   *elen = len ;
   return rv ;
}
int __ll_spawn(char *file, char *parms, char **env, int mode)
{
	DPMI_REGS regs;
	struct sb spawnblock;
   struct sb32 spawnblock32 ;
	UWORD envseg;
	SELECTOR envsel;
   short _DSS ;
	char parms1[1024];
   int elen ;
   int rv = 0 ;
   char *block = createenviron(env, &elen, file) ;
   if (!block)
      return -1 ;
   strcpy(parms1+1,parms);
   strcat(parms1+1,"\r");
   parms1[0] = strlen(parms1+1);
   if (_pmodew) {
      if (dpmi_alloc_real_memory(&envsel,&envseg,(elen+15)/16)) {
         free(block) ;
         return -1 ;
      }
      dpmi_copy_from_ds(envsel,0,block,elen) ;

      regs.h.dx = __nametodta(file,256);
      spawnblock.ocomtail =  __nametodta(parms1,512);
      spawnblock.scomtail =  _dtaseg;
      spawnblock.ofcb1 = __nametodta(fcbstring,768);
      spawnblock.ofcb2 = __nametodta(fcbstring,768+32);
      spawnblock.sfcb1 = spawnblock.sfcb2 = _dtaseg;
      spawnblock.envseg = envseg;
      regs.h.bx = __buftodta(&spawnblock,sizeof(struct sb));
      regs.b.al = 0;
      __doscall(0x4b,&regs);

      free(block) ;
      dpmi_dealloc_real_memory(envsel) ;

      if (regs.h.flags & 1)
         return -1;

      __doscall(0x4d,&regs);
      return regs.b.al;
   } else {
      asm mov word [_DSS],ds
      spawnblock32.oenv = block ;
      spawnblock32.senv = _DSS ;
      spawnblock32.ocomtail = parms1 ;
      spawnblock32.scomtail = _DSS ;
      spawnblock32.ofcb1 = fcbstring ;
      spawnblock32.sfcb1 = _DSS ;
      spawnblock32.ofcb2 = fcbstring ;
      spawnblock32.sfcb2 = _DSS ;
      asm {
         mov ax,0x4b00
		 push ebx
         lea ebx,dword [spawnblock32]
         mov edx,[file]
         int 0x21
		 pop ebx
         jnc  spawnok
         mov [rv],-1
      spawnok:
      }
      free(block) ;
      if (rv != -1) {
		  asm {
		  	mov ax,0x4d00
			int 0x21
			mov byte [rv], al
		  }
      }
      return rv ;
   }
}
