• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

contrib/maloc/src/vsys/vnm.c

00001 /*
00002  * ***************************************************************************
00003  * MALOC = < Minimal Abstraction Layer for Object-oriented C >
00004  * Copyright (C) 1994--2008 Michael Holst
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00019  *
00020  * rcsid="$Id: vnm.c,v 1.18 2008/03/12 05:13:59 fetk Exp $"
00021  * ***************************************************************************
00022  */
00023 
00024 /*
00025  * ***************************************************************************
00026  * File:     vnm.c
00027  *
00028  * Purpose:  Virtual numerical machine.
00029  *
00030  *           In particular, this module defines an imaginary ideal 
00031  *           Virtual Machine for numerical codes, independent of the 
00032  *           underlying hardware.  All resources are provided abstractly.
00033  *
00034  * Notes:    The vnm library provides abstractions only for
00035  *           ANSI/ISO/Standard C; no extensions are provided for.
00036  *           In particular, "getenv" and "system", being almost the 
00037  *           only ISO C facilities for communicating with the underlying
00038  *           command shell, are the only facilities provided for in
00039  *           the abstraction layer.  All other facilities are layered
00040  *           on top of vnm in other libraries.
00041  *
00042  * Author:   Michael Holst
00043  * ***************************************************************************
00044  */
00045 
00046 #include "vnm_p.h"
00047 
00048 VEMBED(rcsid="$Id: vnm.c,v 1.18 2008/03/12 05:13:59 fetk Exp $")
00049 
00050 #if defined(HAVE_UNISTD_H)
00051 #   include <unistd.h> 
00052 #endif
00053 
00054 #if defined(HAVE_SYS_TYPES_H)
00055 #   include <sys/types.h> 
00056 #endif
00057 
00058 #if defined(HAVE_SYS_TIME_H)
00059 #   include <sys/time.h> 
00060 #endif
00061 
00062 #if defined(HAVE_SYS_TIMES_H)
00063 #   include <sys/times.h> 
00064 #endif
00065 
00066 #if defined(HAVE_SYS_STAT_H)
00067 #   include <sys/stat.h> 
00068 #endif
00069 
00070 #if defined(HAVE_WINSOCK_H)
00071     VEXTERNC char *getcwd(char *buf, int size);
00072     VEXTERNC int chdir(const char *path);
00073     VEXTERNC int mkdir(const char *pathname);
00074 #endif
00075 
00076 /* console management */
00077 VPRIVATE FILE *cons[4];
00078 VPRIVATE int consIni[4];
00079 VPRIVATE int consRedirect = 1;
00080 
00081 /* timers */
00082 VPRIVATE long before[VTIMERS];
00083 
00084 /* My unique name */
00085 VPRIVATE int ioTag = -1;
00086 VPRIVATE int nTags =  0;
00087 
00088 /* signal handler and jump data */
00089 VPRIVATE int vSigInt = 0;
00090 VPRIVATE int vJmpOk  = 0;
00091 VPRIVATE jmp_buf vJmpBuf;
00092 
00093 /* sorting */
00094 VPRIVATE void Vnm_qsortR(int *u, int left, int right);
00095 VPRIVATE void Vnm_qsortOrdR(int *u, int *ord, int left, int right);
00096 VPRIVATE void Vnm_dqsortR(double *u, int left, int right);
00097 VPRIVATE void Vnm_dqsortOrdR(double *u, int *ord, int left, int right);
00098 
00099 /*
00100  * ***************************************************************************
00101  * Routine:  Vnm_sigInt, Vnm_sigIntSet, Vnm_sitIntClear
00102  *           Vnm_jmpOk, Vnm_jmpOkSet, Vnm_jmpOkClear
00103  *
00104  * Purpose:  Signal and setjmp handling routines.
00105  *
00106  * Author:   Michael Holst
00107  * ***************************************************************************
00108  */
00109 
00110 /*
00111  * ***************************************************************************
00112  * Routine:  Vnm_sigInt
00113  *
00114  * Purpose:  Return the signal interupt flag.
00115  *
00116  * Author:   Michael Holst
00117  * ***************************************************************************
00118  */
00119 VPUBLIC int Vnm_sigInt(void)
00120 {
00121      return vSigInt;
00122 }
00123 
00124 /*
00125  * ***************************************************************************
00126  * Routine:  Vnm_sigIntSet
00127  *
00128  * Purpose:  Set the signal interrupt flag.
00129  *
00130  * Author:   Michael Holst
00131  * ***************************************************************************
00132  */
00133 VPUBLIC void Vnm_sigIntSet(void)
00134 {
00135     vSigInt=1;
00136 }
00137 
00138 /*
00139  * ***************************************************************************
00140  * Routine:  Vnm_sitIntClear
00141  *
00142  * Purpose:  Clear the signal interrupt flag.
00143  *
00144  * Author:   Michael Holst
00145  * ***************************************************************************
00146  */
00147 VPUBLIC void Vnm_sigIntClear(void)
00148 {
00149     vSigInt=0;
00150 }
00151 
00152 /*
00153  * ***************************************************************************
00154  * Routine:  Vnm_jmpOk
00155  *
00156  * Purpose:  Return the "okay-to-jump" flag.
00157  *
00158  * Author:   Michael Holst
00159  * ***************************************************************************
00160  */
00161 VPUBLIC int Vnm_jmpOk(void)
00162 {
00163     return vJmpOk;
00164 }
00165 
00166 /*
00167  * ***************************************************************************
00168  * Routine:  Vnm_jmpOkSet
00169  *
00170  * Purpose:  Set the "okay-to-jump" flag.
00171  *
00172  * Author:   Michael Holst
00173  * ***************************************************************************
00174  */
00175 VPUBLIC void Vnm_jmpOkSet(void)
00176 {
00177     vJmpOk=1;
00178 }
00179 
00180 /*
00181  * ***************************************************************************
00182  * Routine:  Vnm_jmpOkClear
00183  *
00184  * Purpose:  Clear the "okay-to-jump" flag.
00185  *
00186  * Author:   Michael Holst
00187  * ***************************************************************************
00188  */
00189 VPUBLIC void Vnm_jmpOkClear(void)
00190 {
00191     vJmpOk=0;
00192 }
00193 
00194 /*
00195  * ***************************************************************************
00196  * Routine:  Vnm_signalInit
00197  *
00198  * Purpose:  Initialize the signal handling data structures.
00199  *
00200  * Author:   Michael Holst
00201  * ***************************************************************************
00202  */
00203 VPUBLIC jmp_buf *Vnm_signalInit(void)
00204 {
00205     Vnm_sigIntClear();
00206     Vnm_jmpOkClear();
00207     Vnm_regHand();
00208     return &vJmpBuf;
00209 }
00210 
00211 /*
00212  * ***************************************************************************
00213  * Routine:  Vnm_regHand
00214  *
00215  * Purpose:  Register the signal handler with the operating system.
00216  *
00217  * Author:   Michael Holst
00218  * ***************************************************************************
00219  */
00220 VPUBLIC void Vnm_regHand(void)
00221 {
00222     VASSERT( signal(SIGINT,&Vnm_sigHand) != SIG_ERR );
00223 }
00224 
00225 /*
00226  * ***************************************************************************
00227  * Routine:  Vnm_sigHand
00228  *
00229  * Purpose:  Handle events such as SIGINT.
00230  *           We must have first been registered with "Vnm_signalInit".
00231  *
00232  * Author:   Michael Holst
00233  * ***************************************************************************
00234  */
00235 VPUBLIC void Vnm_sigHand(int num)
00236 {
00237 #if 0
00238     Vnm_print(2,"Vnm_sigHand: caught signal=<%d>\n",num);
00239 #endif
00240 
00241     /* re-register the interrupt handler in case it was cleared by default */
00242     Vnm_regHand();
00243 
00244     /* FIRST: handle SIGINT for killing loops */
00245     Vnm_sigIntSet();
00246 
00247     /* SECOND: handle SIGINT for returning to input prompt via longJmp */
00248     if (Vnm_jmpOk()) {
00249         Vnm_jmpOkClear();
00250         longjmp(vJmpBuf, 1);
00251     } else {
00252         return;
00253     }
00254 }
00255 
00256 /*
00257  * ***************************************************************************
00258  * Routine:  Vnm_powsafe
00259  *
00260  * Purpose:  A safe VPOW function (avoids division by zero).
00261  *
00262  * Author:   Michael Holst
00263  * ***************************************************************************
00264  */
00265 VPUBLIC double Vnm_powsafe(double x, double y)
00266 {
00267     if ((y < 0.) && (x < VSMALL)) {
00268         return 1.0;
00269     } else {
00270         return VPOW( x, y );
00271     }
00272 }
00273 
00274 /*
00275  * ***************************************************************************
00276  * Routine:  Vnm_typeChk
00277  *
00278  * Purpose:  Check out the sizes of various datatypes.
00279  *
00280  * Author:   Michael Holst
00281  * ***************************************************************************
00282  */
00283 VPUBLIC void Vnm_typeChk(void)
00284 {
00285     Vnm_print(0,"Vnm_typeChk: Asserting the following type sizes:\n");
00286     Vnm_print(0,"Vnm_typeChk: SizeOf(char)          = %d (1 on 32-bit arch)\n",
00287         sizeof(char));
00288     Vnm_print(0,"Vnm_typeChk: SizeOf(short)         = %d (2 on 32-bit arch)\n",
00289         sizeof(short));
00290     Vnm_print(0,"Vnm_typeChk: SizeOf(int)           = %d (4 on 32-bit arch)\n",
00291         sizeof(int));
00292     Vnm_print(0,"Vnm_typeChk: SizeOf(unsigned char) = %d (1 on 32-bit arch)\n",
00293         sizeof(unsigned char));
00294     Vnm_print(0,"Vnm_typeChk: SizeOf(unsigned short)= %d (2 on 32-bit arch)\n",
00295         sizeof(unsigned short));
00296     Vnm_print(0,"Vnm_typeChk: SizeOf(unsigned int)  = %d (4 on 32-bit arch)\n",
00297         sizeof(unsigned int));
00298     Vnm_print(0,"Vnm_typeChk: SizeOf(float)         = %d (4 on 32-bit arch)\n",
00299         sizeof(float));
00300     Vnm_print(0,"Vnm_typeChk: SizeOf(double)        = %d (8 on 32-bit arch)\n",
00301         sizeof(double));
00302 
00303     Vnm_print(0,"Vnm_typeChk: Noting also the following type sizes:\n");
00304     Vnm_print(0,"Vnm_typeChk: SizeOf(long)          = %d (4 on 32-bit arch)\n",
00305         sizeof(long));
00306     Vnm_print(0,"Vnm_typeChk: SizeOf(unsigned long) = %d (4 on 32-bit arch)\n",
00307         sizeof(unsigned long));
00308     Vnm_print(0,"Vnm_typeChk: SizeOf(int*)          = %d (4 on 32-bit arch)\n",
00309         sizeof(int*));
00310     Vnm_print(0,"Vnm_typeChk: SizeOf(void*)         = %d (4 on 32-bit arch)\n",
00311         sizeof(void*));
00312     Vnm_print(0,"Vnm_typeChk: SizeOf(size_t)        = %d (4 on 32-bit arch)\n",
00313         sizeof(size_t));
00314 
00315     VASSERT( sizeof(char)              == 1 );
00316     VASSERT( sizeof(short)             == 2 );
00317     VASSERT( sizeof(int)               == 4 );
00318     VASSERT( sizeof(unsigned char)     == 1 );
00319     VASSERT( sizeof(unsigned short)    == 2 );
00320     VASSERT( sizeof(unsigned int)      == 4 );
00321     VASSERT( sizeof(float)             == 4 );
00322     VASSERT( sizeof(double)            == 8 );
00323 
00324     /* VASSERT( sizeof(long)           == 4 ); */
00325     /* VASSERT( sizeof(unsigned long)  == 4 ); */
00326     /* VASSERT( sizeof(int*)           == 4 ); */
00327     /* VASSERT( sizeof(void*)          == 4 ); */
00328     /* VASSERT( sizeof(size_t)         == 4 ); */
00329 }
00330 
00331 /*
00332  * ***************************************************************************
00333  * Routine:  Vnm_epsmac
00334  *
00335  * Purpose:  Computes the unit roundoff of the machine in single
00336  *           precision.  This is defined as the smallest positive machine
00337  *           number u such that  1.0d0 + u .ne. 1.0d0 (in single precision).
00338  *
00339  *           A safe hardcoded machine epsilon as alternative:
00340  *
00341  *                double value;
00342  *                value = 1.0e-9;
00343  *                return value;
00344  *
00345  * Author:   Michael Holst
00346  * ***************************************************************************
00347  */
00348 VPUBLIC double Vnm_epsmac(void)
00349 {
00350     double u, comp, value;
00351     u = 1.0;
00352     while (1) {
00353         u = u * 0.5;
00354         comp = 1.0 + u;
00355         if (comp == 1.0) break;
00356     }
00357     value = u*2.0;
00358     return value;
00359 }
00360 
00361 /*
00362  * ***************************************************************************
00363  * Routine:  Vnm_gentokens
00364  *
00365  * Purpose:  Generate an [argv,argc] pair from a character string "buf"
00366  *           (assumed NULL-terminated) in which tokens are separated by 
00367  *           whitespace "white" with possible comments "comment" occuring.
00368  *           THE INPUT STRING IS MODIFIED HERE!
00369  *
00370  * Notes:    Again, the input string "buf" IS MODIFIED; white space characters
00371  *           (defined in the input string "white") are replaced by the NULL 
00372  *           character '\0'.  The output "argv" is simply a list of pointers
00373  *           to the start of the tokens in "buf", which are NULL-terminated 
00374  *           after we replace the white space with NULLs.
00375  *
00376  *           We follow convention and "NULL"-terminate "argv" by setting
00377  *           the pointer following the last token to "VNULL".  The return
00378  *           value is "argc", the number of tokens found (not including the
00379  *           terminating NULL pointer).  For safety you must pass in the
00380  *           maximal length of argv in the parameter "argvmax".
00381  *
00382  *           If we encounter a token which begins with a comment character
00383  *           (defined in the input string "comment"), then we ignore the 
00384  *           rest of the tokens in the input buffer "buf".  This is suitable
00385  *           for parsing shell languages such as sh/ksh/bash which have
00386  *           comments that start with e.g. "#" and continue until a newline.
00387  *
00388  *           We DO NOT use the C library function strtok in this routine.
00389  *           (There are some bad implementations of strtok around apparently;
00390  *           the internal state variables maintained by strtok can get very
00391  *           messed up if you use strtok in multiple places in a code.)
00392  *
00393  * Author:   Michael Holst
00394  * ***************************************************************************
00395  */
00396 VPUBLIC int Vnm_gentokens(char *buf, char **argv, 
00397     const int argvmax, const char *white, const char *comment)
00398 {
00399     int  i, j, ntok, state, done, bufsize;
00400 
00401     for (i=0; i<argvmax; i++) {
00402         argv[i] = VNULL;
00403     }
00404     bufsize = strlen(buf);
00405     VJMPERR1( buf[bufsize] == '\0' );
00406     ntok = 0;
00407     state = 0;
00408     done = 0;
00409     i=0;
00410     while ((i<bufsize) && (!done)) {
00411         if (strchr(comment,buf[i])) done = 1;
00412         else {
00413             if (!strchr(white,buf[i]) && (state==0)) {
00414                 state = 1;
00415                 argv[ntok] = (buf+i);
00416                 ntok++;
00417             }
00418             if (strchr(white,buf[i])) {
00419                 buf[i] = '\0';
00420                 state = 0;
00421             }
00422             i++;
00423         }
00424     }
00425     argv[ntok] = VNULL;
00426     VJMPERR1( ntok < argvmax );
00427     for (j=i; j<bufsize; j++) {
00428         buf[j] = '\0';
00429     }
00430 
00431     /* return with no errors */
00432     return ntok;
00433 
00434   VERROR1:
00435     Vnm_print(2,"Vnm_gentokens: problem with buffer management.\n");
00436     return 0;
00437 }
00438 
00439 /*
00440  * ***************************************************************************
00441  * Routine:  Vnm_tstart
00442  *
00443  * Purpose:  Starts the timer on the particular machine.
00444  *
00445  * Author:   Michael Holst
00446  * ***************************************************************************
00447  */
00448 VPUBLIC void Vnm_tstart(int timer, const char *name)
00449 {
00450     VASSERT( (timer>=0) && (timer<VTIMERS) );
00451     Vnm_print(0, "Vnm_tstart: starting timer %d (%s)..\n", timer, name);
00452     before[timer] = clock();
00453 }
00454 
00455 /*
00456  * ***************************************************************************
00457  * Routine:  Vnm_tstop
00458  *
00459  * Purpose:  Stops the timer on the particular machine.
00460  *
00461  * Author:   Michael Holst
00462  * ***************************************************************************
00463  */
00464 VPUBLIC void Vnm_tstop(int timer, const char *name)
00465 {
00466     long after;
00467     double cputme;
00468 
00469     VASSERT( (timer>=0) && (timer<VTIMERS) );
00470     after  = clock();
00471     cputme = (double)(after-before[timer]) / (double)(CLOCKS_PER_SEC);
00472     Vnm_print(0, "Vnm_tstop: stopping timer %d (%s).  CPU TIME = %e\n", 
00473         timer, name, cputme);
00474 }
00475 
00476 /*
00477  * ***************************************************************************
00478  * Routine:  Vnm_getuser
00479  *
00480  * Purpose:  Ask the system for the username.
00481  *
00482  * Author:   Michael Holst
00483  * ***************************************************************************
00484  */
00485 VPUBLIC char *Vnm_getuser(char *user, int usermax)
00486 {
00487     char *name = VNULL;
00488     VASSERT( usermax <= VMAX_ARGLEN );
00489 
00490     name = getenv("USER");
00491     if (name != VNULL) strncpy(user,name,usermax);
00492     else strncpy(user,"mcuser",usermax);
00493     return user;
00494 }
00495 
00496 /*
00497  * ***************************************************************************
00498  * Routine:  Vnm_getos
00499  *
00500  * Purpose:  Ask the system for the operating system name.
00501  *
00502  * Author:   Michael Holst
00503  * ***************************************************************************
00504  */
00505 VPUBLIC char *Vnm_getos(char *os, int osmax)
00506 {
00507     char *name = VNULL;
00508     VASSERT( osmax <= VMAX_ARGLEN );
00509 
00510     name = getenv("OSTYPE");
00511     if (name != VNULL) strncpy(os,name,osmax);
00512     else strncpy(os,"UNIX",osmax);
00513     return os;
00514 }
00515 
00516 /*
00517  * ***************************************************************************
00518  * Routine:  Vnm_gethost
00519  *
00520  * Purpose:  Ask the system for the hostname.
00521  *
00522  * Author:   Michael Holst
00523  * ***************************************************************************
00524  */
00525 VPUBLIC char *Vnm_gethost(char *host, int hostmax)
00526 {
00527     int i, j;
00528     char *name = VNULL;
00529     VASSERT( hostmax <= VMAX_ARGLEN );
00530 
00531     name = getenv("HOSTNAME");
00532     if (name != VNULL) {
00533         strncpy(host,name,hostmax);
00534     } else {
00535         name = getenv("HOST");
00536         if (name != VNULL) {
00537             strncpy(host,name,hostmax);
00538         } else {
00539             strncpy(host,"HOST",hostmax);
00540         }
00541     }
00542     j = (int)strlen(host);
00543     for (i=0; i<j; i++) {
00544         if (host[i] == '.') host[i] = '\0';
00545     }
00546     return host;
00547 }
00548 
00549 /*
00550  * ***************************************************************************
00551  * Routine:  Vnm_gethome
00552  *
00553  * Purpose:  Ask the system for the home directory.
00554  *
00555  * Note:     The following preference order is used to set the home directory:
00556  *
00557  *               MCSH_HOME (the user must define this in his environment)
00558  *               CWD       (always defined as the current working directory)
00559  *
00560  *           We consider it an error if we can't return something useful;
00561  *           therefore we will VASSERT(path!=VNULL) before returning.
00562  *
00563  *           We settle on a home directory the first time we are called,
00564  *           and then we simply return this fixed home directory forever.
00565  *           In other words, the first call to Vnm_gethome, regardless of
00566  *           who makes the call, establishes the home directory for everyone
00567  *           else (as long as everyone goes through Vnm_gethome!).
00568  *
00569  * Author:   Michael Holst
00570  * ***************************************************************************
00571  */
00572 VPUBLIC char *Vnm_gethome(char *path, int pathmax)
00573 {
00574     char *home = VNULL;
00575     static char vnmHome[VMAX_ARGLEN];
00576     static int init=0;
00577 
00578     VASSERT( pathmax <= VMAX_ARGLEN );
00579 
00580     if (!init) {
00581         init = 1;
00582         home = getenv("MCSH_HOME");
00583         if (home == VNULL) {
00584             home = Vnm_getcwd(vnmHome,pathmax);
00585             VASSERT( home != VNULL );
00586         } else {
00587             strncpy(vnmHome,home,pathmax);
00588         }
00589     }
00590     strncpy(path,vnmHome,pathmax);
00591     home = path;
00592     return path;
00593 }
00594 
00595 /*
00596  * ***************************************************************************
00597  * Routine:  Vnm_getcwd
00598  *
00599  * Purpose:  Ask the system for the current working directory.
00600  *
00601  * Note:     Consider it an error if we can't return something useful;
00602  *           therefore we will VASSERT(path!=VNULL) before returning.
00603  *
00604  *           Note that unlike Vnm_gethome, a call to Vnm_getcwd returns
00605  *           the current directory, possibly modified from call to call.
00606  *
00607  *           I.e., calls to Vnm_chdir can change the current working
00608  *           directory; Vnm_getcwd returns the current directory, whatever
00609  *           that me be.
00610  *
00611  * Author:   Michael Holst
00612  * ***************************************************************************
00613  */
00614 VPUBLIC char *Vnm_getcwd(char *path, int pathmax)
00615 {
00616     char *cwd = VNULL;
00617     VASSERT( pathmax <= VMAX_ARGLEN );
00618 
00619 #if defined(HAVE_GETCWD)
00620     cwd = getcwd(path, (unsigned int)pathmax);
00621 #else
00622     cwd = getwd(path);
00623 #endif
00624 
00625     VASSERT( cwd != VNULL );
00626     return path;
00627 }
00628 
00629 /*
00630  * ***************************************************************************
00631  * Routine:  Vnm_chdir
00632  *
00633  * Purpose:  Interact with the system to change the working directory.
00634  *
00635  * Author:   Michael Holst
00636  * ***************************************************************************
00637  */
00638 VPUBLIC int Vnm_chdir(const char *path)
00639 {
00640     return chdir(path);
00641 }
00642 
00643 /*
00644  * ***************************************************************************
00645  * Routine:  Vnm_mkdir
00646  *
00647  * Purpose:  Interact with the system to make a new directory.
00648  *
00649  * Author:   Michael Holst
00650  * ***************************************************************************
00651  */
00652 VPUBLIC int Vnm_mkdir(const char *path)
00653 {
00654 #if defined(HAVE_WINSOCK_H)
00655     return mkdir(path);
00656 #else
00657     mode_t mode = 0777;
00658     return mkdir(path,mode);
00659 #endif
00660 }
00661 
00662 /*
00663  * ***************************************************************************
00664  * Routine:  Vnm_system
00665  *
00666  * Purpose:  An improved ANSI-C "system" call.
00667  *
00668  * Author:   Michael Holst
00669  * ***************************************************************************
00670  */
00671 VPUBLIC int Vnm_system(const char *cmd)
00672 {
00673     return system(cmd);
00674 }   
00675 
00676 /*
00677  * ***************************************************************************
00678  * Routine:  Vnm_systemBack
00679  *
00680  * Purpose:  A background variant of the ANSI-C "system" call.
00681  *
00682  * Author:   Michael Holst
00683  * ***************************************************************************
00684  */
00685 VPUBLIC int Vnm_systemBack(const char *cmd)
00686 {
00687     char cmdbuf[VMAX_BUFSIZE];
00688 
00689 #if defined(HAVE_WINSOCK_H)
00690     strcpy(cmdbuf, "start /B ");
00691     strcat(cmdbuf, cmd);
00692 #else
00693     strcpy(cmdbuf, cmd);
00694     strcat(cmdbuf, " &");
00695 #endif
00696     return Vnm_system(cmdbuf);
00697 }   
00698 
00699 /*
00700  * ***************************************************************************
00701  * Routine:  Vnm_systemKill
00702  *
00703  * Purpose:  Something like a UNIX "killall" call.
00704  *
00705  * Author:   Michael Holst
00706  * ***************************************************************************
00707  */
00708 VPUBLIC int Vnm_systemKill(const char *cmd)
00709 {
00710     char cmdbuf[VMAX_BUFSIZE];
00711 
00712 #if defined(HAVE_WINSOCK_H)
00713     strcpy(cmdbuf, "killall ");
00714     strcat(cmdbuf, cmd);
00715     (void)Vnm_system(cmdbuf);
00716 #else
00717     strcpy(cmdbuf, "killall ");
00718     strcat(cmdbuf, cmd);
00719     strcat(cmdbuf, "> /dev/null 2>&1");
00720     (void)Vnm_system(cmdbuf);
00721     strcpy(cmdbuf, "killall ./");
00722     strcat(cmdbuf, cmd);
00723     strcat(cmdbuf, "> /dev/null 2>&1");
00724     (void)Vnm_system(cmdbuf);
00725 #endif
00726     return 0;
00727 }   
00728 
00729 /*
00730  * ***************************************************************************
00731  * Routine:  Vnm_exec
00732  *
00733  * Purpose:  An improved UNIX "exec" call.
00734  *
00735  * Notes:    This routine does not return except on error.
00736  *
00737  * Author:   Michael Holst
00738  * ***************************************************************************
00739  */
00740 VPUBLIC int Vnm_exec(int argc, char **argv)
00741 {
00742 #if !defined(HAVE_WINSOCK_H)
00743     if (strstr(argv[0], "/")) {
00744         execv (argv[0],argv);
00745     } else {
00746         execvp(argv[0],argv);
00747     }
00748 #endif
00749     /* Vnm_system("play sorry.au"); */
00750 
00751     return -1;
00752 }   
00753 
00754 /*
00755  * ***************************************************************************
00756  * Routine:  Vnm_sleep
00757  *
00758  * Purpose:  Implement a sleep function with microsecond resolution.
00759  *
00760  * Notes:    This is hacked out of the "sleep_us" example in
00761  *           Rick Steven's Advance Unix Programming book.
00762  *
00763  * Author:   Michael Holst
00764  * ***************************************************************************
00765  */
00766 VPUBLIC void Vnm_sleep(int nusecs)
00767 {
00768 #if defined(HAVE_WINSOCK_H)
00769 #else
00770     struct timeval tval;
00771     tval.tv_sec  = ((unsigned int)nusecs) / 1000000;
00772     tval.tv_usec = ((unsigned int)nusecs) % 1000000;
00773     select(0, VNULL, VNULL, VNULL, &tval);
00774 #endif
00775 }
00776 
00777 /*
00778  * ***************************************************************************
00779  * Routine:  Vnm_ioTag
00780  *
00781  * Purpose:  Return my I/O tag.
00782  *
00783  * Author:   Michael Holst
00784  * ***************************************************************************
00785  */
00786 VPUBLIC int Vnm_ioTag(void)
00787 {
00788     return ioTag;
00789 }
00790 
00791 /*
00792  * ***************************************************************************
00793  * Routine:  Vnm_nTags
00794  *
00795  * Purpose:  Return the total number of tags.
00796  *
00797  * Author:   Michael Holst
00798  * ***************************************************************************
00799  */
00800 VPUBLIC int Vnm_nTags(void)
00801 {
00802     return nTags;
00803 }
00804 
00805 /*
00806  * ***************************************************************************
00807  * Routine:  Vnm_setIoTag
00808  *
00809  * Purpose:  Set my id.
00810  *
00811  * Author:   Michael Holst
00812  * ***************************************************************************
00813  */
00814 VPUBLIC void Vnm_setIoTag(int myTag, int numTags)
00815 {
00816     ioTag = myTag;
00817     nTags = numTags;
00818 }
00819 
00820 /*
00821  * ***************************************************************************
00822  * Routine:  Vnm_open
00823  *
00824  * Purpose:  Open an I/O console.
00825  *
00826  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
00827  *
00828  *           The following codes are used:
00829  *
00830  *           unit#      C output unit
00831  *           -------    -------------
00832  *
00833  *           unit==0    garbage   -- Non-interactive i/o; lots of stuff
00834  *                                   (can be redirected to ${MCSH_HOME/io.mc)
00835  *
00836  *           unit==1    stdout    -- standard output (Interactive I/O)
00837  *
00838  *           unit==2    stderr    -- standard error (IMPORTANT interactive I/O)
00839  *
00840  *           unit==3    history   -- History file ${MCSH_HOME}/hist.mcsh
00841  *
00842  *           unit==else /dev/null -- Error...
00843  *
00844  * Author:   Michael Holst
00845  * ***************************************************************************
00846  */
00847 VPUBLIC FILE *Vnm_open(const int unit)
00848 {
00849     static int openIni = VFALSE;
00850     int i;
00851     char str[256], fname[256], apnd[256], myhome[VMAX_ARGLEN];
00852     time_t now;
00853 
00854     if ( !((0<=unit)&&(unit<=3)) )
00855         fprintf(stderr,"Vnm_open: Bad UNIT <%d> specified.\n", unit);
00856 
00857     /* initialize once */
00858     if (!openIni) {
00859         for (i=0; i<4; i++) {
00860             consIni[i] = VFALSE;
00861             cons[i]    = VNULL;
00862         }
00863         openIni = VTRUE;
00864     }
00865 
00866     /* open the file unit */
00867     if (cons[unit] == VNULL) {
00868 
00869         /* get a reasonable home directory for ALL file i/o (dot files, etc) */
00870         VASSERT( Vnm_gethome(myhome, sizeof(myhome)) );
00871 
00872         /* do we need to append our id to all of the dot files */
00873         if ((Vnm_ioTag() >= 0) && (Vnm_nTags() > 1)) {
00874             sprintf(apnd,"_%d",Vnm_ioTag());
00875         } else {
00876             apnd[0] = '\0';
00877         }
00878 
00879         if (unit == 0) {
00880             if (consRedirect) {
00881                 sprintf(fname,"%s/%s%s",myhome,"io.mc",apnd);
00882                 if (!consIni[unit]) {
00883                     cons[unit]=fopen( fname, "a" /*"w"*/ );
00884                 } else {
00885                     cons[unit]=fopen( fname, "a" );
00886                 }
00887             } else {
00888                 cons[unit] = stderr;
00889             }
00890         } else if (unit == 1) {
00891             cons[unit] = stdout;
00892         } else if (unit == 2) {
00893             cons[unit] = stderr;
00894         } else if (unit == 3) {
00895             sprintf(fname,"%s/%s%s",myhome,"hist.mcsh",apnd);
00896             if (!consIni[unit]) {
00897                 cons[unit]=fopen(fname, "a" /*"w"*/); 
00898             } else {
00899                 cons[unit]=fopen(fname, "a"); 
00900             }
00901         } else fprintf(stderr,"Vnm_open: Bad UNIT <%d> specified.\n", unit);
00902 
00903         /* Write some info for the first line in the file (if not stdout). */
00904         if (!consIni[unit]) {
00905             if ( cons[unit] != VNULL ) {
00906                 consIni[unit] = VTRUE;
00907                 if ((unit == 0) && (consRedirect)) {
00908                     fprintf(cons[unit],"####################################"
00909                         "##########################################\n");
00910                     fprintf(cons[unit],"# MC-shell I/O capture file.\n");
00911                     now = time(VNULL);
00912                     sprintf(str,"# Creation Date and Time:  %s",ctime(&now));
00913                     fprintf(cons[unit],str);
00914                     fprintf(cons[unit],"####################################"
00915                         "##########################################\n");
00916                 } else if (unit == 3) {
00917                     fprintf(cons[unit],"#! /bin/mcsh\n");
00918                     fprintf(cons[unit],"####################################"
00919                         "##########################################\n");
00920                     fprintf(cons[unit],"# MC-shell history file.\n");
00921                     now = time(VNULL);
00922                     sprintf(str,"# Creation Date and Time:  %s",ctime(&now));
00923                     fprintf(cons[unit],str);
00924                     fprintf(cons[unit],"####################################"
00925                         "##########################################\n");
00926                 }
00927             }
00928         }
00929     }
00930     return cons[unit];
00931 }
00932 
00933 /*
00934  * ***************************************************************************
00935  * Routine:  Vnm_close
00936  *
00937  * Purpose:  Close an I/O console.
00938  *
00939  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
00940  *
00941  * Author:   Michael Holst
00942  * ***************************************************************************
00943  */
00944 VPUBLIC int Vnm_close(const int unit)
00945 {
00946     int retcode;
00947 
00948     if ( !((0<=unit)&&(unit<=3)) ) {
00949         fprintf(stderr,"Vnm_close: Bad UNIT <%d> specified.\n", unit);
00950     }
00951 
00952     if (  (cons[unit] != VNULL) 
00953        && (cons[unit] != stdin)
00954        && (cons[unit] != stdout)
00955        && (cons[unit] != stderr) ) {
00956         retcode = fclose(cons[unit]);
00957     } else {
00958         retcode = 1;
00959     }
00960     cons[unit] = VNULL;
00961     return retcode;
00962 }
00963 
00964 /*
00965  * ***************************************************************************
00966  * Routine:  Vnm_flush
00967  *
00968  * Purpose:  Attempt to flush the specified i/o stream.
00969  *
00970  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
00971  *
00972  * Author:   Michael Holst
00973  * ***************************************************************************
00974  */
00975 VPUBLIC void Vnm_flush(const int unit)
00976 {
00977     if ( !((0<=unit)&&(unit<=3)) ) {
00978         fprintf(stderr,"Vnm_flush: Bad UNIT <%d> specified.\n", unit);
00979     }
00980 
00981     if (cons[unit] != VNULL) {
00982         fflush(cons[unit]);
00983     }
00984 }
00985 
00986 /*
00987  * ***************************************************************************
00988  * Routine:  Vnm_redirect
00989  *
00990  * Purpose:  Set/unset the redirect flag for UNIT zero.
00991  *           When redirected, I/O goes to the file: ${MCSH_HOME}/io.mc
00992  *
00993  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
00994  *
00995  * Author:   Michael Holst
00996  * ***************************************************************************
00997  */
00998 VPUBLIC void Vnm_redirect(const int flag)
00999 {
01000     if ( !((flag==0)||(flag==1)) ) {
01001         fprintf(stderr,"Vnm_redirect: Bad FLAG <%d> specified.\n", flag);
01002     }
01003 
01004     consRedirect = flag;
01005 }
01006 
01007 /*
01008  * ***************************************************************************
01009  * Routine:  Vnm_print
01010  *
01011  * Purpose:  External interface to the console i/o routine.
01012  *
01013  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
01014  *
01015  * Author:   Michael Holst
01016  * ***************************************************************************
01017  */
01018 VPUBLIC void Vnm_print(const int unit, const char *format, ...)
01019 {
01020     va_list argList;
01021     FILE    *fp;
01022 
01023     if ( !((0<=unit)&&(unit<=3)) ) {
01024         fprintf(stderr,"Vnm_print: Bad UNIT <%d> specified.\n", unit);
01025     }
01026 
01027     fp = Vnm_open(unit);
01028     if (fp != VNULL) {
01029         va_start(argList, format);
01030         vfprintf(fp, format, argList);
01031         va_end(argList);
01032         Vnm_close(unit);
01033     }
01034     Vnm_flush(unit);
01035 }
01036 
01037 /*
01038  * ***************************************************************************
01039  * Routine:  Vnm_tprint
01040  *
01041  * Purpose:  Add our ioTag to Vnm_print output.
01042  *
01043  * Notes:    For a tag to be added, both of the following conditions
01044  *           must hold:
01045  *
01046  *               Vnm_ioTag() >= 0   (I.e., I must have been given a tag)
01047  *               Vnm_nTags() >  1   (I must not be the only one given a tag)
01048  *
01049  * NOTE:     We MUST NOT use VASSERT (or Vnm_print!) in this routine.
01050  *
01051  * Author:   Michael Holst
01052  * ***************************************************************************
01053  */
01054 VPUBLIC void Vnm_tprint(const int unit, const char *format, ...)
01055 {
01056     va_list argList;
01057     FILE    *fp;
01058 
01059     if ( !((0<=unit)&&(unit<=3)) ) {
01060         if ((Vnm_ioTag() >= 0) && (Vnm_nTags() > 1)) {
01061             fprintf(stderr, "[%d] ", Vnm_ioTag());
01062         }
01063         fprintf(stderr,"Vnm_tprint: Bad UNIT <%d> specified.\n", unit);
01064     }
01065 
01066     fp = Vnm_open(unit);
01067     if (fp != VNULL) {
01068         if ((Vnm_ioTag() >= 0) && (Vnm_nTags() > 1)) {
01069             fprintf(fp, "[%d] ", Vnm_ioTag());
01070         }
01071         va_start(argList, format);
01072         vfprintf(fp, format, argList);
01073         va_end(argList);
01074         Vnm_close(unit);
01075     }
01076     Vnm_flush(unit);
01077 }
01078 
01079 /*
01080  * ***************************************************************************
01081  * Routine:  Vnm_qsort
01082  *
01083  * Purpose:  Front-end to quick sort integer array from [-large] to [+large].
01084  *
01085  * Author:   Michael Holst
01086  * ***************************************************************************
01087  */
01088 VPUBLIC void Vnm_qsort(int *u, int size)
01089 {
01090     int i, itmp;
01091 
01092     /* find largest entry; place on right for qSortRecurse */
01093     for (i=0; i<size-1; i++) {
01094         if (u[i] > u[size-1]) {
01095             itmp = u[size-1];
01096             u[size-1] = u[i];
01097             u[i] = itmp;
01098         }
01099     }
01100 
01101     /* now call qSortRecurse */
01102     Vnm_qsortR(u, 0, size-2);
01103 }
01104 
01105 /*
01106  * ***************************************************************************
01107  * Routine:  Vnm_qsortOrd
01108  *
01109  * Purpose:  Front-end to quick sort integer array from [-large] to [+large].
01110  *
01111  * Author:   Michael Holst
01112  * ***************************************************************************
01113  */
01114 VPUBLIC void Vnm_qsortOrd(int *u, int *ord, int size)
01115 {
01116     int i, itmp;
01117 
01118     /* find largest entry; place on right for qSortRecurse */
01119     for (i=0; i<size-1; i++) {
01120         if (u[i] > u[size-1]) {
01121             itmp = u[size-1];
01122             u[size-1] = u[i];
01123             u[i] = itmp;
01124             itmp = ord[size-1];
01125             ord[size-1] = ord[i];
01126             ord[i] = itmp;
01127         }
01128     }
01129 
01130     /* now call qSortRecurse */
01131     Vnm_qsortOrdR(u, ord, 0, size-2);
01132 }
01133 
01134 /*
01135  * ***************************************************************************
01136  * Routine:  Vnm_dqsort
01137  *
01138  * Purpose:  Front-end to quick sort integer array from [-large] to [+large].
01139  *
01140  * Author:   Michael Holst
01141  * ***************************************************************************
01142  */
01143 VPUBLIC void Vnm_dqsort(double *u, int size)
01144 {
01145     int i;
01146     double tmp;
01147 
01148     /* find largest entry; place on right for qSortRecurse */
01149     for (i=0; i<size-1; i++) {
01150         if (u[i] > u[size-1]) {
01151             tmp = u[size-1];
01152             u[size-1] = u[i];
01153             u[i] = tmp;
01154         }
01155     }
01156 
01157     /* now call qSortRecurse */
01158     Vnm_dqsortR(u, 0, size-2);
01159 }
01160 
01161 /*
01162  * ***************************************************************************
01163  * Routine:  Vnm_dqsortOrd
01164  *
01165  * Purpose:  Front-end to quick sort integer array from [-large] to [+large].
01166  *
01167  * Author:   Michael Holst
01168  * ***************************************************************************
01169  */
01170 VPUBLIC void Vnm_dqsortOrd(double *u, int *ord, int size)
01171 {
01172     int i, itmp;
01173     double tmp;
01174 
01175     /* find largest entry; place on right for qSortRecurse */
01176     for (i=0; i<size-1; i++) {
01177         if (u[i] > u[size-1]) {
01178             tmp = u[size-1];
01179             u[size-1] = u[i];
01180             u[i] = tmp;
01181             itmp = ord[size-1];
01182             ord[size-1] = ord[i];
01183             ord[i] = itmp;
01184         }
01185     }
01186 
01187     /* now call qSortRecurse */
01188     Vnm_dqsortOrdR(u, ord, 0, size-2);
01189 }
01190 
01191 /*
01192  * ***************************************************************************
01193  * Routine:  Vnm_qsortR
01194  *
01195  * Purpose:  RECURSIVE Quick sort a vector from [-large] to [+large].
01196  *
01197  * Notes:    Sorts u[left],...,u[right] in nondecreasing order.
01198  *           IMPORTANT NOTE: it is assumed that u[left] <= u[right+1]
01199  *           THEREFORE, you must have set u[right+1] to be greater than
01200  *           or equal to all entries u[0],...,u[right].
01201  *
01202  *           pivot=u[left] is arbitrarily chosen as the pivot key.
01203  *           i,j=used to partition sublist so at all times: 
01204  *
01205  *                u[m] <= pivot <= u[n],   m<i, n>j.
01206  *
01207  * Author:   Michael Holst
01208  * ***************************************************************************
01209  */
01210 VPRIVATE void Vnm_qsortR(int *u, int left, int right)
01211 {
01212     int i, j, pivot, tmp;
01213     if (left < right) {
01214         i = left;
01215         j = right+1;
01216         pivot = u[left];
01217         do {
01218             do { i++; } while (u[i] < pivot);
01219             do { j--; } while (u[j] > pivot);
01220             if (i<j) {
01221                 tmp = u[i]; 
01222                 u[i] = u[j]; 
01223                 u[j] = tmp; 
01224             }
01225         } while (i<j);
01226         tmp = u[left]; 
01227         u[left] = u[j]; 
01228         u[j] = tmp; 
01229         Vnm_qsortR(u, left, j-1);
01230         Vnm_qsortR(u, j+1, right);
01231     }
01232 }
01233 
01234 /*
01235  * ***************************************************************************
01236  * Routine:  Vnm_qsortOrdR
01237  *
01238  * Purpose:  RECURSIVE Quick sort a vector from [-large] to [+large].
01239  *
01240  * Notes:    Sorts u[left],...,u[right] in nondecreasing order.
01241  *           IMPORTANT NOTE: it is assumed that u[left] <= u[right+1]
01242  *           THEREFORE, you must have set u[right+1] to be greater than
01243  *           or equal to all entries u[0],...,u[right].
01244  *
01245  *           pivot=u[left] is arbitrarily chosen as the pivot key.
01246  *           i,j=used to partition sublist so at all times: 
01247  *
01248  *                u[m] <= pivot <= u[n],   m<i, n>j.
01249  *
01250  * Author:   Michael Holst
01251  * ***************************************************************************
01252  */
01253 VPRIVATE void Vnm_qsortOrdR(int *u, int *ord, int left, int right)
01254 {
01255     int i, j, pivot, tmp, itmp;
01256     if (left < right) {
01257         i = left;
01258         j = right+1;
01259         pivot = u[left];
01260         do {
01261             do { i++; } while (u[i] < pivot);
01262             do { j--; } while (u[j] > pivot);
01263             if (i<j) {
01264                 tmp = u[i]; 
01265                 u[i] = u[j]; 
01266                 u[j] = tmp; 
01267                 itmp = ord[i]; 
01268                 ord[i] = ord[j]; 
01269                 ord[j] = itmp; 
01270             }
01271         } while (i<j);
01272         tmp = u[left]; 
01273         u[left] = u[j]; 
01274         u[j] = tmp; 
01275         itmp = ord[left]; 
01276         ord[left] = ord[j]; 
01277         ord[j] = itmp; 
01278         Vnm_qsortOrdR(u, ord, left, j-1);
01279         Vnm_qsortOrdR(u, ord, j+1, right);
01280     }
01281 }
01282 
01283 /*
01284  * ***************************************************************************
01285  * Routine:  Vnm_dqsortR
01286  *
01287  * Purpose:  RECURSIVE Quick sort a vector from [-large] to [+large].
01288  *
01289  * Notes:    Sorts u[left],...,u[right] in nondecreasing order.
01290  *           IMPORTANT NOTE: it is assumed that u[left] <= u[right+1]
01291  *           THEREFORE, you must have set u[right+1] to be greater than
01292  *           or equal to all entries u[0],...,u[right].
01293  *
01294  *           pivot=u[left] is arbitrarily chosen as the pivot key.
01295  *           i,j=used to partition sublist so at all times: 
01296  *
01297  *                u[m] <= pivot <= u[n],   m<i, n>j.
01298  *
01299  * Author:   Michael Holst
01300  * ***************************************************************************
01301  */
01302 VPRIVATE void Vnm_dqsortR(double *u, int left, int right)
01303 {
01304     int i, j;
01305     double pivot, tmp;
01306     if (left < right) {
01307         i = left;
01308         j = right+1;
01309         pivot = u[left];
01310         do {
01311             do { i++; } while (u[i] < pivot);
01312             do { j--; } while (u[j] > pivot);
01313             if (i<j) {
01314                 tmp = u[i]; 
01315                 u[i] = u[j]; 
01316                 u[j] = tmp; 
01317             }
01318         } while (i<j);
01319         tmp = u[left]; 
01320         u[left] = u[j]; 
01321         u[j] = tmp; 
01322         Vnm_dqsortR(u, left, j-1);
01323         Vnm_dqsortR(u, j+1, right);
01324     }
01325 }
01326 
01327 /*
01328  * ***************************************************************************
01329  * Routine:  Vnm_dqsortOrdR
01330  *
01331  * Purpose:  RECURSIVE Quick sort a vector from [-large] to [+large].
01332  *
01333  * Notes:    Sorts u[left],...,u[right] in nondecreasing order.
01334  *           IMPORTANT NOTE: it is assumed that u[left] <= u[right+1]
01335  *           THEREFORE, you must have set u[right+1] to be greater than
01336  *           or equal to all entries u[0],...,u[right].
01337  *
01338  *           pivot=u[left] is arbitrarily chosen as the pivot key.
01339  *           i,j=used to partition sublist so at all times: 
01340  *
01341  *                u[m] <= pivot <= u[n],   m<i, n>j.
01342  *
01343  * Author:   Michael Holst
01344  * ***************************************************************************
01345  */
01346 VPRIVATE void Vnm_dqsortOrdR(double *u, int *ord, int left, int right)
01347 {
01348     int i, j, itmp;
01349     double pivot, tmp;
01350     if (left < right) {
01351         i = left;
01352         j = right+1;
01353         pivot = u[left];
01354         do {
01355             do { i++; } while (u[i] < pivot);
01356             do { j--; } while (u[j] > pivot);
01357             if (i<j) {
01358                 tmp = u[i]; 
01359                 u[i] = u[j]; 
01360                 u[j] = tmp; 
01361                 itmp = ord[i]; 
01362                 ord[i] = ord[j]; 
01363                 ord[j] = itmp; 
01364             }
01365         } while (i<j);
01366         tmp = u[left]; 
01367         u[left] = u[j]; 
01368         u[j] = tmp; 
01369         itmp = ord[left]; 
01370         ord[left] = ord[j]; 
01371         ord[j] = itmp; 
01372         Vnm_dqsortOrdR(u, ord, left, j-1);
01373         Vnm_dqsortOrdR(u, ord, j+1, right);
01374     }
01375 }
01376 

Generated on Wed Oct 20 2010 11:12:15 for APBS by  doxygen 1.7.2