home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mint104s.zoo / mint.src / main.c < prev    next >
C/C++ Source or Header  |  1993-03-08  |  39KB  |  1,460 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. #include "mint.h"
  8. #include "version.h"
  9. #include "cookie.h"
  10. #include "xbra.h"
  11.  
  12. /* the kernel's stack size */
  13. #define STACK    8*1024L
  14.  
  15. /* if the user is holding down the magic shift key, we ask before booting */
  16. #define MAGIC_SHIFT 0x2        /* left shift */
  17.  
  18. /* magic number to show that we have captured the reset vector */
  19. #define RES_MAGIC 0x31415926L
  20.  
  21. static void xbra_install P_((xbra_vec *, long, long ARGS_ON_STACK (*)()));
  22. static void init_intr P_((void));
  23. static long getmch P_((void));
  24. static void do_line P_((char *));
  25. static void shutmedown P_((PROC *));
  26. void shutdown P_((void));
  27. static void doset P_((char *,char *));
  28. static long ARGS_ON_STACK mint_criticerr P_((long));
  29. static void ARGS_ON_STACK do_exec_os P_((register long basepage));
  30.  
  31. static int gem_active;    /* 0 if AES has not started, nonzero otherwise */
  32.  
  33. #define EXEC_OS 0x4feL
  34. static int  check_for_gem P_((void));
  35. static void run_auto_prgs P_((void));
  36.  
  37. #ifdef LATTICE
  38. /*
  39.  * AGK: this is witchcraft to completely replace the startup code for
  40.  * Lattice; doing so saves around 10K on the final binary and pulls only
  41.  * long division & multitplication from the library (and not even those
  42.  * if you compile for native '030). The drawback of this code is it
  43.  * passes no environment or command line whatsoever. Since I always
  44.  * set MiNT options & environment in 'mint.cnf' this is not a personal
  45.  * downer, however at some point in the future we ought to have a kernel
  46.  * parseargs() like call which sets these things up.
  47.  */ 
  48. BASEPAGE *_base;
  49.  
  50. static void
  51. start(BASEPAGE *bp)
  52. {
  53.     long shrinklen;
  54.     
  55.     _base = bp;
  56.     shrinklen = bp->p_tlen + bp->p_dlen + bp->p_blen + STACK + 0x100;
  57.     if (bp->p_lowtpa + shrinklen <= bp->p_hitpa) {
  58.         static char null[1] = {""};
  59.         static char *argv[2] = {null, NULL};
  60.         extern __builtin_putreg P_((int, long));    /* totally bogus */
  61.  
  62.         __builtin_putreg(15, bp->p_lowtpa + shrinklen);
  63.         Mshrink((void *)bp->p_lowtpa, shrinklen);
  64.         main(1, argv);
  65.     }
  66.     Pterm(ENSMEM);
  67. }
  68. #endif
  69.  
  70. #ifdef __GNUC__
  71. long _stksize = STACK;
  72. #ifndef PROFILING
  73. #include <minimal.h>
  74. #endif
  75. #endif
  76.  
  77. int curs_off = 0;    /* set if we should turn the cursor off when exiting */
  78. int mint_errno = 0;    /* error return from open and creat filesystem calls */
  79.  
  80. /*
  81.  * AGK: for proper co-processors we must consider saving their context.
  82.  * This variable when non-zero indicates that the BIOS considers a true
  83.  * coprocessor to be present. We use this variable in the context switch
  84.  * code to decide whether to attempt an FPU context save.
  85.  */
  86. short fpu = 0;
  87.  
  88. /*
  89.  * "mch" holds what kind of machine we are running on
  90.  */
  91. long mch = 0;
  92.  
  93. /*
  94.  * "screen_boundary+1" tells us how screens must be positioned
  95.  * (to a 256 byte boundary on STs, a 16 byte boundary on other
  96.  * machines; actually, 16 bytes is conservative, 4 is probably
  97.  * OK, but it doesn't hurt to be cautious). The +1 is because
  98.  * we're using this as a mask in the ROUND() macro in mem.h.
  99.  */
  100. int screen_boundary = 255;
  101.  
  102. /*
  103.  * variable holds processor type
  104.  */
  105. long mcpu = 0;
  106.  
  107. /*
  108.  * variable holds language preference
  109.  */
  110. int gl_lang = -1;
  111.  
  112. /*
  113.  * variable set if someone has already installed an flk cookie
  114.  */
  115. int flk = 0;
  116.  
  117. /*
  118.  * variable set to 1 if the _VDO cookie indicates Falcon style video
  119.  */
  120. int FalconVideo;
  121.  
  122. /* program to run at startup */
  123. #ifdef MULTITOS
  124. static int init_is_gemsys = 1;    /* set to 1 if init is gem.sys */
  125. #else
  126. static int init_is_gemsys = 0;    /* set to 1 if init is gem.sys */
  127. #endif
  128. static const char *init_prg = 0;
  129.  
  130. /* note: init_tail is also used as a temporary stack for resets in
  131.  * intr.spp
  132.  */
  133. char init_tail[256];
  134.  
  135. /* initial environment for that program */
  136. static char *init_env = 0;
  137. /* temporary pointer into that environment for setenv */
  138. static char *env_ptr;
  139. /* length of the environment */
  140. static long env_len;
  141.  
  142. /* GEMDOS pointer to current basepage */
  143. BASEPAGE **tosbp;
  144.  
  145. /* pointer to the BIOS keyboard shift variable */
  146. extern char *kbshft;    /* see bios.c */
  147.  
  148. /* version of TOS we're running over */
  149. int tosvers;
  150.  
  151. /* structures for keyboard/MIDI interrupt vectors */
  152. KBDVEC *syskey, oldkey;
  153. xbra_vec old_ikbd;            /* old ikbd vector */
  154.  
  155. /* values the user sees for the DOS, BIOS, and XBIOS vectors */
  156. long save_dos, save_bios, save_xbios;
  157.  
  158. /* values for original system vectors */
  159. xbra_vec old_dos, old_bios, old_xbios, old_timer, old_vbl, old_5ms;
  160. xbra_vec old_criticerr;
  161. xbra_vec old_execos;
  162.  
  163. long old_term;
  164.  
  165. xbra_vec old_resvec;    /* old reset vector */
  166. long old_resval;    /* old reset validation */
  167.  
  168. #ifdef EXCEPTION_SIGS
  169. /* bus error, address error, illegal instruction, etc. vectors */
  170. xbra_vec old_bus, old_addr, old_ill, old_divzero, old_trace, old_priv;
  171. xbra_vec old_linef, old_chk, old_trapv, old_mmuconf, old_format, old_cpv;
  172. xbra_vec old_uninit, old_spurious, old_fpcp[7], old_pmmuill, old_pmmuacc;
  173. #endif
  174.  
  175. /* BIOS disk vectors */
  176. xbra_vec old_mediach, old_getbpb, old_rwabs;
  177.  
  178. /* BIOS drive map */
  179. long olddrvs;
  180.  
  181. extern Func bios_tab[], dos_tab[];
  182.  
  183. /* kernel info that is passed to loaded file systems and device drivers */
  184.  
  185. struct kerinfo kernelinfo = {
  186.     MAJ_VERSION, MIN_VERSION,
  187.     DEFAULT_MODE, 0,
  188.     bios_tab, dos_tab,
  189.     changedrv,
  190.     Trace, Debug, ALERT, FATAL,
  191.     kmalloc, kfree, umalloc, ufree,
  192.     strnicmp, stricmp, strlwr, strupr, ksprintf,
  193.     ms_time, unixtim, dostim,
  194.     nap, sleep, wake, wakeselect,
  195.     denyshare, denylock
  196. };
  197.  
  198. /* table of processor frame sizes in _words_ (not used on MC68000) */
  199. unsigned char framesizes[16] = {
  200. /*0*/    0,    /* MC68010/M68020/M68030/M68040 short */
  201. /*1*/    0,    /* M68020/M68030/M68040 throwaway */
  202. /*2*/    2,    /* M68020/M68030/M68040 instruction error */
  203. /*3*/    2,    /* M68040 floating point post instruction */
  204. /*4*/    3,    /* MC68LC040/MC68EC040 unimplemented floating point instruction */
  205. /*5*/    0,    /* NOTUSED */
  206. /*6*/    0,    /* NOTUSED */
  207. /*7*/    26,    /* M68040 access error */    
  208. /*8*/    25,    /* MC68010 long */    
  209. /*9*/    6,    /* M68020/M68030 mid instruction */
  210. /*A*/    12,    /* M68020/M68030 short bus cycle */
  211. /*B*/    42,    /* M68020/M68030 long bus cycle */
  212. /*C*/    8,    /* CPU32 bus error */
  213. /*D*/    0,    /* NOTUSED */
  214. /*E*/    0,    /* NOTUSED */
  215. /*F*/    0    /* NOTUSED */
  216. };
  217.  
  218. /* TOS and MiNT cookie jars, respectively. See the comments and code 
  219.  * after main() for further details
  220.  */
  221.  
  222. COOKIE *oldcookie, *newcookie;
  223.  
  224. /*
  225.  * install a new vector for address "addr", using the XBRA protocol.
  226.  * must run in supervisor mode!
  227.  */
  228.  
  229. static void
  230. xbra_install(xv, addr, func)
  231.     xbra_vec *xv;
  232.     long addr;
  233.     long ARGS_ON_STACK (*func)();
  234. {
  235.     xv->xbra_magic = XBRA_MAGIC;
  236.     xv->xbra_id = MINT_MAGIC;
  237.     xv->jump = JMP_OPCODE;
  238.     xv->this = func;
  239.     xv->next = *((struct xbra **)addr);
  240.     *((short **)addr) = &xv->jump;
  241. }
  242.  
  243. /*
  244.  * MiNT critical error handler; all it does is to jump through
  245.  * the vector for the current process
  246.  */
  247.  
  248. static long ARGS_ON_STACK
  249. mint_criticerr(error)
  250.     long error;    /* high word is error, low is drive */
  251. {
  252.     return (*curproc->criticerr)(error);
  253. }
  254.  
  255. /*
  256.  * if we are MultiTOS, and if we are running from the AUTO folder,
  257.  * then we grab the exec_os vector and use that to start GEM; that
  258.  * way programs that expect exec_os to act a certain way will still
  259.  * work.
  260.  * NOTE: we must use Pexec instead of p_exec here, because we will
  261.  * be running in a user context (that of process 1, not process 0)
  262.  */
  263.  
  264. static void ARGS_ON_STACK
  265. do_exec_os(basepage)
  266.     register long basepage;
  267. {
  268.     register int r;
  269.  
  270.     if (!init_prg)
  271.         init_prg = "\\multitos\\gem.sys";
  272.  
  273. /* we have to set a7 to point to lower in our TPA; otherwise we would
  274.  * bus error right after the Mshrink call!
  275.  */
  276.     setstack(basepage+500L);
  277. #ifdef __TURBOC__
  278.     Mshrink(0, (void *)basepage, 512L);
  279. #else
  280.     Mshrink((void *)basepage, 512L);
  281. #endif
  282.     r = Pexec(200, init_prg, init_tail, init_env);
  283.     Pterm(r);
  284. }
  285.  
  286.  
  287. /* initialize all interrupt vectors and new trap routines
  288.  * we also get here any TOS variables that we're going to change
  289.  * (e.g. the pointer to the cookie jar) so that rest_intr can
  290.  * restore them.
  291.  */
  292.  
  293. static void
  294. init_intr()
  295. {
  296.     extern long ARGS_ON_STACK mint_bios();
  297.     extern long ARGS_ON_STACK mint_dos();
  298.     extern long ARGS_ON_STACK mint_timer();
  299.     extern long ARGS_ON_STACK mint_vbl();
  300.     extern long ARGS_ON_STACK mint_5ms();
  301.     extern long ARGS_ON_STACK mint_xbios();
  302.     extern long ARGS_ON_STACK reset();
  303.       extern long ARGS_ON_STACK new_ikbd();
  304.       extern long ARGS_ON_STACK new_bus();
  305.       extern long ARGS_ON_STACK new_addr();
  306.       extern long ARGS_ON_STACK new_ill();
  307.       extern long ARGS_ON_STACK new_divzero();
  308.       extern long ARGS_ON_STACK new_trace();
  309.       extern long ARGS_ON_STACK new_priv();
  310.       extern long ARGS_ON_STACK new_linef();
  311.       extern long ARGS_ON_STACK new_chk();
  312.       extern long ARGS_ON_STACK new_trapv();
  313.       extern long ARGS_ON_STACK new_fpcp();
  314.       extern long ARGS_ON_STACK new_mmu();
  315.       extern long ARGS_ON_STACK new_format();
  316.       extern long ARGS_ON_STACK new_cpv();
  317.       extern long ARGS_ON_STACK new_uninit();
  318.       extern long ARGS_ON_STACK new_spurious();
  319.       extern long ARGS_ON_STACK new_pmmuacc();
  320.     short savesr;
  321.     int i;
  322.  
  323.     syskey = (KBDVEC *)Kbdvbase();
  324.     oldkey = *syskey;
  325.  
  326.     xbra_install(&old_ikbd, (long)(&syskey->ikbdsys), new_ikbd);
  327.  
  328. /* gratuitous (void *) for Lattice */
  329.     old_term = (long)Setexc(0x102, (void *)-1UL);
  330.  
  331.     savesr = spl7();
  332.  
  333.     xbra_install(&old_dos, 0x84L, mint_dos);
  334.     save_dos = (long)old_dos.next;
  335.  
  336.     xbra_install(&old_bios, 0xb4L, mint_bios);
  337.     save_bios = (long)old_bios.next;
  338.  
  339.     xbra_install(&old_xbios, 0xb8L, mint_xbios);
  340.     save_xbios = (long)old_xbios.next;
  341.  
  342.     xbra_install(&old_timer, 0x400L, mint_timer);
  343.     xbra_install(&old_criticerr, 0x404L, mint_criticerr);
  344.     xbra_install(&old_5ms, 0x114L, mint_5ms);
  345.     xbra_install(&old_vbl, 4*0x1cL, mint_vbl);
  346.     xbra_install(&old_resvec, 0x42aL, reset);
  347.     old_resval = *((long *)0x426L);
  348.     *((long *)0x426L) = RES_MAGIC;
  349.  
  350.     spl(savesr);
  351.  
  352. #ifdef EXCEPTION_SIGS
  353. /* set up signal handlers */
  354.     xbra_install(&old_bus, 8L, new_bus);
  355.     xbra_install(&old_addr, 12L, new_addr);
  356.     xbra_install(&old_ill, 16L, new_ill);
  357.     xbra_install(&old_divzero, 20L, new_divzero);
  358.     xbra_install(&old_trace, 36L, new_trace);
  359.     xbra_install(&old_priv, 32L, new_priv);
  360.     if (tosvers >= 0x106)
  361.         xbra_install(&old_linef, 44L, new_linef);
  362.     xbra_install(&old_chk, 24L, new_chk);
  363.     xbra_install(&old_trapv, 28L, new_trapv);
  364.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  365.         xbra_install(&old_fpcp[i], 192L + i * 4, new_fpcp);
  366.     }
  367.     xbra_install(&old_mmuconf, 224L, new_mmu);
  368.     xbra_install(&old_pmmuill, 228L, new_mmu);
  369.     xbra_install(&old_pmmuacc, 232L, new_pmmuacc);
  370.     xbra_install(&old_format, 56L, new_format);
  371.     xbra_install(&old_cpv, 52L, new_cpv);
  372.     xbra_install(&old_uninit, 60L, new_uninit);
  373.     xbra_install(&old_spurious, 96L, new_spurious);
  374. #endif
  375.  
  376. /* set up disk vectors */
  377.     xbra_install(&old_mediach, 0x47eL, new_mediach);
  378.     xbra_install(&old_rwabs, 0x476L, new_rwabs);
  379.     xbra_install(&old_getbpb, 0x472L, new_getbpb);
  380.     olddrvs = *((long *)0x4c2L);
  381.  
  382. /* set up cookie jar */
  383.     oldcookie = *CJAR;    /* CJAR defined in cookie.h */
  384.     install_cookies();
  385. }
  386.  
  387. /* restore all interrupt vectors and trap routines */
  388. /*
  389.  * NOTE: This is *not* the approved way of unlinking XBRA trap handlers.
  390.  * Normally, one should trace through the XBRA chain. However, this is
  391.  * a very unusual situation: when MiNT exits, any TSRs or programs running
  392.  * under MiNT will no longer exist, and so any vectors that they have
  393.  * caught will be pointing to never-never land! So we do something that
  394.  * would normally be considered rude, and restore the vectors to
  395.  * what they were before we ran.
  396.  * BUG: we should restore *all* vectors, not just the ones that MiNT caught.
  397.  */
  398.  
  399. void
  400. restr_intr()
  401. {
  402.     short savesr;
  403.     int i;
  404.  
  405.     savesr = spl7();
  406.     *syskey = oldkey;        /* restore keyboard vectors */
  407.     *tosbp = _base;            /* restore GEMDOS basepage pointer */
  408.     *CJAR = oldcookie;        /* restore old cookie jar */
  409.  
  410. #ifdef EXCEPTION_SIGS
  411.     *((long *)0x08L) = (long) old_bus.next;
  412.     *((long *)0x0cL) = (long) old_addr.next;
  413.     *((long *)0x10L) = (long) old_ill.next;
  414.     *((long *)0x14L) = (long) old_divzero.next;
  415.     *((long *)0x20L) = (long) old_priv.next;
  416.     *((long *)0x24L) = (long) old_trace.next;
  417.     if (old_linef.next)
  418.         *((long *)0x2cL) = (long) old_linef.next;
  419.     *((long *)0x18L) = (long) old_chk.next;
  420.     *((long *)0x1cL) = (long) old_trapv.next;
  421.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  422.         ((long *)0xc0L)[i] = (long) old_fpcp[i].next;
  423.     }
  424.     *((long *)0xe0L) = (long) old_mmuconf.next;
  425.     *((long *)0xe4L) = (long) old_pmmuill.next;
  426.     *((long *)0xe8L) = (long) old_pmmuacc.next;
  427.     *((long *)0x38L) = (long) old_format.next;
  428.     *((long *)0x34L) = (long) old_cpv.next;
  429.     *((long *)0x3cL) = (long) old_uninit.next;
  430.     *((long *)0x60L) = (long) old_spurious.next;
  431. #endif
  432.     *((long *)0x84L) = (long) old_dos.next;
  433.     *((long *)0xb4L) = (long) old_bios.next;
  434.     *((long *)0xb8L) = (long) old_xbios.next;
  435.     *((long *)0x408L) = old_term;
  436.     *((long *)0x404L) = (long) old_criticerr.next;
  437.     *((long *)0x114L) = (long) old_5ms.next;
  438.     *((long *)0x400L) = (long) old_timer.next;
  439.     *((long *)0x70L) = (long) old_vbl.next;
  440.     *((long *)0x426L) = old_resval;
  441.     *((long *)0x42aL) = (long) old_resvec.next;
  442.     *((long *)0x476L) = (long) old_rwabs.next;
  443.     *((long *)0x47eL) = (long) old_mediach.next;
  444.     *((long *)0x472L) = (long) old_getbpb.next;
  445.     *((long *)0x4c2L) = olddrvs;
  446.  
  447.     spl(savesr);
  448. }
  449.  
  450.  
  451. /* we save the TOS supervisor stack pointer so that we can reset it when
  452.    calling Pterm() (not that anyone will ever want to leave MiNT :-)).
  453.  */
  454.  
  455. long tosssp;        /* TOS supervisor stack pointer */
  456.  
  457.  
  458. /*
  459.  * enter_kernel: called every time we enter the MiNT kernel via a trap
  460.  * call. Sets up the GEMDOS and BIOS vectors to point to TOS, and
  461.  * sets up other vectors and system variables appropriately. Note that
  462.  * calling enter_kernel multiple times is probably NOT a good idea,
  463.  * but the code will allow it.
  464.  */
  465.  
  466. short in_kernel = 0;
  467.  
  468. void ARGS_ON_STACK
  469. enter_kernel()
  470. {
  471.     short save_sr;
  472.  
  473.     if (in_kernel) return;
  474.  
  475.     save_sr = spl7();
  476.     save_dos = *((long *) 0x84L);
  477.     save_bios = *((long *) 0xb4L);
  478.     save_xbios = *((long *) 0xb8L);
  479.     *((long *) 0x84L) = (long)old_dos.next;
  480.     *((long *) 0xb4L) = (long)old_bios.next;
  481.     *((long *) 0xb8L) = (long)old_xbios.next;
  482.     *tosbp = _base;
  483.  
  484.     in_kernel = 1;
  485.     spl(save_sr);
  486. }
  487.  
  488. /*
  489.  * leave_kernel: called before leaving the kernel, either back to
  490.  * user mode or when calling a signal handler or the GEMDOS
  491.  * terminate vector. Note that interrupts should be disabled before
  492.  * this routine is called.
  493.  */
  494.  
  495. void ARGS_ON_STACK
  496. leave_kernel()
  497. {
  498.     *((long *) 0x84L) = save_dos;
  499.     *((long *) 0xb4L) = save_bios;
  500.     *((long *) 0xb8L) = save_xbios;
  501.     *tosbp = curproc->base;
  502.     in_kernel = 0;
  503. }
  504.  
  505. /*
  506.  * shut down processes; this involves waking them all up, and sending
  507.  * them SIGTERM to give them a chance to clean up after themselves
  508.  */
  509.  
  510. static void
  511. shutmedown(p)
  512.     PROC *p;
  513. {
  514.     UNUSED(p);
  515.     curproc->wait_cond = 0;
  516. }
  517.  
  518. void
  519. shutdown()
  520. {
  521.     PROC *p;
  522.     int proc_left = 0;
  523.  
  524.     curproc->sighandle[SIGCHLD] = SIG_IGN;
  525.  
  526.     for (p = proclist; p; p = p->gl_next) {
  527.         if (p->pid == 0) continue;
  528.         if (p->wait_q != ZOMBIE_Q && p->wait_q != TSR_Q) {
  529.             if (p->wait_q != READY_Q) {
  530.                 short sr = spl7();
  531.                 rm_q(p->wait_q, p);
  532.                 add_q(READY_Q, p);
  533.                 spl(sr);
  534.             }
  535.             post_sig(p, SIGTERM);
  536.             proc_left++;
  537.         }
  538.     }
  539.  
  540.     if (proc_left) {
  541.         /* sleep a little while, to give the other processes a chance to
  542.            shut down
  543.          */
  544.  
  545.         addtimeout(1000, shutmedown);
  546.         do {
  547.             sleep(WAIT_Q, (long)shutdown);
  548.         } while (curproc->wait_cond == (long)shutdown);
  549.     }
  550. }
  551.  
  552. #ifdef __GNUC__
  553. int
  554. main(argc, argv, envp)
  555.     int argc;
  556.     char **argv, **envp;
  557. #else
  558. int
  559. main(argc, argv)
  560.     int argc;
  561.     char **argv;
  562. #endif
  563. {
  564.     long *sysbase;
  565.     long r;
  566.     extern int debug_level, debug_logging;    /* in debug.c */
  567.     extern int no_mem_prot;        /* memprot.c */
  568.     extern const char *greet1, *greet2;
  569.                     /* welcome.c */
  570.     static char buf[SPRINTF_MAX];
  571.     static char curpath[128];
  572.     long yn;
  573.     FILEPTR *f;
  574.  
  575. /* figure out what kind of machine we're running on */
  576. /* biosfs wants to know this; also sets no_mem_prot */
  577. /* 920625 kbad put it here so memprot_warning can be intelligent */
  578.     (void)Supexec(getmch);
  579. #ifdef ONLY030
  580.     if (mcpu != 30) {
  581.         Cconws("\r\nThis version of MiNT requires a 68030.\r\n");
  582.         Cconws("Hit any key to continue.\r\n");
  583.         (void)Cconin();
  584.         Pterm0();
  585.     }
  586. #endif
  587.  
  588. #ifdef MULTITOS
  589. /* Ask the user if s/he wants to boot MultiTOS or regular TOS */
  590.     if ((Kbshift(-1) & MAGIC_SHIFT) == MAGIC_SHIFT) {
  591.         yn = boot_kernel_p();
  592.         Cconws("\r\n");
  593.         if (!yn)
  594.             Pterm0();
  595.     }
  596. #else
  597. /* Allow the user to abort the boot if the magic combination of shift keys
  598.  * is held down (see MAGIC_SHIFT above)
  599.  */
  600.     if ((Kbshift(-1) & MAGIC_SHIFT) == MAGIC_SHIFT) {
  601.         Cconws("Boot MiNT? (y/n) ");
  602.         yn = Cconin() & 0x7f;
  603.         if (yn != 'y' && yn != 'Y') {
  604.             Cconws("\r\n\r\nMiNT not booted, at user's request.\r\n");
  605.             Pterm0();
  606.         }
  607.     }
  608. #endif
  609.  
  610.     if (argv[0][0] == 0) {    /* maybe started from the desktop */
  611.         curs_off = 1;
  612.     }
  613.  
  614.     yn = 0; /* by default, don't print basepage */
  615.     --argc, ++argv;
  616.     while (argc && **argv == '-') {
  617.         if (argv[0][1] >= '0' && argv[0][1] <= '9') {
  618.         /* a number sets out_device to that device */
  619.             extern int out_device;
  620.             out_device = (int)atol(&argv[0][1]);
  621.         }
  622.         else if (argv[0][1] == 'b') {
  623.         /* print MiNT basepage */
  624.             yn++;
  625.         }
  626.         else if (argv[0][1] == 'd') {
  627.         /* -d increases debugging level */
  628.             debug_level++;
  629.         }
  630.         else if (argv[0][1] == 'm' || argv[0][1] == 'p') {
  631.             int givenotice = (argv[0][2] != 'w');
  632.         /* -m and -p turn off memory protection */
  633.         extern const char *memprot_notice, *memprot_warning;
  634.             if (no_mem_prot) {
  635.                 if (givenotice)
  636.                 Cconws(memprot_notice);
  637.             }
  638.             else {
  639.                 no_mem_prot = 1;
  640.                 if (givenotice)
  641.                 Cconws(memprot_warning);
  642.             }
  643.         }
  644.         else if (argv[0][1] == 'l') {
  645.         /* -l turns on debug logging */
  646.             debug_logging = 1;
  647.         }
  648.         else {
  649.             Cconws("Unknown argument (ignored): ");
  650.             Cconws(*argv);
  651.             Cconws("\r\n");
  652.         }
  653.         ++argv, --argc;
  654.     }
  655.     if (argc) {
  656.         Cconws("Unknown argument ignored: ");
  657.         Cconws(*argv);
  658.         Cconws(" (and all the rest)\r\n");
  659.         }
  660.  
  661. /* greetings */
  662.     Cconws(greet1);
  663.     ksprintf(buf, VERS_STRING, MAJ_VERSION, MIN_VERSION);
  664.     Cconws(buf);
  665.     Cconws(greet2);
  666.  
  667. #ifdef __TURBOC__
  668.     Cconws("PRELIMINARY PureC compiled version!\r\n");
  669. #endif
  670.  
  671.     if (yn)
  672.     {
  673.             ksprintf(buf,"MiNT@%lx\r\nhit a key...",_base);
  674.         Cconws(buf);
  675.         (void)Crawcin();
  676.         Cconws("\r\033K");
  677.     }
  678.  
  679. #ifdef notdef
  680. /* if less than 1 megabyte free, turn off memory protection */
  681.     if (Mxalloc(-1L, 3) < ONE_MEG && !no_mem_prot) {
  682.         extern const char *insuff_mem_warning;
  683.         Cconws(insuff_mem_warning);
  684.         no_mem_prot = 1;
  685.     }
  686. #endif
  687.  
  688. /* look for ourselves as \AUTO\MINTNP.PRG; if so, we turn memory
  689.  * protection off
  690.  */
  691.     if (!no_mem_prot && Fsfirst("\\AUTO\\MINTNP.PRG",0) == 0)
  692.         no_mem_prot = 1;
  693.  
  694. /* check for GEM -- this must be done from user mode */
  695.     gem_active = check_for_gem();
  696.  
  697. /*
  698.  * get the current directory, so that we can switch back to it after
  699.  * the file systems are properly initialized
  700.  */
  701. /* set the current directory for the current process */
  702.     (void)Dgetpath(curpath, 0);
  703.  
  704.     tosssp = (long)Super(0L);    /* enter supervisor mode */
  705.  
  706. /* get GEMDOS pointer to current basepage */
  707. /* 0x4f2 points to the base of the OS; here we can find the OS compilation
  708.    date, and (in newer versions of TOS) where the current basepage pointer
  709.    is kept; in older versions of TOS, it's at 0x602c
  710.  */
  711.     sysbase = *((long **)(0x4f2L));    /* gets the RAM OS header */
  712.     sysbase = (long *)sysbase[2];    /* gets the ROM one */
  713.  
  714.     tosvers = (int)(sysbase[0] & 0x0000ffff);
  715.     if (tosvers == 0x100) {
  716.         if ((sysbase[7] & 0xfffe0000L) == 0x00080000L)
  717.             tosbp = (BASEPAGE **)0x873cL;    /* SPANISH ROM */
  718.         else
  719.             tosbp = (BASEPAGE **) 0x602cL;
  720.         kbshft = (char *) 0x0e1bL;
  721.     } else {
  722.         tosbp = (BASEPAGE **) sysbase[10];
  723.         kbshft = (char *) sysbase[9];
  724.     }
  725.  
  726. /* The TT TOS release notes are wrong... this is the real way to test
  727.  * for Bconmap ability
  728.  */
  729.     has_bconmap = (Bconmap(0) == 0);
  730.  
  731. /* initialize memory */
  732.     init_mem();
  733.  
  734. /* initialize the basic file systems */
  735.     init_filesys();
  736.  
  737. /* initialize processes */
  738.     init_proc();
  739.  
  740. /* initialize system calls */
  741.     init_dos();
  742.     init_bios();
  743.     init_xbios();
  744.  
  745. /* NOTE: there's a call to kmalloc embedded in install_cookies, which
  746.  * is called by init_intr; so make sure this is the last of the
  747.  * init_* things called!
  748.  */
  749.     init_intr();
  750.     enter_kernel();
  751.  
  752.     if (!gem_active) {
  753. /* make MiNT invisible in the basepage chain, so that
  754.  * programs that rely on a certain basepage chain
  755.  * structure to determine whether or not they were run
  756.  * from the desktop will have a better chance of working.
  757.  * NOTE THAT THIS IS ONLY DONE TO HELP OUT BRAIN-DAMAGED
  758.  * SOFTWARE: do *not* try counting basepages to figure
  759.  * out whether or not you were run from the desktop!!!
  760.  */
  761.         rootproc->base = _base->p_parent;
  762.     }
  763.  
  764. /* set up standard file handles for the current process
  765.  * do this here, *after* init_intr has set the Rwabs vector,
  766.  * so that AHDI doesn't get upset by references to drive U:
  767.  */
  768.     f = do_open("U:\\DEV\\CONSOLE", O_RDWR, 0, (XATTR *)0);
  769.     if (!f) {
  770.         FATAL("unable to open CONSOLE device");
  771.     }
  772.     curproc->control = f;
  773.     curproc->handle[0] = f;
  774.     curproc->handle[1] = f;
  775.     f->links = 3;
  776.  
  777.     f = do_open("U:\\DEV\\MODEM1", O_RDWR, 0, (XATTR *)0);
  778.     curproc->aux = f;
  779.     if (has_bconmap) {
  780.     /* If someone has already done a Bconmap call, then
  781.      * MODEM1 may no longer be the default
  782.      */
  783.         bconmap(curbconmap);
  784.         f = curproc->aux;    /* bconmap can change curproc->aux */
  785.     }
  786.     if (f) {
  787.         curproc->handle[2] = f;
  788.         f->links++;
  789.     }
  790.     f = do_open("U:\\DEV\\CENTR", O_RDWR, 0, (XATTR *)0);
  791.     if (f) {
  792.         curproc->handle[3] = curproc->prn = f;
  793.         f->links = 2;
  794.     }
  795.     if (f) {
  796.         f = do_open("U:\\DEV\\MIDI", O_RDWR, 0, (XATTR *)0);
  797.         curproc->midiin = curproc->midiout = f;
  798.         f->links = 2;
  799.     }
  800.  
  801. /* load external file systems */
  802.     if (*curpath) {
  803.         (void)d_setpath(curpath);
  804.     }
  805.     
  806. #ifndef PROFILING
  807. /* load_filesys causes media changes :-( */
  808.     load_filesys();
  809. #endif
  810.  
  811. /* note that load_filesys changed the
  812.  * directory on us!!
  813.  */
  814.     if (*curpath) {
  815.         (void)d_setpath(curpath);
  816.     }
  817.     
  818. /* load the configuration file */
  819.     load_config();
  820.  
  821.     *((long *)0x4c2L) |= PSEUDODRVS;
  822.  
  823.     if (init_env == 0)
  824.         init_env = (char *)_base->p_env;
  825.  
  826. /* empty environment? Set the PATH variable to the root of the current drive */
  827.     if (init_env[0] == 0) {
  828.         static char path_env[] = "PATH=\0C:\0";
  829.         path_env[6] = curproc->curdrv + 'A';
  830.         init_env = path_env;
  831.     }
  832.  
  833. /* if we are MultiTOS, we're running in the AUTO folder, and our INIT is
  834.  * called GEM.SYS, take the exec_os() vector
  835.  */
  836.     if (!gem_active && init_is_gemsys) {
  837.         xbra_install(&old_execos, EXEC_OS, (long ARGS_ON_STACK (*)())do_exec_os);
  838.     }
  839.  
  840. /* run any programs appearing after us in the AUTO folder */
  841.     run_auto_prgs();
  842.  
  843. /* run the initial program */
  844. /* if that program is in fact GEM, we start it via exec_os, otherwise
  845.  * we do it with Pexec.
  846.  * the logic is: if the user specified init_prg, and it is not
  847.  * a gem.sys file, then we try to execute it; if it *is* a gem.sys
  848.  * file, we try to execute it if gem is already active, otherwise
  849.  * we jump through the exec_os vector (which we grabbed above) in
  850.  * order to start it. We *never* go through exec_os if we're not in
  851.  * the AUTO folder.
  852.  */
  853.     if (init_prg && (!init_is_gemsys || gem_active)) {
  854.         r = p_exec(0, (char *)init_prg, init_tail, init_env);
  855.     } else if (!gem_active) {   
  856.         BASEPAGE *bp; int pid;
  857.         bp = (BASEPAGE *)p_exec(7, (char *)7L, (char *)"\0", init_env);
  858.         bp->p_tbase = *((long *) EXEC_OS );
  859.         r = p_exec(106, (char *)"GEM", bp, 0L);
  860.         pid = (int)r;
  861.         if (pid > 0) {
  862.             do {
  863.                 r = p_wait3(0, (long *)0);
  864.             } while(pid != ((r & 0xffff0000L) >> 16));
  865.             r &= 0x0000ffff;
  866.         }
  867.     } else {
  868. Cconws("If MiNT is run after GEM starts, you must specify a program\r\n");
  869. Cconws("to run initially in MINT.CNF, with an INIT= line\r\n");
  870.             r = 0;
  871.     }
  872.  
  873.     if (r < 0 && init_prg) {
  874.         ksprintf(buf, "FATAL: couldn't run %s\r\n", init_prg);
  875.         Cconws(buf);
  876.     }
  877.  
  878.     if (r) {
  879.         ksprintf(buf, "exit code: %ld\r\n", r);
  880.         Cconws(buf);
  881.     }
  882.  
  883.     rootproc->base = _base;
  884.  
  885. /* shut down all processes gracefully */
  886.     shutdown();
  887.  
  888. /* put everything back and exit */
  889.     if (!gem_active && init_is_gemsys) {
  890.     /* we stole exec_os above */
  891.         *((long *)EXEC_OS) = (long)old_execos.next;
  892.     }
  893.     restr_intr();
  894.     close_filesys();
  895.  
  896.     (void)Super((void *)tosssp);    /* gratuitous (void *) for Lattice */
  897.     Cconws("leaving MiNT\r\n");
  898.  
  899.     if (curs_off)
  900.         Cconws("\033f");    /* disable cursor */
  901.  
  902.     return 0;
  903. }
  904.  
  905.  
  906. /*
  907.  * cookie jar handling routines. The "cookie jar" is an area of memory
  908.  * reserved by TOS for TSR's and utility programs; the idea is that
  909.  * you put a cookie in the jar to notify people of available services.
  910.  * The BIOS uses the cookie jar in TOS 1.6 and higher; for earlier versions
  911.  * of TOS, the jar is always empty (unless someone added a cookie before
  912.  * us; POOLFIX does, for example).
  913.  * MiNT establishes an entirely new cookie jar (with the old cookies copied
  914.  * over) and frees it on exit. That's because TSR's run under MiNT
  915.  * will no longer be accessible after MiNT exits.
  916.  * MiNT also puts a cookie in the jar, with tag field 'MiNT' (of course)
  917.  * and with the major version of MiNT in the high byte of the low word,
  918.  * and the minor version in the low byte.
  919.  */
  920.  
  921. void
  922. install_cookies()
  923. {
  924.     COOKIE *cookie;
  925.     int i, ncookies;
  926.     long ncsize;
  927.  
  928.     /* note that init_intr sets oldcookie to the old cookie jar */
  929.  
  930.     ncookies = 0;
  931.     cookie = oldcookie;
  932.     if (cookie) {
  933.         while (cookie->tag.aslong != 0) {
  934.         /* check for true FPU co-processor */
  935.             if (!strncmp(cookie->tag.aschar, "_FPU",4) &&
  936.                  (cookie->value >> 16) >= 2)
  937.                 fpu = 1;
  938.         /* check for _FLK cookie */
  939.             else if (!strncmp(cookie->tag.aschar, "_FLK",4))
  940.                 flk = 1;
  941.             cookie++; ncookies++;
  942.         }
  943.     }
  944.  
  945.     /*
  946.      * We allocate the cookie jar in global memory so anybody can read
  947.      * it or write it. This code allocates at least 8 more cookies, and
  948.      * then rounds up to a QUANTUM boundary (that's what ROUND does). 
  949.      * Probably, nobody will have to allocate another cookie jar :-)
  950.      */
  951.  
  952.     /* NOTE: obviously, we can do this only if init_intr is called
  953.      * _after_ memory, processes, etc. have been initialized
  954.      */
  955.     ncsize = (ncookies+8)*sizeof(COOKIE);
  956.     ncsize = ROUND(ncsize);
  957.     newcookie = (COOKIE *)alloc_region(core, ncsize, PROT_G);
  958.  
  959. /* copy the old cookies to the new jar */
  960.  
  961.     for (i = 0; i < ncookies; i++) {
  962.         newcookie[i] = oldcookie[i];
  963.     }
  964.  
  965. /* install MiNT cookie */
  966.     strncpy(newcookie[i].tag.aschar, "MiNT", 4);
  967.     newcookie[i].value = (MAJ_VERSION << 8) | MIN_VERSION;
  968.     i++;
  969.  
  970. /* install _FLK cookie to indicate that file locking works */
  971.     if (!flk) {
  972.         strncpy(newcookie[i].tag.aschar, "_FLK", 4);
  973.         newcookie[i].value = 0;
  974.         i++;
  975.     }
  976.  
  977. /* the last cookie should have a 0 tag, and a value indicating the number
  978.  * of slots, total
  979.  */
  980.  
  981.     newcookie[i].tag.aslong = 0;
  982.     newcookie[i].value = ncsize/sizeof(COOKIE);
  983.  
  984.     *CJAR = newcookie;
  985.  
  986. }
  987.  
  988. /*
  989.  * Get the value of the _MCH cookie, if one exists; also set no_mem_prot if
  990.  * there's a _CPU cookie and you're not on an '030, or if there is none.
  991.  * This must be done in a separate routine because the machine type and CPU
  992.  * type are needed when initializing the system, whereas install_cookies is
  993.  * not called until everything is practically up.
  994.  * In fact, getmch() should be called before *anything* else is
  995.  * initialized, so that if we find a MiNT cookie already in the
  996.  * jar we can bail out early and painlessly.
  997.  */
  998.  
  999. static long
  1000. getmch()
  1001. {
  1002.     COOKIE *jar;
  1003.     int foundcpu = 0;
  1004.     int i;
  1005.     long *sysbase;
  1006.     extern int no_mem_prot;
  1007.  
  1008.     mcpu = 0;
  1009.     jar = *CJAR;    /* CJAR defined in cookie.h */
  1010.     if (jar) {
  1011.         while (jar->tag.aslong != 0) {
  1012.         /* check for machine type */
  1013.             if (!strncmp(jar->tag.aschar, "_MCH",4)) {
  1014.                 mch = jar->value;
  1015.             } else if (!strncmp(jar->tag.aschar, "_CPU",4)) {
  1016.                     /* if not '030 then no memory protection */
  1017.                 mcpu = jar->value;
  1018.                     if (jar->value != 30) no_mem_prot = 1;
  1019.                     foundcpu = 1;
  1020.             } else if (!strncmp(jar->tag.aschar, "_VDO",4)) {
  1021.                 FalconVideo = (jar->value == 0x00000300L);
  1022.                 if (jar->value & 0xffff0000L)
  1023.                     screen_boundary = 15;
  1024.             } else if (!strncmp(jar->tag.aschar, "MiNT",4)) {
  1025.                 Cconws("MiNT is already installed!!\r\n");
  1026.                 Pterm(2);
  1027.             } else if (!strncmp(jar->tag.aschar, "_AKP",4)) {
  1028.                 gl_lang = (int) ((jar->value >> 8) & 0x00ff);
  1029.             }
  1030.             jar++;
  1031.         }
  1032.     }
  1033.     if (!foundcpu) no_mem_prot = 1;
  1034. /*
  1035.  * if no preference found, look at the country code to decide
  1036.  */
  1037.     if (gl_lang < 0) {
  1038.         sysbase = *((long **)(0x4f2L)); /* gets the RAM OS header */
  1039.         sysbase = (long *)sysbase[2];    /* gets the ROM one */
  1040.         i = (int) ((sysbase[7] & 0x7ffe0000L) >> 17L);
  1041.         switch(i) {
  1042.         case 1:        /* Germany */
  1043.         case 8:        /* Swiss German */
  1044.             gl_lang = 1;
  1045.             break;
  1046.         case 2:        /* France */
  1047.         case 7:        /* Swiss French */
  1048.             gl_lang = 2;
  1049.             break;
  1050.         case 4:        /* Spain */
  1051.             gl_lang = 4;
  1052.             break;
  1053.         case 5:        /* Italy */
  1054.             gl_lang = 5;
  1055.             break;
  1056.         default:
  1057.             gl_lang = 0;
  1058.             break;
  1059.         }
  1060.     }
  1061.     
  1062.     return 0L;
  1063. }
  1064.  
  1065. /*
  1066.  * routines for reading the configuration file
  1067.  * we allow the following commands in the file:
  1068.  * # anything        -- comment
  1069.  * INIT=file        -- specify boot program
  1070.  * CON=file        -- specify initial file/device for handles -1, 0, 1
  1071.  * PRN=file        -- specify initial file for handle 2
  1072.  * BIOSBUF=[yn]        -- if 'n' or 'N' then turn off BIOSBUF feature
  1073.  * DEBUG_LEVEL=n    -- set debug level to (decimal number) n
  1074.  * DEBUG_DEVNO=n    -- set debug device number to (decimal number) n
  1075.  * HARDSCROLL=n        -- set hard-scroll size to n, range 0-99.
  1076.  * SLICES=nnn        -- set multitasking granularity
  1077.  * echo message        -- print a message on the screen
  1078.  * alias drive path    -- make a fake drive pointing at a path
  1079.  * cd dir        -- change directory/drive
  1080.  * exec cmd args    -- execute a program
  1081.  * setenv name val    -- set up environment
  1082.  * sln file1 file2    -- create a symbolic link
  1083.  * ren file1 file2    -- rename a file
  1084.  *
  1085.  * BUG: if you use setenv in mint.cnf, *none* of the original environment
  1086.  * gets passed to children. This is rarely a problem if mint.prg is
  1087.  * in the auto folder.
  1088.  */
  1089.  
  1090. extern short bconbdev, bconbsiz;    /* from bios.c */
  1091.  
  1092. static void
  1093. doset(name, val)
  1094.     char *name, *val;
  1095. {
  1096.     char *t;
  1097.  
  1098.     if (!strcmp(name, "GEM")) {
  1099.         init_is_gemsys = 1;
  1100.         goto setup_init;
  1101.     } 
  1102.     if (!strcmp(name, "INIT")) {
  1103.         init_is_gemsys = 0;
  1104. setup_init:
  1105.         t = kmalloc(strlen(val)+1);
  1106.         if (!t) return;
  1107.         strcpy(t, val);
  1108.         init_prg = t;
  1109.         while (*t && !isspace(*t)) t++;
  1110. /* get the command tail, too */
  1111.         if (*t) {
  1112.             *t++ = 0;
  1113.             strncpy(init_tail+1, t, 125);
  1114.             init_tail[126] = 0;
  1115.             init_tail[0] = strlen(init_tail+1);
  1116.         }
  1117.         return;
  1118.     }
  1119.     if (!strcmp(name, "CON")) {
  1120.         FILEPTR *f;
  1121.         int i;
  1122.  
  1123.         f = do_open(val, O_RDWR, 0, (XATTR *)0);
  1124.         if (f) {
  1125.             for (i = -1; i < 2; i++) {
  1126.                 do_close(curproc->handle[i]);
  1127.                 curproc->handle[i] = f;
  1128.                 f->links++;
  1129.             }
  1130.             f->links--;    /* correct for overdoing it */
  1131.         }
  1132.         return;
  1133.     }
  1134.     if (!strcmp(name, "PRN")) {
  1135.         FILEPTR *f;
  1136.  
  1137.         f = do_open(val, O_RDWR|O_CREAT|O_TRUNC, 0, (XATTR *)0);
  1138.         if (f) {
  1139.             do_close(curproc->handle[2]);
  1140.             do_close(curproc->prn);
  1141.             curproc->prn = curproc->handle[2] = f;
  1142.             f->links = 2;
  1143.         }
  1144.         return;
  1145.     }
  1146.     if (!strcmp(name, "BIOSBUF")) {
  1147.         if (*val == 'n' || *val == 'N') {
  1148.             if (bconbsiz) bflush();
  1149.             bconbdev = -1;
  1150.         }
  1151.         return;
  1152.     }
  1153.     if (!strcmp(name, "DEBUG_LEVEL")) {
  1154.         extern int debug_level;
  1155.         if (*val >= '0' && *val <= '9')
  1156.             debug_level = (int)atol(val);
  1157.         else ALERT("Bad arg to \"DEBUG_LEVEL\" in cnf file");
  1158.         return;
  1159.     }
  1160.     if (!strcmp(name, "DEBUG_DEVNO")) {
  1161.         extern int out_device;
  1162.         if (*val >= '0' && *val <= '9')
  1163.             out_device= (int)atol(val);
  1164.         else ALERT("Bad arg to \"DEBUG_DEVNO\" in cnf file");
  1165.         return;
  1166.     }
  1167.  
  1168. #ifdef FASTTEXT
  1169.     if (!strcmp(name, "HARDSCROLL")) {
  1170.         int i;
  1171.         extern int hardscroll;
  1172.  
  1173.         if (!strcmp(val, "AUTO")) {
  1174.             hardscroll = -1;
  1175.             return;
  1176.         }
  1177.         i = *val++;
  1178.         if (i < '0' || i > '9') return;
  1179.         hardscroll = i-'0';
  1180.         i = *val;
  1181.         if (i < '0' || i > '9') return;
  1182.         hardscroll = 10*hardscroll + i - '0';
  1183.         return;
  1184.     }
  1185. #endif
  1186.     if (!strcmp(name, "MAXMEM")) {
  1187.         long r;
  1188.  
  1189.         r = atol(val) * 1024L;
  1190.         if (r > 0)
  1191.             p_setlimit(2, r);
  1192.         return;
  1193.     }
  1194.     if (!strcmp(name, "SLICES")) {
  1195.         extern short time_slice;
  1196.  
  1197.         time_slice = atol(val);
  1198.         return;
  1199.     }
  1200.  
  1201.     if (!strcmp(name, "PSEUDODRIVES")) {
  1202.         FORCE("PSEUDODRIVES= no longer supported");
  1203.         return;
  1204.     }
  1205.     FORCE("Unknown variable `%s'", name);
  1206. }
  1207.  
  1208. /* Execute a line from the config file */
  1209. static void
  1210. do_line(line)
  1211.     char *line;
  1212. {
  1213.     char *cmd, *arg1, *arg2;
  1214.     char *newenv;
  1215.     char *t;
  1216.     int i;
  1217.  
  1218.     while (*line == ' ') line++;
  1219.     if (*line == '#') return;    /* ignore comments */
  1220.     if (!*line) return;        /* and also blank lines */
  1221.  
  1222.     cmd = line;
  1223. /* check for variable assignments (e.g. INIT=, etc.) */
  1224. /*
  1225.  * AGK: note we check for spaces whilst scanning so that an environment
  1226.  * variable may include an =, this has the unfortunate side effect that
  1227.  * the '=' _has_ to be concatenated to the variable name (INIT etc.)
  1228.  */
  1229.     for (t = cmd; *t && *t != ' '; t++) {
  1230.         if (*t == '=') {
  1231.             *t++ = 0;
  1232.             doset(cmd, t);
  1233.             return;
  1234.         }
  1235.     }
  1236.  
  1237. /* OK, assume a regular command; break it up into 'cmd', 'arg1', arg2' */
  1238.  
  1239.     while (*line && *line != ' ') line++;
  1240.     if (*line == ' ') {
  1241.         *line++ = 0;
  1242.         while (*line == ' ') line++;
  1243.     }
  1244.  
  1245.     if (!strcmp(cmd, "echo")) {
  1246.         c_conws(line); c_conws("\r\n");
  1247.         return;
  1248.     }
  1249.     arg1 = line;
  1250.     while (*line && *line != ' ') line++;
  1251.     if (*line) {
  1252.         *line++ = 0;
  1253.         while (*line == ' ') line++;
  1254.     }
  1255.     if (!strcmp(cmd, "cd")) {
  1256.         int drv;
  1257.         (void)d_setpath(arg1);
  1258.         drv = toupper(*arg1) - 'A';
  1259.         if (arg1[1] == ':') (void)d_setdrv(drv);
  1260.         return;
  1261.     }
  1262.     if (!strcmp(cmd, "exec")) {
  1263.         char cmdline[128];
  1264.         int i;
  1265.  
  1266.         i = strlen(line);
  1267.         if (i > 126) i = 126;
  1268.         cmdline[0] = i;
  1269.         strncpy(cmdline+1, line, i);
  1270.         cmdline[i+1] = 0;
  1271.         i = (int)p_exec(0, arg1, cmdline, init_env);
  1272.         if (i == -33) {
  1273.             FORCE("%s: file not found", arg1);
  1274.         } else if (i < 0) {
  1275.             FORCE("%s: error while attempting to execute", arg1);
  1276.         }
  1277.         return;
  1278.     }
  1279.     if (!strcmp(cmd, "setenv")) {
  1280.         if (strlen(arg1) + strlen(line) + 4 + (env_ptr - init_env) >
  1281.                              env_len) {
  1282.             long j;
  1283.  
  1284.             env_len += 1024;
  1285.             newenv = (char *)m_xalloc(env_len, 0x13);
  1286.             if (init_env) {
  1287.                 t = init_env;
  1288.                 j = env_ptr - init_env;
  1289.                 env_ptr = newenv;
  1290.                 for (i = 0; i < j; i++)
  1291.                     *env_ptr++ = *t++;
  1292.                 if (init_env)
  1293.                     m_free((virtaddr)init_env);
  1294.             } else {
  1295.                 env_ptr = newenv;
  1296.             }
  1297.             init_env = newenv;
  1298.         }
  1299.         while (*arg1) {
  1300.             *env_ptr++ = *arg1++;
  1301.         }
  1302.         *env_ptr++ = '=';
  1303.         while (*line) {
  1304.             *env_ptr++ = *line++;
  1305.         }
  1306.         *env_ptr++ = 0;
  1307.         *env_ptr = 0;
  1308.         return;
  1309.     }
  1310.  
  1311.     arg2 = line;
  1312.     while (*line && *line != ' ') line++;
  1313.     if (*line) {
  1314.         *line = 0;
  1315.     }
  1316.     if (!strcmp(cmd, "alias")) {
  1317.         int drv;
  1318.         long r;
  1319.         fcookie root_dir;
  1320.         extern int aliasdrv[];
  1321.  
  1322.         drv = toupper(*arg1) - 'A';
  1323.         if (drv < 0 || drv >= NUM_DRIVES) {
  1324.             ALERT("Bad drive (%c:) in alias", drv+'A');
  1325.             return;
  1326.         }
  1327.         r = path2cookie(arg2, NULL, &root_dir);
  1328.         if (r) {
  1329.             ALERT("alias: TOS error %ld while looking for %s",
  1330.                 r, arg2);
  1331.             return;
  1332.         }
  1333.         aliasdrv[drv] = root_dir.dev + 1;
  1334.         *((long *)0x4c2L) |= (1L << drv);
  1335.         release_cookie(&curproc->curdir[drv]);
  1336.         dup_cookie(&curproc->curdir[drv], &root_dir);
  1337.         release_cookie(&curproc->root[drv]);
  1338.         curproc->root[drv] = root_dir;
  1339.         return;
  1340.     }
  1341.     if (!strcmp(cmd, "sln")) {
  1342.         (void)f_symlink(arg1, arg2);
  1343.         return;
  1344.     }
  1345.     if (!strcmp(cmd, "ren")) {
  1346.         (void)f_rename(0, arg1, arg2);
  1347.         return;
  1348.     }
  1349.     FORCE("syntax error in mint.cnf near: %s", cmd);
  1350. }
  1351.  
  1352. #define BUF 512
  1353. #define LINE 256
  1354.  
  1355. void
  1356. load_config()
  1357. {
  1358.     int fd;
  1359.     long r;
  1360.     char buf[BUF+1], c;
  1361.     char line[LINE+1];
  1362.     char *from;
  1363.     int count = 0;
  1364.  
  1365.     fd = (int) f_open("mint.cnf", 0);
  1366.     if (fd < 0)
  1367.         fd = (int) f_open("\\mint\\mint.cnf", 0);
  1368.     if (fd < 0)
  1369.         fd = (int) f_open("\\multitos\\mint.cnf", 0);
  1370.     if (fd < 0) return;
  1371.     buf[BUF] = 0;
  1372.     from = &buf[BUF];
  1373.     line[LINE] = 0;
  1374.  
  1375.     for(;;) {
  1376.         c = *from++;
  1377.         if (!c) {
  1378.             r = f_read(fd, (long)BUF, buf);
  1379.             if (r <= 0) break;
  1380.             buf[r] = 0;
  1381.             from = buf;
  1382.         } else if (c == '\r') {
  1383.             continue;
  1384.         } else if (c == '\n') {
  1385.             line[count] = 0;
  1386.             do_line(line);
  1387.             count = 0;
  1388.         } else {
  1389.             if (count < LINE) {
  1390.                 line[count++] = c;
  1391.             }
  1392.         }
  1393.     }
  1394.     if (count) {
  1395.         line[count] = 0;
  1396.         do_line(line);
  1397.     }
  1398.     f_close(fd);
  1399. }
  1400.  
  1401. /*
  1402.  * run programs in the AUTO folder that appear after MINT.PRG
  1403.  * some things to watch out for:
  1404.  * (1) make sure GEM isn't active
  1405.  * (2) make sure there really is a MINT.PRG in the auto folder
  1406.  */
  1407.  
  1408. /*
  1409.  * some global variables used to see if GEM is active
  1410.  */
  1411. static short aes_intout[64];
  1412. static short aes_dummy[64];
  1413. static short aes_globl[15];
  1414. static short aes_cntrl[6] = { 10, 0, 1, 0, 0 };
  1415.  
  1416. short *aes_pb[6] = { aes_cntrl, aes_globl, aes_dummy, aes_intout,
  1417.              aes_dummy, aes_dummy };
  1418.  
  1419. /* check for whether GEM is active; remember, this *must* be done in
  1420.  * user mode
  1421.  */
  1422.  
  1423. static int
  1424. check_for_gem()
  1425. {
  1426.     call_aes(aes_pb);    /* does an appl_init */
  1427.     return aes_globl[0];
  1428. }
  1429.  
  1430. static void
  1431. run_auto_prgs()
  1432. {
  1433.     DTABUF *dta;
  1434.     long r;
  1435.     static char pathspec[32] = "\\AUTO\\";
  1436.     short runthem = 0;    /* set to 1 after we find MINT.PRG */
  1437.  
  1438. /* if the AES is running, don't check AUTO */
  1439.  
  1440.     if (gem_active) {
  1441.         return;
  1442.     }
  1443.  
  1444. /* OK, now let's run through \\AUTO looking for
  1445.  * programs...
  1446.  */
  1447.     dta = (DTABUF *)f_getdta();
  1448.     r = f_sfirst("\\AUTO\\*.PRG", 0);
  1449.     while (r >= 0) {
  1450.         if (!strcmp(dta->dta_name, "MINT.PRG") ||
  1451.             !strcmp(dta->dta_name, "MINTNP.PRG"))
  1452.             runthem = 1;
  1453.         else if (runthem) {
  1454.             strcpy(pathspec+6, dta->dta_name);
  1455.             (void)p_exec(0, pathspec, (char *)"", init_env);
  1456.         }
  1457.         r = f_snext();
  1458.     }
  1459. }
  1460.