/* @(#)osh.c 17.1.1.1 (ES0-DMD) 01/25/02 17:35:25 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .TYPE Module .NAME osh .LANGUAGE C .AUTHOR IPG-ESO Garching .CATEGORY Host operating system interfaces. Host services. .ENVIRONMENT VAX/VMS Version .COMMENTS Provide miscellaneous host services. The routines return time and date stamps, return cpu time used by the current process, translate logicals (environment) executes host commands. Time resolution is host dependent parameter. The routines return always a non-negative integer number on successful return. Otherwise, a value of -1 is set to indicate an error condition and the variable ``oserror'' contains the symbolic error code. .VERSION 0.0 25-Aug-1986 Definition. J. D. Ponz .VERSION 1.8 10-Feb-1988 VMS Version. F. ochsenbein. Difference oshgmt / oshtime .VERSION 1.9 05-Sep-1989 Changed some `unclever' macros... .VERSION 2.0 08-Aug-1990 Added oshtm / oshtl (time conversions) ------------------------------------------------------------*/ #define DEBUG 0 #include #include #ifdef EOF #undef EOF #endif MID_EXTERN int oserror; MID_EXTERN int vmserror; #include /* System */ #include /* System */ #include /* System */ #include /* System */ #include /* System */ #define stime long #define TR_MAX LNM$C_NAMLENGTH /* Maximal length translation */ #define len dsc$w_length #define s dsc$a_pointer typedef struct dsc$descriptor descript; #define void_string {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL_PTR(char)} #define InitDescript(text) \ {sizeof(text)-1, DSC$K_DTYPE_T, DSC$K_CLASS_S,text} #define SET_STRING(dsc,str) dsc.s = str, dsc.len = strlen(str) \ /* Set address & length of a string */ struct item { /* For TRNLNM system service */ unsigned short int len; unsigned short int item_code; void *addr; void *return_len; }; static long returned_len = 0; static char tr_buf[TR_MAX+1] = ""; #define FINISH goto FIN #define RETURN(x) FIN: return (oserror ? -1 : x) /*========================================================================== * Logical Name Translations *==========================================================================*/ /*==========================================================================*/ int oshset(logname, translation) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Inserts a logical name in the Environment. .RETURNS 0 (success) / -1 (failure) .REMARKS ------------------------------------------------------------*/ char *logname; /* IN : logical name */ char *translation; /* IN : Equivalence String */ { static descript sdv_table = InitDescript("LNM$PROCESS_TABLE"); static descript sdv_in = void_string; static struct { struct item Item; /* Equivalence string */ long end; } item_eq = { {0, LNM$_STRING, 0, &returned_len}, 0 }; oserror = 0; SET_STRING(sdv_in, logname); item_eq.Item.addr = translation, item_eq.Item.len = strlen(translation); vmserror = SYS$CRELNM(0,&sdv_table,&sdv_in,0,&item_eq); if ((vmserror&1) == 0) { oserror = ENXIO; FINISH;} FIN: return(oserror ? -1 : 0); } /*==========================================================================*/ char *oshenv(logname, table) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Translate logical names into physical names., according to a table. .RETURNS Address of equivalence name / NULL when logname not found .REMARKS table is used only in VMS environment (default is LNM$FILE_DEV). Translation is not case-dependent on VMS. Use recursive translation. ------------------------------------------------------------*/ char *logname; /* IN : logical name */ char *table; /* IN : name of the table to look for (VMS only) */ { static unsigned int lnmlength = 0; static unsigned int attr_case = LNM$M_CASE_BLIND; static unsigned int attr_list = 0; static descript sdv_table = void_string; static descript sdv_in = void_string; static descript sdv_out = InitDescript(tr_buf); static struct { struct item Item; /* Equivalence string */ long end; } item_eq = { {TR_MAX, LNM$_STRING, tr_buf, &sdv_out}, 0 }; static struct { struct item Item; /* Attributes of logical */ long end; } item_attr = { {sizeof(attr_list), LNM$_ATTRIBUTES, &attr_list, &lnmlength}, 0 }; register char *p; oserror = 0; SET_STRING(sdv_in, logname); p = (table ? table : "LNM$FILE_DEV"); p = (*p ? p : "LNM$FILE_DEV"); /* In case of void string */ SET_STRING(sdv_table, p); /* Write info as descriptors */ p = logname; vmserror = SYS$TRNLNM(&attr_case,&sdv_table,&sdv_in,0,&item_attr); if (vmserror != SS$_NORMAL) { oserror = ENXIO; FINISH;} /* Continue Translations while a translation exists */ while (attr_list & (LNM$M_EXISTS)) { SYS$TRNLNM(&attr_case,&sdv_table,&sdv_in,0,&item_eq); tr_buf[sdv_out.len] = EOS; /* Append the EOS character */ p = tr_buf; if (*p == 033) p += 4; /* Terminal translation */ if (tr_buf[--(sdv_out.len)] != ':') (sdv_out.len)++; sdv_in.s = sdv_out.s; sdv_in.len = sdv_out.len; if (SYS$TRNLNM(&attr_case,&sdv_table,&sdv_in,0,&item_attr) != SS$_NORMAL) FINISH; if (attr_list & (LNM$M_CONCEALED | LNM$M_TERMINAL)) FINISH; } FIN: return(oserror ? NULL_PTR(char) : p); } #if 0 /*==========================================================================*/ int oshtr(logname, phname, size) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Translate logical names into physical names. i.e. $KEYS ==> myfile.key .RETURNS Value 0 on normal return, -1 when logname not found (phname then contains an empty string) .REMARKS Simply use oshenv. ------------------------------------------------------------*/ char *logname; /* IN : logical name */ char *phname; /* OUT : logical physical name */ int size; /* IN : size of phname */ { register char *p, *q; if (size < 2) { oserror = EINVAL; FINISH; } /* Output too small */ *phname = EOS; p = oshenv(logname, NULL_PTR(char)); if (!p) FINISH; /* No translation... */ if (strlen(p) >= (size-1)) /* Translation is too long */ { oserror = ERANGE; FINISH;} for (q=phname; *p; p++, q++) *q = *p; *q = EOS; return (oserror ? -1 : 0); } #endif /*========================================================================== * Date / Time Services *==========================================================================*/ /*======================================================================*/ static long vmstime(q) /*+++++++++++++ .PURPOSE Converts the VAX time to standard .RETURNS Time as seconds elapsed since Jan. 1, 1970 .REMARKS The VAX time is 64 bits; origin = Nov. 17, 1858; units = 100ns. (40587 days before Jan 1, 1970) --------------*/ unsigned long *q; /* IN: VAX time */ { register double tt; register long t; tt = q[1] * 4294967296e0; tt = tt + q[0]; tt = tt / 1.e7 - (40587.e0 * 86400.e0); t = tt; return(t); } /*==========================================================================*/ long oshtime() /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Retrieves current (local!) time in seconds elapsed since Jan. 1, 1970, 0h. .RETURNS The time in seconds. .REMARKS ------------------------------------------------------------*/ { static long qtime[2]; SYS$GETTIM(qtime); return(vmstime(qtime)); } #define Jan1_1970 135140L /* Date in 400-yr cycle */ #define Jan1_1980 138792L /* Date in 400-yr cycle */ #define Jan1_2000 0L /* Date in 400-yr cycle */ long oshtl(T) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Convert time structure into seconds since Jan. 1, 1970 .RETURNS The time in seconds. .REMARKS Computation is done here, system call seems to be non-existent... ------------------------------------------------------------*/ struct tm *T; /* IN: Time structure to convert */ { register long int j, y, t; /* Compute Day of 400 yr cycle */ y = T->tm_year; if (y < 1000) y += 1900; y %= 400; y += 400; /* To be sure j is positive */ j = y - (11 - T->tm_mon)/10; t = ((1461L*j)/4 + (306L * ((T->tm_mon+10)%12) + 5)/10 - (3* ((j + 100L)/100L))/4 + T->tm_mday + 59L) % 146097L; /* Compute Week day */ T->tm_wday = (t+6L)%7L; t -= Jan1_1970; /* Origin = Jan 1, 1970 */ if (t < -24855) t += 146097L; if (t > 24855) t -= 146097L; /* Transform Day into seconds */ if (t < -24855) t = -24855; if (t > 24855) t = 24855; t = t * 86400L + T->tm_hour * 3600L + T->tm_min * 60L + T->tm_sec; return(t); } struct tm *oshtm(clock) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Convert time (long) as time structure .RETURNS Equivalent structure with filled items .REMARKS VMS localtime is completely wrong for dates < Jan 1, 1970 !!! ------------------------------------------------------------*/ long clock; /* IN: Time as seconds since Jan. 1, 1970 */ { long t, days, y; static struct tm T; static unsigned char month[12]={31,28,31,30,31,30,31,31,30,31,30,31}; t = clock; days = t/86400L; if (t < 0) days--; t -= (days*86400L); days += (t/86400L); t %= 86400L; T.tm_sec = t%60; t /= 60; T.tm_min = t%60; T.tm_hour = t/60; /* Compute Week day */ T.tm_wday = (days+Jan1_1970+6L)%7L; days += (70L*365L + 18L); /* Offset 1900 */ y = (4L*days)/1461L; T.tm_year = y; T.tm_yday = days - 365L*y - (y+3)/4; /* Compute mon + mday from yday */ month[1] = (y&3 ? 28 : 29); for (y=T.tm_yday, t=0; y>=month[t]; y -= month[t], t++) ; T.tm_mon = t; T.tm_mday = y+1; return(&T); } /*==========================================================================*/ long oshgmt() /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Retrieves GMT time in seconds elapsed since Jan. 1, 1970, 0h. .RETURNS The time in seconds. .REMARKS ------------------------------------------------------------*/ { static long qtime[2] ; static int TU = 0; register char *p; char *oshenv(); p = oshenv("TIMEZONE", NULL_PTR(char)); if (p) TU = atoi(p); /* Get GMT difference */ SYS$GETTIM(qtime); return(vmstime(qtime) - TU*60); } #if 0 /*==========================================================================*/ long oshcpu(op, ftime) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Gets CPU time. Precision is : hundreds of seconds. Cpu time returned is the sum of the time spend for both system tasks and process itself needed for the completion of the task. .RETURNS Elapsed CPU time in `clock-ticks' (1/100 s) for VMS -1 if the operation to do is unknown or if the get operation was not preceded by an initialization. .REMARKS On MS-DOS, cpu time is equated to elapsed time... ------------------------------------------------------------*/ int op; /* IN : operation to execute : INIT_CLOCK / GET_CLOCK */ float *ftime; /* OUT: CPU time in seconds */ { long lastime; static long firstime = 0; static int param = 2; oserror = 0; if (ftime) *ftime = 0.e0; switch (op) { case INIT_CLOCK : /**** Initialize timer */ lastime = 0; vmserror = LIB$INIT_TIMER(); if (!(vmserror&1)) oserror = EINTR; break; case GET_CLOCK : /**** get time */ vmserror = LIB$STAT_TIMER(¶m,&lastime); if (ftime) *ftime = lastime, *ftime /= 1.e2; if (!(vmserror&1)) oserror = EINTR; break; default : /**** Operation code error */ oserror = EINVAL; return(-1); } return (oserror ? -1 : lastime); } /*==========================================================================*/ long oshela(op, ftime) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Gets ELAPSED time. Precision is : 1 seconds. .RETURNS Elapsed time (s) on normal return. Value -1 if the operation to do is unknown or if the get operation was not preceded by an initialization. .REMARKS ------------------------------------------------------------*/ int op; /* IN: operation INIT_CLOCK / GET_CLOCK */ long *ftime; /* OUT: Elapsed time in seconds */ { static long firstime = 0; register long lastime; if (ftime) *ftime = 0; oserror = 0; switch (op) { case INIT_CLOCK : /**** Initialize timer */ lastime = 0; firstime = oshtime(); break; case GET_CLOCK : /**** get time */ lastime = oshtime() - firstime; if (ftime) *ftime = lastime; break; default : /**** Operation code error */ oserror = EINVAL; } return (oserror ? -1 : lastime); } #endif /*==========================================================================*/ int oshcmd(command, input, output, error) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Executes system command(maybe with arguments). The routine defines also the pathnames for standard input, output and error units. Enviroment variable SHELL must be defined. .RETURNS Value 0 on normal return / -1 if error. .REMARKS error parameter ignored for VMS. ------------------------------------------------------------*/ char *command; /* IN : system command */ char *input; /* IN : standard input stream */ char *output; /* IN : standard output stream */ char *error; /* IN : error output stream */ { static unsigned int attr_list = 0; static descript sdv_com = void_string; static descript sdv_in = void_string; descript *in, *out; static descript sdv_out = InitDescript(tr_buf); oserror = 0; SET_STRING(sdv_com, command); in = (input ? &sdv_in : 0); out = (output ? &sdv_out: 0); if (in) SET_STRING(sdv_in, input); if (out) SET_STRING(sdv_out, output); vmserror = LIB$SPAWN(&sdv_com, in, out); if (!(vmserror&1)) oserror = EINTR; return (oserror ? -1 : 0); } /*==========================================================================*/ int oshexec(command) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Executes system command(maybe with arguments). .RETURNS Value 0 on normal return / -1 if error. .REMARKS Stops the program ! ------------------------------------------------------------*/ char *command; /* IN : system command */ { static descript sdv_com = void_string; oserror = 0; SET_STRING(sdv_com, command); vmserror = LIB$DO_COMMAND(&sdv_com); if (!(vmserror&1)) oserror = EINTR; return (oserror ? -1 : 0); } char * oshmcpy(s1, s2, n) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE copies n characters from memory area s2 to s1. .RETURNS It returns s1. .REMARKS System dependencies: none. ------------------------------------------------------------*/ register char *s1, *s2; register int n; { register char *os1 = s1; while (--n >= 0) *s1++ = *s2++; return (os1); } int oshdate(date_string, date_struct) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Gets date and time stamp. No special structure adopted. .RETURNS A pointer to the time structure is defined in (system) {\begin{TeX} \begin{itemize} \item int tm_year number \item int tm_mon number [0-11] \item int tm_mday [1-31] \item int tm_yday [0-355] \item int tm_wday [0-6] (Sunday = 0) \item int tm_hour [0-23] \item int tm_min [0-59] \item int tm_sec [0-59]. \item int tm_saving \end{itemize} \end{TeX}} .REMARKS System dependencies: --Not implemented for VMS ------------------------------------------------------------*/ char date_string[28]; /* OUT : date-time stamp */ struct tm *date_struct; /* OUT : date-time structure (see description) */ { return(-1); } oshchdir(path) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Change current working directory. .RETURNS Value 0 on normal return. -1 on failure and oserror set. .REMARKS System dependencies: --UNIX: chdir(3) ------------------------------------------------------------*/ char *path; { if (chdir(path) == -1) { oserror = errno; return(-1); } else return(0); }