/*===========================================================================
  Copyright (C) 1995-2009 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 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence 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.
.COMMENTS    
             Provide miscellaneous host services. 
             The routines return time and date stamps,
             return cpu time used by the current process, translates host
             error codes and 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.
             Symbolic error codes for each function to be defined.
.VERSION  0.0 	25-Aug-1986   Definition.       J. D. Ponz
.VERSION  1.0 	28-Oct-1986   Programmation.    B.    Pirenne
.VERSION  1.1 	15-Mar-1987   Add oshela.       B. Pirenne
.VERSION  1.5 	14-Apr-1987   bsd-sysv compatible.  B.    Pirenne
.VERSION  1.6 	15-Jul-1987   oshcpu returns a real number; date through a
                                 structure. B. Pirenne
.VERSION  1.7 	10-Dec-1987   Cosmetic changes    I. Suisalu
.VERSION  1.8 	05-Oct-1988   Time edition simplifications. F. Ochsenbein
.VERSION  1.9 	01-Aug-1990   oshcmd takes care of buffer overflow. F. O.
.VERSION  2.0  	07-Aug-1990   Added oshtm oshtl (conversion long to structure)
					FO
.VERSION  2.1  	910911        Using memcpy() instead of bcopy(). CG
.VERSION  2.2   950502	      Adding oshmidvers. CG.

 090429		last modif
------------------------------------------------------------*/
/*
 * Define _POSIX_SOURCE to indicate
 * that this is a POSIX program
 */
#define _POSIX_SOURCE 1

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/times.h>
#include <time.h>
#include <osparms.h>
#include <proto_os.h>		/* ANSI-C prototyping */

#ifndef CLK_TCK
#define CLK_TCK	50
#endif

int oshcpu(op, ctime) 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.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.
         The cpu time is expressed in seconds, in a floating point format.
.RETURNS Value 0 on normal return.
         value -1 if the operation to do is unknown or if 
         the get operation was not preceded by an initialization.
.REMARKS System dependencies:
 --UNIX: times(3c)
------------------------------------------------------------*/
int op;		/* IN : operation to execute : INIT_CPU_CLOCK  \
		        to initialize timer, GET_CPU_CLOCK to get the time. */
float *ctime;	/* OUT: ctime is the cpu time passed since the init. op.; */
{
	struct tms buffer;  /* buffer to receive time accounting information */
	static time_t firstime=0L;
	time_t lastime; 

	switch (op) {
	case INIT_CPU_CLOCK : /**** Initialize timer */
		if(times(&buffer) == -1L) {
			oserror = errno;
			return(-1);
			}
		firstime = buffer.tms_utime + buffer.tms_stime 
			+ buffer.tms_cutime + buffer.tms_cstime; 
		*ctime = 0.;
		break;
	case GET_CPU_CLOCK : /**** get time */
		if(!(int)firstime){
			oserror=EINVAL;
			return(-1);
			}
		if(times(&buffer) == -1L) {
			oserror = errno;
			return(-1);
			}
		lastime = buffer.tms_utime + buffer.tms_stime + 
			buffer.tms_cutime + buffer.tms_cstime - firstime;
		/* 
		** conversion of the time from 1/HZ s. to sec. 
		*/
		*ctime = (float)lastime / CLK_TCK;
		break;
	default  : /**** Operation code error */
		oserror = EINVAL;
		return(-1);
	}
	return (0);
}

long oshtime() 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Gets CURRENT time. Precision is : 1 seconds.
.RETURNS Time (normally as seconds elapsed since Jan. 1, 1970)
.REMARKS 
------------------------------------------------------------*/
{
  return((long) time((time_t *)0));
}


struct tm *oshtm(clock) 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Convert time from long to structure
.RETURNS Address of a filled tm structure (see time.h)
------------------------------------------------------------*/
	long	clock;	/* IN: Time in seconds since Jan. 1, 1970	*/
{
	static	time_t	aclock;
  
  aclock = clock;
  return(gmtime(&aclock));
}

#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);
}

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 <time.h> (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:
 --UNIX: time(2)
------------------------------------------------------------*/
   char  *date_string;		/* OUT : date-time stamp  (was date_string[28] before) */
   struct tm *date_struct;	/* OUT : date-time structure (see description) */
{
	struct tm *dt;
	time_t	curseconds;
	int	i, m;
	static  char template[]="WW, DD MMM YYYY   hh:mm:ss";
	static 	char Day_list[]= "SuMoTuWeThFrSa";
	static 	char Month_list[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

	/*
	** get current time in seconds since 1/1/1970  
	*/
	if((curseconds = time((time_t *)0)) < 0) {
		oserror = errno;
		return(-1);
		}

	/* 
	** fill in the structure with date information 
	*/

	dt = localtime(&curseconds); 
	if (dt->tm_year < 1900)	dt->tm_year += 1900;
	memcpy((char *)date_struct,(char *)dt,sizeof(struct tm));

	/* 
	** now create a string with time and date according 
	** to the above picture
	*/

	for (i = 2*dt->tm_wday, m=0; m <= 1; m++)	
		template[m] = Day_list[i++];

	for (i = dt->tm_mday, m=5; m>=4; m--, i/=10)  
		template[m] = '0'+i%10;
	
	for (i = 3*dt->tm_mon, m = 7; m <= 9; m++)
		template[m] = Month_list[i++];
	
	for (i = dt->tm_year, m = 14; m >= 11; m--, i/=10)
		template[m] = '0' + i%10;
	
	for (i = dt->tm_hour, m = 19; m >= 18; m--, i/=10)
		template[m] = '0' + i%10;
	
	for (i = dt->tm_min, m = 22; m >= 21; m--, i/=10)
		template[m] = '0' + i%10;
	
	for (i = dt->tm_sec, m = 25; m >= 24; m--, i/=10)
		template[m] = '0' + i%10;
	
	/* ** now copy template to date_string 	*/

	m = 27;			/* sizeof(template) + 1  (change, if template changes!) */
	memcpy(date_string,template,(size_t)m);

	return(0);
}


int oshmsg(code, message)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Gets system error message.
.RETURNS Value 0 on normal return, -1 if the error code does not exist. 
.REMARKS System dependencies:
 --UNIX: sys_errlist[]
------------------------------------------------------------*/
int    code;		/* IN  : system error code */
char   *message;	/* OUT : system error message */
{
if (code < 0)
   {
   oserror = EINVAL;
   return(-1); 
   }

(void) strcpy(message,strerror(oserror));
return(0);
}

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. The status of the execution of the
         command in the other cases.
.REMARKS System dependencies:
 --UNIX: system(3S)
------------------------------------------------------------*/
char *command;			/* IN : system command */
char *input;			/* IN : standard input stream */
char *output;			/* IN : standard output stream */
char *error;			/* IN : error output stream */
{ 
	char buffer[256];
	char *p;
#define strappend(s)   strncpy(p,s,buffer+sizeof(buffer)-(p+1)), p += strlen(p)

	strncpy(buffer,command,sizeof(buffer)-1);
	buffer[sizeof(buffer)-1] = '\0';
	p = buffer + strlen(buffer);
	if(input != NULL) if (*input) {
		strappend(" <");
		strappend(input);
		}
	if(output != NULL) if (*output) {
		strappend(" >");
		strappend(output);
		}
	if(error != NULL) if (*error) {
		strappend(" 2>");
		strappend(error);
		}
	return(system(buffer));
}

#define MAX_CURRENT_WORKING_DIR 128
static char current_working_dir[MAX_CURRENT_WORKING_DIR];
int oshgetcwd(path)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Return current working directory.
.RETURNS Value 0 on normal return.  -1 on failure and oserror set.
.REMARKS System dependencies:
 --UNIX: getcwd(3)
------------------------------------------------------------*/
char **path;
{
  if (getcwd(current_working_dir,(size_t)MAX_CURRENT_WORKING_DIR) == NULL) {
    oserror = errno;
    return(-1);
    }
  else {
    *path = current_working_dir;
    return(0);
    }
}

int 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);
}

char *oshmidvers()
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE   Get MIDVERS string (located in patchlevel.h).
.RETURNS   Pointer to static variable MIDVERS
-------------------------------------------------------------------- */
{
    return("Midas version...");
}
