1 /*
2  * ***************************************************************************
3  * MALOC = < Minimal Abstraction Layer for Object-oriented C >
4  * Copyright (C) 1994-- Michael Holst
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * rcsid="$Id: vnm.c,v 1.20 2010/08/12 05:40:32 fetk Exp $"
21  * ***************************************************************************
22  */
23 
24 /*
25  * ***************************************************************************
26  * File:     vnm.c
27  *
28  * Purpose:  Virtual numerical machine.
29  *
30  *           In particular, this module defines an imaginary ideal
31  *           Virtual Machine for numerical codes, independent of the
32  *           underlying hardware.  All resources are provided abstractly.
33  *
34  * Notes:    The vnm library provides abstractions only for
35  *           ANSI/ISO/Standard C; no extensions are provided for.
36  *           In particular, "getenv" and "system", being almost the
37  *           only ISO C facilities for communicating with the underlying
38  *           command shell, are the only facilities provided for in
39  *           the abstraction layer.  All other facilities are layered
40  *           on top of vnm in other libraries.
41  *
42  * Author:   Michael Holst
43  * ***************************************************************************
44  */
45 
46 #include "vnm_p.h"
47 
48 VEMBED(rcsid="$Id: vnm.c,v 1.20 2010/08/12 05:40:32 fetk Exp $")
49 
50 #if defined(HAVE_UNISTD_H)
51 #   include <unistd.h>
52 #endif
53 
54 #if defined(HAVE_SYS_TYPES_H)
55 #   include <sys/types.h>
56 #endif
57 
58 #if defined(HAVE_SYS_TIME_H)
59 #   include <sys/time.h>
60 #endif
61 
62 #if defined(HAVE_SYS_TIMES_H)
63 #   include <sys/times.h>
64 #endif
65 
66 #if defined(HAVE_SYS_STAT_H)
67 #   include <sys/stat.h>
68 #endif
69 
70 #if defined(HAVE_WINSOCK_H)
71     VEXTERNC char *getcwd(char *buf, int size);
72     VEXTERNC int chdir(const char *path);
73     VEXTERNC int mkdir(const char *pathname);
74 #endif
75 
76 /* console management */
77 VPRIVATE FILE *cons[4];
78 VPRIVATE int consIni[4];
79 VPRIVATE int consRedirect = 1;
80 
81 /* timers */
82 VPRIVATE long before[VTIMERS];
83 
84 /* My unique name */
85 VPRIVATE int ioTag = -1;
86 VPRIVATE int nTags =  0;
87 
88 /* signal handler and jump data */
89 VPRIVATE int vSigInt = 0;
90 VPRIVATE int vJmpOk  = 0;
91 VPRIVATE jmp_buf vJmpBuf;
92 
93 /* sorting */
94 VPRIVATE void Vnm_qsortR(int *u, int left, int right);
95 VPRIVATE void Vnm_qsortOrdR(int *u, int *ord, int left, int right);
96 VPRIVATE void Vnm_dqsortR(double *u, int left, int right);
97 VPRIVATE void Vnm_dqsortOrdR(double *u, int *ord, int left, int right);
98 
99 /*
100  * ***************************************************************************
101  * Routine:  Vnm_sigInt, Vnm_sigIntSet, Vnm_sitIntClear
102  *           Vnm_jmpOk, Vnm_jmpOkSet, Vnm_jmpOkClear
103  *
104  * Purpose:  Signal and setjmp handling routines.
105  *
106  * Author:   Michael Holst
107  * ***************************************************************************
108  */
109 
110 /*
111  * ***************************************************************************
112  * Routine:  Vnm_sigInt
113  *
114  * Purpose:  Return the signal interupt flag.
115  *
116  * Author:   Michael Holst
117  * ***************************************************************************
118  */
Vnm_sigInt(void)119 VPUBLIC int Vnm_sigInt(void)
120 {
121      return vSigInt;
122 }
123 
124 /*
125  * ***************************************************************************
126  * Routine:  Vnm_sigIntSet
127  *
128  * Purpose:  Set the signal interrupt flag.
129  *
130  * Author:   Michael Holst
131  * ***************************************************************************
132  */
Vnm_sigIntSet(void)133 VPUBLIC void Vnm_sigIntSet(void)
134 {
135     vSigInt=1;
136 }
137 
138 /*
139  * ***************************************************************************
140  * Routine:  Vnm_sitIntClear
141  *
142  * Purpose:  Clear the signal interrupt flag.
143  *
144  * Author:   Michael Holst
145  * ***************************************************************************
146  */
Vnm_sigIntClear(void)147 VPUBLIC void Vnm_sigIntClear(void)
148 {
149     vSigInt=0;
150 }
151 
152 /*
153  * ***************************************************************************
154  * Routine:  Vnm_jmpOk
155  *
156  * Purpose:  Return the "okay-to-jump" flag.
157  *
158  * Author:   Michael Holst
159  * ***************************************************************************
160  */
Vnm_jmpOk(void)161 VPUBLIC int Vnm_jmpOk(void)
162 {
163     return vJmpOk;
164 }
165 
166 /*
167  * ***************************************************************************
168  * Routine:  Vnm_jmpOkSet
169  *
170  * Purpose:  Set the "okay-to-jump" flag.
171  *
172  * Author:   Michael Holst
173  * ***************************************************************************
174  */
Vnm_jmpOkSet(void)175 VPUBLIC void Vnm_jmpOkSet(void)
176 {
177     vJmpOk=1;
178 }
179 
180 /*
181  * ***************************************************************************
182  * Routine:  Vnm_jmpOkClear
183  *
184  * Purpose:  Clear the "okay-to-jump" flag.
185  *
186  * Author:   Michael Holst
187  * ***************************************************************************
188  */
Vnm_jmpOkClear(void)189 VPUBLIC void Vnm_jmpOkClear(void)
190 {
191     vJmpOk=0;
192 }
193 
194 /*
195  * ***************************************************************************
196  * Routine:  Vnm_signalInit
197  *
198  * Purpose:  Initialize the signal handling data structures.
199  *
200  * Author:   Michael Holst
201  * ***************************************************************************
202  */
Vnm_signalInit(void)203 VPUBLIC jmp_buf *Vnm_signalInit(void)
204 {
205     Vnm_sigIntClear();
206     Vnm_jmpOkClear();
207     Vnm_regHand();
208     return &vJmpBuf;
209 }
210 
211 /*
212  * ***************************************************************************
213  * Routine:  Vnm_regHand
214  *
215  * Purpose:  Register the signal handler with the operating system.
216  *
217  * Author:   Michael Holst
218  * ***************************************************************************
219  */
Vnm_regHand(void)220 VPUBLIC void Vnm_regHand(void)
221 {
222     VASSERT( signal(SIGINT,&Vnm_sigHand) != SIG_ERR );
223 }
224 
225 /*
226  * ***************************************************************************
227  * Routine:  Vnm_sigHand
228  *
229  * Purpose:  Handle events such as SIGINT.
230  *           We must have first been registered with "Vnm_signalInit".
231  *
232  * Author:   Michael Holst
233  * ***************************************************************************
234  */
Vnm_sigHand(int num)235 VPUBLIC void Vnm_sigHand(int num)
236 {
237 #if 0
238     Vnm_print(2,"Vnm_sigHand: caught signal=<%d>\n",num);
239 #endif
240 
241     /* re-register the interrupt handler in case it was cleared by default */
242     Vnm_regHand();
243 
244     /* FIRST: handle SIGINT for killing loops */
245     Vnm_sigIntSet();
246 
247     /* SECOND: handle SIGINT for returning to input prompt via longJmp */
248     if (Vnm_jmpOk()) {
249         Vnm_jmpOkClear();
250         longjmp(vJmpBuf, 1);
251     } else {
252         return;
253     }
254 }
255 
256 /*
257  * ***************************************************************************
258  * Routine:  Vnm_powsafe
259  *
260  * Purpose:  A safe VPOW function (avoids division by zero).
261  *
262  * Author:   Michael Holst
263  * ***************************************************************************
264  */
Vnm_powsafe(double x,double y)265 VPUBLIC double Vnm_powsafe(double x, double y)
266 {
267     if ((y < 0.) && (x < VSMALL)) {
268         return 1.0;
269     } else {
270         return VPOW( x, y );
271     }
272 }
273 
274 /*
275  * ***************************************************************************
276  * Routine:  Vnm_typeChk
277  *
278  * Purpose:  Check out the sizes of various datatypes.
279  *
280  * Author:   Michael Holst
281  * ***************************************************************************
282  */
Vnm_typeChk(void)283 VPUBLIC void Vnm_typeChk(void)
284 {
285     Vnm_print(0,"Vnm_typeChk: Asserting the following type sizes:\n");
286     Vnm_print(0,"Vnm_typeChk: SizeOf(char)          = %d (1 on 32-bit arch)\n",
287         sizeof(char));
288     Vnm_print(0,"Vnm_typeChk: SizeOf(short)         = %d (2 on 32-bit arch)\n",
289         sizeof(short));
290     Vnm_print(0,"Vnm_typeChk: SizeOf(int)           = %d (4 on 32-bit arch)\n",
291         sizeof(int));
292     Vnm_print(0,"Vnm_typeChk: SizeOf(unsigned char) = %d (1 on 32-bit arch)\n",
293         sizeof(unsigned char));
294     Vnm_print(0,"Vnm_typeChk: SizeOf(unsigned short)= %d (2 on 32-bit arch)\n",
295         sizeof(unsigned short));
296     Vnm_print(0,"Vnm_typeChk: SizeOf(unsigned int)  = %d (4 on 32-bit arch)\n",
297         sizeof(unsigned int));
298     Vnm_print(0,"Vnm_typeChk: SizeOf(float)         = %d (4 on 32-bit arch)\n",
299         sizeof(float));
300     Vnm_print(0,"Vnm_typeChk: SizeOf(double)        = %d (8 on 32-bit arch)\n",
301         sizeof(double));
302 
303     Vnm_print(0,"Vnm_typeChk: Noting also the following type sizes:\n");
304     Vnm_print(0,"Vnm_typeChk: SizeOf(long)          = %d (4 on 32-bit arch)\n",
305         sizeof(long));
306     Vnm_print(0,"Vnm_typeChk: SizeOf(unsigned long) = %d (4 on 32-bit arch)\n",
307         sizeof(unsigned long));
308     Vnm_print(0,"Vnm_typeChk: SizeOf(int*)          = %d (4 on 32-bit arch)\n",
309         sizeof(int*));
310     Vnm_print(0,"Vnm_typeChk: SizeOf(void*)         = %d (4 on 32-bit arch)\n",
311         sizeof(void*));
312     Vnm_print(0,"Vnm_typeChk: SizeOf(size_t)        = %d (4 on 32-bit arch)\n",
313         sizeof(size_t));
314 
315     VASSERT( sizeof(char)              == 1 );
316     VASSERT( sizeof(short)             == 2 );
317     VASSERT( sizeof(int)               == 4 );
318     VASSERT( sizeof(unsigned char)     == 1 );
319     VASSERT( sizeof(unsigned short)    == 2 );
320     VASSERT( sizeof(unsigned int)      == 4 );
321     VASSERT( sizeof(float)             == 4 );
322     VASSERT( sizeof(double)            == 8 );
323 
324     /* VASSERT( sizeof(long)           == 4 ); */
325     /* VASSERT( sizeof(unsigned long)  == 4 ); */
326     /* VASSERT( sizeof(int*)           == 4 ); */
327     /* VASSERT( sizeof(void*)          == 4 ); */
328     /* VASSERT( sizeof(size_t)         == 4 ); */
329 }
330 
331 /*
332  * ***************************************************************************
333  * Routine:  Vnm_epsmac
334  *
335  * Purpose:  Computes the unit roundoff of the machine in single
336  *           precision.  This is defined as the smallest positive machine
337  *           number u such that  1.0d0 + u .ne. 1.0d0 (in single precision).
338  *
339  *           A safe hardcoded machine epsilon as alternative:
340  *
341  *                double value;
342  *                value = 1.0e-9;
343  *                return value;
344  *
345  * Author:   Michael Holst
346  * ***************************************************************************
347  */
Vnm_epsmac(void)348 VPUBLIC double Vnm_epsmac(void)
349 {
350     double u, comp, value;
351     u = 1.0;
352     while (1) {
353         u = u * 0.5;
354         comp = 1.0 + u;
355         if (comp == 1.0) break;
356     }
357     value = u*2.0;
358     return value;
359 }
360 
361 /*
362  * ***************************************************************************
363  * Routine:  Vnm_gentokens
364  *
365  * Purpose:  Generate an [argv,argc] pair from a character string "buf"
366  *           (assumed NULL-terminated) in which tokens are separated by
367  *           whitespace "white" with possible comments "comment" occuring.
368  *           THE INPUT STRING IS MODIFIED HERE!
369  *
370  * Notes:    Again, the input string "buf" IS MODIFIED; white space characters
371  *           (defined in the input string "white") are replaced by the NULL
372  *           character '\0'.  The output "argv" is simply a list of pointers
373  *           to the start of the tokens in "buf", which are NULL-terminated
374  *           after we replace the white space with NULLs.
375  *
376  *           We follow convention and "NULL"-terminate "argv" by setting
377  *           the pointer following the last token to "VNULL".  The return
378  *           value is "argc", the number of tokens found (not including the
379  *           terminating NULL pointer).  For safety you must pass in the
380  *           maximal length of argv in the parameter "argvmax".
381  *
382  *           If we encounter a token which begins with a comment character
383  *           (defined in the input string "comment"), then we ignore the
384  *           rest of the tokens in the input buffer "buf".  This is suitable
385  *           for parsing shell languages such as sh/ksh/bash which have
386  *           comments that start with e.g. "#" and continue until a newline.
387  *
388  *           We DO NOT use the C library function strtok in this routine.
389  *           (There are some bad implementations of strtok around apparently;
390  *           the internal state variables maintained by strtok can get very
391  *           messed up if you use strtok in multiple places in a code.)
392  *
393  * Author:   Michael Holst
394  * ***************************************************************************
395  */
Vnm_gentokens(char * buf,char ** argv,const int argvmax,const char * white,const char * comment)396 VPUBLIC int Vnm_gentokens(char *buf, char **argv,
397     const int argvmax, const char *white, const char *comment)
398 {
399     int  i, j, ntok, state, done, bufsize;
400 
401     for (i=0; i<argvmax; i++) {
402         argv[i] = VNULL;
403     }
404     bufsize = strlen(buf);
405     VJMPERR1( buf[bufsize] == '\0' );
406     ntok = 0;
407     state = 0;
408     done = 0;
409     i=0;
410     while ((i<bufsize) && (!done)) {
411         if (strchr(comment,buf[i])) done = 1;
412         else {
413             if (!strchr(white,buf[i]) && (state==0)) {
414                 state = 1;
415                 argv[ntok] = (buf+i);
416                 ntok++;
417             }
418             if (strchr(white,buf[i])) {
419                 buf[i] = '\0';
420                 state = 0;
421             }
422             i++;
423         }
424     }
425     argv[ntok] = VNULL;
426     VJMPERR1( ntok < argvmax );
427     for (j=i; j<bufsize; j++) {
428         buf[j] = '\0';
429     }
430 
431     /* return with no errors */
432     return ntok;
433 
434   VERROR1:
435     Vnm_print(2,"Vnm_gentokens: problem with buffer management.\n");
436     return 0;
437 }
438 
439 /*
440  * ***************************************************************************
441  * Routine:  Vnm_tstart
442  *
443  * Purpose:  Starts the timer on the particular machine.
444  *
445  * Author:   Michael Holst
446  * ***************************************************************************
447  */
Vnm_tstart(int timer,const char * name)448 VPUBLIC void Vnm_tstart(int timer, const char *name)
449 {
450     VASSERT( (timer>=0) && (timer<VTIMERS) );
451     Vnm_print(0, "Vnm_tstart: starting timer %d (%s)..\n", timer, name);
452     before[timer] = clock();
453 }
454 
455 /*
456  * ***************************************************************************
457  * Routine:  Vnm_tstop
458  *
459  * Purpose:  Stops the timer on the particular machine.
460  *
461  * Author:   Michael Holst
462  * ***************************************************************************
463  */
Vnm_tstop(int timer,const char * name)464 VPUBLIC void Vnm_tstop(int timer, const char *name)
465 {
466     long after;
467     double cputme;
468 
469     VASSERT( (timer>=0) && (timer<VTIMERS) );
470     after  = clock();
471     cputme = (double)(after-before[timer]) / (double)(CLOCKS_PER_SEC);
472     Vnm_print(0, "Vnm_tstop: stopping timer %d (%s).  CPU TIME = %e\n",
473         timer, name, cputme);
474 }
475 
476 /*
477  * ***************************************************************************
478  * Routine:  Vnm_getuser
479  *
480  * Purpose:  Ask the system for the username.
481  *
482  * Author:   Michael Holst
483  * ***************************************************************************
484  */
Vnm_getuser(char * user,int usermax)485 VPUBLIC char *Vnm_getuser(char *user, int usermax)
486 {
487     char *name = VNULL;
488     VASSERT( usermax <= VMAX_ARGLEN );
489 
490     name = getenv("USER");
491     if (name != VNULL) strncpy(user,name,usermax);
492     else strncpy(user,"mcuser",usermax);
493     return user;
494 }
495 
496 /*
497  * ***************************************************************************
498  * Routine:  Vnm_getos
499  *
500  * Purpose:  Ask the system for the operating system name.
501  *
502  * Author:   Michael Holst
503  * ***************************************************************************
504  */
Vnm_getos(char * os,int osmax)505 VPUBLIC char *Vnm_getos(char *os, int osmax)
506 {
507     char *name = VNULL;
508     VASSERT( osmax <= VMAX_ARGLEN );
509 
510     name = getenv("OSTYPE");
511     if (name != VNULL) strncpy(os,name,osmax);
512     else strncpy(os,"UNIX",osmax);
513     return os;
514 }
515 
516 /*
517  * ***************************************************************************
518  * Routine:  Vnm_gethost
519  *
520  * Purpose:  Ask the system for the hostname.
521  *
522  * Author:   Michael Holst
523  * ***************************************************************************
524  */
Vnm_gethost(char * host,int hostmax)525 VPUBLIC char *Vnm_gethost(char *host, int hostmax)
526 {
527     int i, j;
528     char *name = VNULL;
529     VASSERT( hostmax <= VMAX_ARGLEN );
530 
531     name = getenv("HOSTNAME");
532     if (name != VNULL) {
533         strncpy(host,name,hostmax);
534     } else {
535         name = getenv("HOST");
536         if (name != VNULL) {
537             strncpy(host,name,hostmax);
538         } else {
539             strncpy(host,"HOST",hostmax);
540         }
541     }
542     j = (int)strlen(host);
543     for (i=0; i<j; i++) {
544         if (host[i] == '.') host[i] = '\0';
545     }
546     return host;
547 }
548 
549 /*
550  * ***************************************************************************
551  * Routine:  Vnm_gethome
552  *
553  * Purpose:  Ask the system for the home directory.
554  *
555  * Note:     The following preference order is used to set the home directory:
556  *
557  *               MCSH_HOME (the user must define this in his environment)
558  *               CWD       (always defined as the current working directory)
559  *
560  *           We consider it an error if we can't return something useful;
561  *           therefore we will VASSERT(path!=VNULL) before returning.
562  *
563  *           We settle on a home directory the first time we are called,
564  *           and then we simply return this fixed home directory forever.
565  *           In other words, the first call to Vnm_gethome, regardless of
566  *           who makes the call, establishes the home directory for everyone
567  *           else (as long as everyone goes through Vnm_gethome!).
568  *
569  * Author:   Michael Holst
570  * ***************************************************************************
571  */
Vnm_gethome(char * path,int pathmax)572 VPUBLIC char *Vnm_gethome(char *path, int pathmax)
573 {
574     char *home = VNULL;
575     static char vnmHome[VMAX_ARGLEN];
576     static int init=0;
577 
578     VASSERT( pathmax <= VMAX_ARGLEN );
579 
580     if (!init) {
581         init = 1;
582         home = getenv("MCSH_HOME");
583         if (home == VNULL) {
584             home = Vnm_getcwd(vnmHome,pathmax);
585             VASSERT( home != VNULL );
586         } else {
587             strncpy(vnmHome,home,pathmax);
588         }
589     }
590     strncpy(path,vnmHome,pathmax);
591     home = path;
592     return path;
593 }
594 
595 /*
596  * ***************************************************************************
597  * Routine:  Vnm_getcwd
598  *
599  * Purpose:  Ask the system for the current working directory.
600  *
601  * Note:     Consider it an error if we can't return something useful;
602  *           therefore we will VASSERT(path!=VNULL) before returning.
603  *
604  *           Note that unlike Vnm_gethome, a call to Vnm_getcwd returns
605  *           the current directory, possibly modified from call to call.
606  *
607  *           I.e., calls to Vnm_chdir can change the current working
608  *           directory; Vnm_getcwd returns the current directory, whatever
609  *           that me be.
610  *
611  * Author:   Michael Holst
612  * ***************************************************************************
613  */
Vnm_getcwd(char * path,int pathmax)614 VPUBLIC char *Vnm_getcwd(char *path, int pathmax)
615 {
616     char *cwd = VNULL;
617     VASSERT( pathmax <= VMAX_ARGLEN );
618 
619 #if defined(HAVE_GETCWD)
620     cwd = getcwd(path, (unsigned int)pathmax);
621 #else
622     cwd = getwd(path);
623 #endif
624 
625     VASSERT( cwd != VNULL );
626     return path;
627 }
628 
629 /*
630  * ***************************************************************************
631  * Routine:  Vnm_chdir
632  *
633  * Purpose:  Interact with the system to change the working directory.
634  *
635  * Author:   Michael Holst
636  * ***************************************************************************
637  */
Vnm_chdir(const char * path)638 VPUBLIC int Vnm_chdir(const char *path)
639 {
640     return chdir(path);
641 }
642 
643 /*
644  * ***************************************************************************
645  * Routine:  Vnm_mkdir
646  *
647  * Purpose:  Interact with the system to make a new directory.
648  *
649  * Author:   Michael Holst
650  * ***************************************************************************
651  */
Vnm_mkdir(const char * path)652 VPUBLIC int Vnm_mkdir(const char *path)
653 {
654 #if defined(HAVE_WINSOCK_H)
655     return mkdir(path);
656 #else
657     mode_t mode = 0777;
658     return mkdir(path,mode);
659 #endif
660 }
661 
662 /*
663  * ***************************************************************************
664  * Routine:  Vnm_system
665  *
666  * Purpose:  An improved ANSI-C "system" call.
667  *
668  * Author:   Michael Holst
669  * ***************************************************************************
670  */
Vnm_system(const char * cmd)671 VPUBLIC int Vnm_system(const char *cmd)
672 {
673     return system(cmd);
674 }
675 
676 /*
677  * ***************************************************************************
678  * Routine:  Vnm_systemBack
679  *
680  * Purpose:  A background variant of the ANSI-C "system" call.
681  *
682  * Author:   Michael Holst
683  * ***************************************************************************
684  */
Vnm_systemBack(const char * cmd)685 VPUBLIC int Vnm_systemBack(const char *cmd)
686 {
687     char cmdbuf[VMAX_BUFSIZE];
688 
689 #if defined(HAVE_WINSOCK_H)
690     strcpy(cmdbuf, "start /B ");
691     strcat(cmdbuf, cmd);
692 #else
693     strcpy(cmdbuf, cmd);
694     strcat(cmdbuf, " &");
695 #endif
696     return Vnm_system(cmdbuf);
697 }
698 
699 /*
700  * ***************************************************************************
701  * Routine:  Vnm_systemKill
702  *
703  * Purpose:  Something like a UNIX "killall" call.
704  *
705  * Author:   Michael Holst
706  * ***************************************************************************
707  */
Vnm_systemKill(const char * cmd)708 VPUBLIC int Vnm_systemKill(const char *cmd)
709 {
710     char cmdbuf[VMAX_BUFSIZE];
711 
712 #if defined(HAVE_WINSOCK_H)
713     strcpy(cmdbuf, "killall ");
714     strcat(cmdbuf, cmd);
715     (void)Vnm_system(cmdbuf);
716 #else
717     strcpy(cmdbuf, "killall ");
718     strcat(cmdbuf, cmd);
719     strcat(cmdbuf, "> /dev/null 2>&1");
720     (void)Vnm_system(cmdbuf);
721     strcpy(cmdbuf, "killall ./");
722     strcat(cmdbuf, cmd);
723     strcat(cmdbuf, "> /dev/null 2>&1");
724     (void)Vnm_system(cmdbuf);
725 #endif
726     return 0;
727 }
728 
729 /*
730  * ***************************************************************************
731  * Routine:  Vnm_exec
732  *
733  * Purpose:  An improved UNIX "exec" call.
734  *
735  * Notes:    This routine does not return except on error.
736  *
737  * Author:   Michael Holst
738  * ***************************************************************************
739  */
Vnm_exec(int argc,char ** argv)740 VPUBLIC int Vnm_exec(int argc, char **argv)
741 {
742 #if !defined(HAVE_WINSOCK_H)
743     if (strstr(argv[0], "/")) {
744         execv (argv[0],argv);
745     } else {
746         execvp(argv[0],argv);
747     }
748 #endif
749     /* Vnm_system("play sorry.au"); */
750 
751     return -1;
752 }
753 
754 /*
755  * ***************************************************************************
756  * Routine:  Vnm_sleep
757  *
758  * Purpose:  Implement a sleep function with microsecond resolution.
759  *
760  * Notes:    This is hacked out of the "sleep_us" example in
761  *           Rick Steven's Advance Unix Programming book.
762  *
763  * Author:   Michael Holst
764  * ***************************************************************************
765  */
Vnm_sleep(int nusecs)766 VPUBLIC void Vnm_sleep(int nusecs)
767 {
768 #if defined(HAVE_WINSOCK_H)
769 #else
770     struct timeval tval;
771     tval.tv_sec  = ((unsigned int)nusecs) / 1000000;
772     tval.tv_usec = ((unsigned int)nusecs) % 1000000;
773     select(0, VNULL, VNULL, VNULL, &tval);
774 #endif
775 }
776 
777 /*
778  * ***************************************************************************
779  * Routine:  Vnm_ioTag
780  *
781  * Purpose:  Return my I/O tag.
782  *
783  * Author:   Michael Holst
784  * ***************************************************************************
785  */
Vnm_ioTag(void)786 VPUBLIC int Vnm_ioTag(void)
787 {
788     return ioTag;
789 }
790 
791 /*
792  * ***************************************************************************
793  * Routine:  Vnm_nTags
794  *
795  * Purpose:  Return the total number of tags.
796  *
797  * Author:   Michael Holst
798  * ***************************************************************************
799  */
Vnm_nTags(void)800 VPUBLIC int Vnm_nTags(void)
801 {
802     return nTags;
803 }
804 
805 /*
806  * ***************************************************************************
807  * Routine:  Vnm_setIoTag
808  *
809  * Purpose:  Set my id.
810  *
811  * Author:   Michael Holst
812  * ***************************************************************************
813  */
Vnm_setIoTag(int myTag,int numTags)814 VPUBLIC void Vnm_setIoTag(int myTag, int numTags)
815 {
816     ioTag = myTag;
817     nTags = numTags;
818 }
819 
820 /*
821  * ***************************************************************************
822  * Routine:  Vnm_open
823  *
824  * Purpose:  Open an I/O console.
825  *
826  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
827  *
828  *           The following codes are used:
829  *
830  *           unit#      C output unit
831  *           -------    -------------
832  *
833  *           unit==0    garbage   -- Non-interactive i/o; lots of stuff
834  *                                   (can be redirected to ${MCSH_HOME/io.mc)
835  *
836  *           unit==1    stdout    -- standard output (Interactive I/O)
837  *
838  *           unit==2    stderr    -- standard error (IMPORTANT interactive I/O)
839  *
840  *           unit==3    history   -- History file ${MCSH_HOME}/hist.mcsh
841  *
842  *           unit==else /dev/null -- Error...
843  *
844  * Author:   Michael Holst
845  * ***************************************************************************
846  */
Vnm_open(const int unit)847 VPUBLIC FILE *Vnm_open(const int unit)
848 {
849     static int openIni = VFALSE;
850     int i;
851     char str[256], fname[256], apnd[256], myhome[VMAX_ARGLEN];
852     time_t now;
853 
854     if ( !((0<=unit)&&(unit<=3)) )
855         fprintf(stderr,"Vnm_open: Bad UNIT <%d> specified.\n", unit);
856 
857     /* initialize once */
858     if (!openIni) {
859         for (i=0; i<4; i++) {
860             consIni[i] = VFALSE;
861             cons[i]    = VNULL;
862         }
863         openIni = VTRUE;
864     }
865 
866     /* open the file unit */
867     if (cons[unit] == VNULL) {
868 
869         /* get a reasonable home directory for ALL file i/o (dot files, etc) */
870         VASSERT( Vnm_gethome(myhome, sizeof(myhome)) );
871 
872         /* do we need to append our id to all of the dot files */
873         if ((Vnm_ioTag() >= 0) && (Vnm_nTags() > 1)) {
874             sprintf(apnd,"_%d",Vnm_ioTag());
875         } else {
876             apnd[0] = '\0';
877         }
878 
879         if (unit == 0) {
880             if (consRedirect) {
881                 sprintf(fname,"%s/%s%s",myhome,"io.mc",apnd);
882                 if (!consIni[unit]) {
883                     cons[unit]=fopen( fname, "a" /*"w"*/ );
884                 } else {
885                     cons[unit]=fopen( fname, "a" );
886                 }
887             } else {
888                 cons[unit] = stderr;
889             }
890         } else if (unit == 1) {
891             cons[unit] = stdout;
892         } else if (unit == 2) {
893             cons[unit] = stderr;
894         } else if (unit == 3) {
895             sprintf(fname,"%s/%s%s",myhome,"hist.mcsh",apnd);
896             if (!consIni[unit]) {
897                 cons[unit]=fopen(fname, "a" /*"w"*/);
898             } else {
899                 cons[unit]=fopen(fname, "a");
900             }
901         } else fprintf(stderr,"Vnm_open: Bad UNIT <%d> specified.\n", unit);
902 
903         /* Write some info for the first line in the file (if not stdout). */
904         if (!consIni[unit]) {
905             if ( cons[unit] != VNULL ) {
906                 consIni[unit] = VTRUE;
907                 if ((unit == 0) && (consRedirect)) {
908                     fprintf(cons[unit],"####################################"
909                         "##########################################\n");
910                     fprintf(cons[unit],"# MC-shell I/O capture file.\n");
911                     now = time(VNULL);
912                     sprintf(str,"# Creation Date and Time:  %s",ctime(&now));
913                     fprintf(cons[unit],"%s\n",str);
914                     fprintf(cons[unit],"####################################"
915                         "##########################################\n");
916                 } else if (unit == 3) {
917                     fprintf(cons[unit],"#! /bin/mcsh\n");
918                     fprintf(cons[unit],"####################################"
919                         "##########################################\n");
920                     fprintf(cons[unit],"# MC-shell history file.\n");
921                     now = time(VNULL);
922                     sprintf(str,"# Creation Date and Time:  %s",ctime(&now));
923                     fprintf(cons[unit],"%s\n",str);
924                     fprintf(cons[unit],"####################################"
925                         "##########################################\n");
926                 }
927             }
928         }
929     }
930     return cons[unit];
931 }
932 
933 /*
934  * ***************************************************************************
935  * Routine:  Vnm_close
936  *
937  * Purpose:  Close an I/O console.
938  *
939  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
940  *
941  * Author:   Michael Holst
942  * ***************************************************************************
943  */
Vnm_close(const int unit)944 VPUBLIC int Vnm_close(const int unit)
945 {
946     int retcode;
947 
948     if ( !((0<=unit)&&(unit<=3)) ) {
949         fprintf(stderr,"Vnm_close: Bad UNIT <%d> specified.\n", unit);
950     }
951 
952     if (  (cons[unit] != VNULL)
953        && (cons[unit] != stdin)
954        && (cons[unit] != stdout)
955        && (cons[unit] != stderr) ) {
956         retcode = fclose(cons[unit]);
957     } else {
958         retcode = 1;
959     }
960     cons[unit] = VNULL;
961     return retcode;
962 }
963 
964 /*
965  * ***************************************************************************
966  * Routine:  Vnm_flush
967  *
968  * Purpose:  Attempt to flush the specified i/o stream.
969  *
970  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
971  *
972  * Author:   Michael Holst
973  * ***************************************************************************
974  */
Vnm_flush(const int unit)975 VPUBLIC void Vnm_flush(const int unit)
976 {
977     if ( !((0<=unit)&&(unit<=3)) ) {
978         fprintf(stderr,"Vnm_flush: Bad UNIT <%d> specified.\n", unit);
979     }
980 
981     if (cons[unit] != VNULL) {
982         fflush(cons[unit]);
983     }
984 }
985 
986 /*
987  * ***************************************************************************
988  * Routine:  Vnm_redirect
989  *
990  * Purpose:  Set/unset the redirect flag for UNIT zero.
991  *           When redirected, I/O goes to the file: ${MCSH_HOME}/io.mc
992  *
993  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
994  *
995  * Author:   Michael Holst
996  * ***************************************************************************
997  */
Vnm_redirect(const int flag)998 VPUBLIC void Vnm_redirect(const int flag)
999 {
1000     if ( !((flag==0)||(flag==1)) ) {
1001         fprintf(stderr,"Vnm_redirect: Bad FLAG <%d> specified.\n", flag);
1002     }
1003 
1004     consRedirect = flag;
1005 }
1006 
1007 /*
1008  * ***************************************************************************
1009  * Routine:  Vnm_print
1010  *
1011  * Purpose:  External interface to the console i/o routine.
1012  *
1013  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
1014  *
1015  * Author:   Michael Holst
1016  * ***************************************************************************
1017  */
Vnm_print(const int unit,const char * format,...)1018 VPUBLIC void Vnm_print(const int unit, const char *format, ...)
1019 {
1020     va_list argList;
1021     FILE    *fp;
1022 
1023     if ( !((0<=unit)&&(unit<=3)) ) {
1024         fprintf(stderr,"Vnm_print: Bad UNIT <%d> specified.\n", unit);
1025     }
1026 
1027     fp = Vnm_open(unit);
1028     if (fp != VNULL) {
1029         va_start(argList, format);
1030         vfprintf(fp, format, argList);
1031         va_end(argList);
1032         Vnm_close(unit);
1033     }
1034     Vnm_flush(unit);
1035 }
1036 
1037 /*
1038  * ***************************************************************************
1039  * Routine:  Vnm_tprint
1040  *
1041  * Purpose:  Add our ioTag to Vnm_print output.
1042  *
1043  * Notes:    For a tag to be added, both of the following conditions
1044  *           must hold:
1045  *
1046  *               Vnm_ioTag() >= 0   (I.e., I must have been given a tag)
1047  *               Vnm_nTags() >  1   (I must not be the only one given a tag)
1048  *
1049  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
1050  *
1051  * Author:   Michael Holst
1052  * ***************************************************************************
1053  */
Vnm_tprint(const int unit,const char * format,...)1054 VPUBLIC void Vnm_tprint(const int unit, const char *format, ...)
1055 {
1056     va_list argList;
1057     FILE    *fp;
1058 
1059     if ( !((0<=unit)&&(unit<=3)) ) {
1060         if ((Vnm_ioTag() >= 0) && (Vnm_nTags() > 1)) {
1061             fprintf(stderr, "[%d] ", Vnm_ioTag());
1062         }
1063         fprintf(stderr,"Vnm_tprint: Bad UNIT <%d> specified.\n", unit);
1064     }
1065 
1066     fp = Vnm_open(unit);
1067     if (fp != VNULL) {
1068         if ((Vnm_ioTag() >= 0) && (Vnm_nTags() > 1)) {
1069             fprintf(fp, "[%d] ", Vnm_ioTag());
1070         }
1071         va_start(argList, format);
1072         vfprintf(fp, format, argList);
1073         va_end(argList);
1074         Vnm_close(unit);
1075     }
1076     Vnm_flush(unit);
1077 }
1078 
1079 /*
1080  * ***************************************************************************
1081  * Routine:  Vnm_qsort
1082  *
1083  * Purpose:  Front-end to quick sort integer array from [-large] to [+large].
1084  *
1085  * Author:   Michael Holst
1086  * ***************************************************************************
1087  */
Vnm_qsort(int * u,int size)1088 VPUBLIC void Vnm_qsort(int *u, int size)
1089 {
1090     int i, itmp;
1091 
1092     /* find largest entry; place on right for qSortRecurse */
1093     for (i=0; i<size-1; i++) {
1094         if (u[i] > u[size-1]) {
1095             itmp = u[size-1];
1096             u[size-1] = u[i];
1097             u[i] = itmp;
1098         }
1099     }
1100 
1101     /* now call qSortRecurse */
1102     Vnm_qsortR(u, 0, size-2);
1103 }
1104 
1105 /*
1106  * ***************************************************************************
1107  * Routine:  Vnm_qsortOrd
1108  *
1109  * Purpose:  Front-end to quick sort integer array from [-large] to [+large].
1110  *
1111  * Author:   Michael Holst
1112  * ***************************************************************************
1113  */
Vnm_qsortOrd(int * u,int * ord,int size)1114 VPUBLIC void Vnm_qsortOrd(int *u, int *ord, int size)
1115 {
1116     int i, itmp;
1117 
1118     /* find largest entry; place on right for qSortRecurse */
1119     for (i=0; i<size-1; i++) {
1120         if (u[i] > u[size-1]) {
1121             itmp = u[size-1];
1122             u[size-1] = u[i];
1123             u[i] = itmp;
1124             itmp = ord[size-1];
1125             ord[size-1] = ord[i];
1126             ord[i] = itmp;
1127         }
1128     }
1129 
1130     /* now call qSortRecurse */
1131     Vnm_qsortOrdR(u, ord, 0, size-2);
1132 }
1133 
1134 /*
1135  * ***************************************************************************
1136  * Routine:  Vnm_dqsort
1137  *
1138  * Purpose:  Front-end to quick sort integer array from [-large] to [+large].
1139  *
1140  * Author:   Michael Holst
1141  * ***************************************************************************
1142  */
Vnm_dqsort(double * u,int size)1143 VPUBLIC void Vnm_dqsort(double *u, int size)
1144 {
1145     int i;
1146     double tmp;
1147 
1148     /* find largest entry; place on right for qSortRecurse */
1149     for (i=0; i<size-1; i++) {
1150         if (u[i] > u[size-1]) {
1151             tmp = u[size-1];
1152             u[size-1] = u[i];
1153             u[i] = tmp;
1154         }
1155     }
1156 
1157     /* now call qSortRecurse */
1158     Vnm_dqsortR(u, 0, size-2);
1159 }
1160 
1161 /*
1162  * ***************************************************************************
1163  * Routine:  Vnm_dqsortOrd
1164  *
1165  * Purpose:  Front-end to quick sort integer array from [-large] to [+large].
1166  *
1167  * Author:   Michael Holst
1168  * ***************************************************************************
1169  */
Vnm_dqsortOrd(double * u,int * ord,int size)1170 VPUBLIC void Vnm_dqsortOrd(double *u, int *ord, int size)
1171 {
1172     int i, itmp;
1173     double tmp;
1174 
1175     /* find largest entry; place on right for qSortRecurse */
1176     for (i=0; i<size-1; i++) {
1177         if (u[i] > u[size-1]) {
1178             tmp = u[size-1];
1179             u[size-1] = u[i];
1180             u[i] = tmp;
1181             itmp = ord[size-1];
1182             ord[size-1] = ord[i];
1183             ord[i] = itmp;
1184         }
1185     }
1186 
1187     /* now call qSortRecurse */
1188     Vnm_dqsortOrdR(u, ord, 0, size-2);
1189 }
1190 
1191 /*
1192  * ***************************************************************************
1193  * Routine:  Vnm_qsortR
1194  *
1195  * Purpose:  RECURSIVE Quick sort a vector from [-large] to [+large].
1196  *
1197  * Notes:    Sorts u[left],...,u[right] in nondecreasing order.
1198  *           IMPORTANT NOTE: it is assumed that u[left] <= u[right+1]
1199  *           THEREFORE, you must have set u[right+1] to be greater than
1200  *           or equal to all entries u[0],...,u[right].
1201  *
1202  *           pivot=u[left] is arbitrarily chosen as the pivot key.
1203  *           i,j=used to partition sublist so at all times:
1204  *
1205  *                u[m] <= pivot <= u[n],   m<i, n>j.
1206  *
1207  * Author:   Michael Holst
1208  * ***************************************************************************
1209  */
Vnm_qsortR(int * u,int left,int right)1210 VPRIVATE void Vnm_qsortR(int *u, int left, int right)
1211 {
1212     int i, j, pivot, tmp;
1213     if (left < right) {
1214         i = left;
1215         j = right+1;
1216         pivot = u[left];
1217         do {
1218             do { i++; } while (u[i] < pivot);
1219             do { j--; } while (u[j] > pivot);
1220             if (i<j) {
1221                 tmp = u[i];
1222                 u[i] = u[j];
1223                 u[j] = tmp;
1224             }
1225         } while (i<j);
1226         tmp = u[left];
1227         u[left] = u[j];
1228         u[j] = tmp;
1229         Vnm_qsortR(u, left, j-1);
1230         Vnm_qsortR(u, j+1, right);
1231     }
1232 }
1233 
1234 /*
1235  * ***************************************************************************
1236  * Routine:  Vnm_qsortOrdR
1237  *
1238  * Purpose:  RECURSIVE Quick sort a vector from [-large] to [+large].
1239  *
1240  * Notes:    Sorts u[left],...,u[right] in nondecreasing order.
1241  *           IMPORTANT NOTE: it is assumed that u[left] <= u[right+1]
1242  *           THEREFORE, you must have set u[right+1] to be greater than
1243  *           or equal to all entries u[0],...,u[right].
1244  *
1245  *           pivot=u[left] is arbitrarily chosen as the pivot key.
1246  *           i,j=used to partition sublist so at all times:
1247  *
1248  *                u[m] <= pivot <= u[n],   m<i, n>j.
1249  *
1250  * Author:   Michael Holst
1251  * ***************************************************************************
1252  */
Vnm_qsortOrdR(int * u,int * ord,int left,int right)1253 VPRIVATE void Vnm_qsortOrdR(int *u, int *ord, int left, int right)
1254 {
1255     int i, j, pivot, tmp, itmp;
1256     if (left < right) {
1257         i = left;
1258         j = right+1;
1259         pivot = u[left];
1260         do {
1261             do { i++; } while (u[i] < pivot);
1262             do { j--; } while (u[j] > pivot);
1263             if (i<j) {
1264                 tmp = u[i];
1265                 u[i] = u[j];
1266                 u[j] = tmp;
1267                 itmp = ord[i];
1268                 ord[i] = ord[j];
1269                 ord[j] = itmp;
1270             }
1271         } while (i<j);
1272         tmp = u[left];
1273         u[left] = u[j];
1274         u[j] = tmp;
1275         itmp = ord[left];
1276         ord[left] = ord[j];
1277         ord[j] = itmp;
1278         Vnm_qsortOrdR(u, ord, left, j-1);
1279         Vnm_qsortOrdR(u, ord, j+1, right);
1280     }
1281 }
1282 
1283 /*
1284  * ***************************************************************************
1285  * Routine:  Vnm_dqsortR
1286  *
1287  * Purpose:  RECURSIVE Quick sort a vector from [-large] to [+large].
1288  *
1289  * Notes:    Sorts u[left],...,u[right] in nondecreasing order.
1290  *           IMPORTANT NOTE: it is assumed that u[left] <= u[right+1]
1291  *           THEREFORE, you must have set u[right+1] to be greater than
1292  *           or equal to all entries u[0],...,u[right].
1293  *
1294  *           pivot=u[left] is arbitrarily chosen as the pivot key.
1295  *           i,j=used to partition sublist so at all times:
1296  *
1297  *                u[m] <= pivot <= u[n],   m<i, n>j.
1298  *
1299  * Author:   Michael Holst
1300  * ***************************************************************************
1301  */
Vnm_dqsortR(double * u,int left,int right)1302 VPRIVATE void Vnm_dqsortR(double *u, int left, int right)
1303 {
1304     int i, j;
1305     double pivot, tmp;
1306     if (left < right) {
1307         i = left;
1308         j = right+1;
1309         pivot = u[left];
1310         do {
1311             do { i++; } while (u[i] < pivot);
1312             do { j--; } while (u[j] > pivot);
1313             if (i<j) {
1314                 tmp = u[i];
1315                 u[i] = u[j];
1316                 u[j] = tmp;
1317             }
1318         } while (i<j);
1319         tmp = u[left];
1320         u[left] = u[j];
1321         u[j] = tmp;
1322         Vnm_dqsortR(u, left, j-1);
1323         Vnm_dqsortR(u, j+1, right);
1324     }
1325 }
1326 
1327 /*
1328  * ***************************************************************************
1329  * Routine:  Vnm_dqsortOrdR
1330  *
1331  * Purpose:  RECURSIVE Quick sort a vector from [-large] to [+large].
1332  *
1333  * Notes:    Sorts u[left],...,u[right] in nondecreasing order.
1334  *           IMPORTANT NOTE: it is assumed that u[left] <= u[right+1]
1335  *           THEREFORE, you must have set u[right+1] to be greater than
1336  *           or equal to all entries u[0],...,u[right].
1337  *
1338  *           pivot=u[left] is arbitrarily chosen as the pivot key.
1339  *           i,j=used to partition sublist so at all times:
1340  *
1341  *                u[m] <= pivot <= u[n],   m<i, n>j.
1342  *
1343  * Author:   Michael Holst
1344  * ***************************************************************************
1345  */
Vnm_dqsortOrdR(double * u,int * ord,int left,int right)1346 VPRIVATE void Vnm_dqsortOrdR(double *u, int *ord, int left, int right)
1347 {
1348     int i, j, itmp;
1349     double pivot, tmp;
1350     if (left < right) {
1351         i = left;
1352         j = right+1;
1353         pivot = u[left];
1354         do {
1355             do { i++; } while (u[i] < pivot);
1356             do { j--; } while (u[j] > pivot);
1357             if (i<j) {
1358                 tmp = u[i];
1359                 u[i] = u[j];
1360                 u[j] = tmp;
1361                 itmp = ord[i];
1362                 ord[i] = ord[j];
1363                 ord[j] = itmp;
1364             }
1365         } while (i<j);
1366         tmp = u[left];
1367         u[left] = u[j];
1368         u[j] = tmp;
1369         itmp = ord[left];
1370         ord[left] = ord[j];
1371         ord[j] = itmp;
1372         Vnm_dqsortOrdR(u, ord, left, j-1);
1373         Vnm_dqsortOrdR(u, ord, j+1, right);
1374     }
1375 }
1376 
1377