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