/*
 * %CopyrightBegin%
 * 
 * Copyright Ericsson AB 1999-2012. All Rights Reserved.
 * 
 * The contents of this file are subject to the Erlang Public License,
 * Version 1.1, (the "License"); you may not use this file except in
 * compliance with the License. You should have received a copy of the
 * Erlang Public License along with this software. If not, it can be
 * retrieved online at http://www.erlang.org/.
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 * 
 * %CopyrightEnd%
 */

/*
 * BIFs belonging to the 'os' module.
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include "sys.h"
#include "erl_vm.h"
#include "global.h"
#include "erl_process.h"
#include "error.h"
#include "erl_driver.h"
#include "bif.h"
#include "big.h"
#include "dist.h"
#include "erl_version.h"

/*
 * Return the pid for the Erlang process in the host OS.
 */

 /* return a timestamp */
BIF_RETTYPE os_timestamp_0(BIF_ALIST_0)
{
    Uint megasec, sec, microsec;
    Eterm* hp;

    get_sys_now(&megasec, &sec, &microsec);
    hp = HAlloc(BIF_P, 4);
    BIF_RET(TUPLE3(hp, make_small(megasec), make_small(sec),
		   make_small(microsec)));
}


BIF_RETTYPE os_getpid_0(BIF_ALIST_0)
{
     char pid_string[21]; /* enough for a 64 bit number */
     int n;
     Eterm* hp;
     sys_get_pid(pid_string); /* In sys.c */
     n = sys_strlen(pid_string);
     hp = HAlloc(BIF_P, n*2);
     BIF_RET(buf_to_intlist(&hp, pid_string, n, NIL));
}

BIF_RETTYPE os_getenv_0(BIF_ALIST_0)
{
    GETENV_STATE state;
    char *cp;
    Eterm* hp;
    Eterm ret;
    Eterm str;

    init_getenv_state(&state);

    ret = NIL;
    while ((cp = getenv_string(&state)) != NULL) {
	str = erts_convert_native_to_filename(BIF_P,(byte *)cp);
	hp = HAlloc(BIF_P, 2);
	ret = CONS(hp, str, ret);
    }

    fini_getenv_state(&state);

    return ret;
}

#define STATIC_BUF_SIZE 1024
BIF_RETTYPE os_getenv_1(BIF_ALIST_1)
{
    Process* p = BIF_P;
    Eterm str;
    Sint len;
    int res;
    char *key_str, *val;
    char buf[STATIC_BUF_SIZE];
    size_t val_size = sizeof(buf);

    key_str = erts_convert_filename_to_native(BIF_ARG_1,buf,STATIC_BUF_SIZE,
					      ERTS_ALC_T_TMP,1,0,&len);

    if (!key_str) {
	BIF_ERROR(p, BADARG);
    }

    if (key_str != &buf[0])
	val = &buf[0];
    else {
	/* len includes zero byte */
	val_size -= len;
	val = &buf[len];
    }
    res = erts_sys_getenv(key_str, val, &val_size);

    if (res < 0) {
    no_var:
	str = am_false;
    } else {
	if (res > 0) {
	    val = erts_alloc(ERTS_ALC_T_TMP, val_size);
	    while (1) {
		res = erts_sys_getenv(key_str, val, &val_size);
		if (res == 0)
		    break;
		else if (res < 0)
		    goto no_var;
		else
		    val = erts_realloc(ERTS_ALC_T_TMP, val, val_size);
	    }
	}
	str = erts_convert_native_to_filename(p,(byte *)val);
    }
    if (key_str != &buf[0])
	erts_free(ERTS_ALC_T_TMP, key_str);
    if (val < &buf[0] || &buf[sizeof(buf)-1] < val)
	erts_free(ERTS_ALC_T_TMP, val);
    BIF_RET(str);
}

BIF_RETTYPE os_putenv_2(BIF_ALIST_2)
{
    char def_buf_key[STATIC_BUF_SIZE];
    char def_buf_value[STATIC_BUF_SIZE];
    char *key_buf, *value_buf;

    key_buf = erts_convert_filename_to_native(BIF_ARG_1,def_buf_key,
					      STATIC_BUF_SIZE,
					      ERTS_ALC_T_TMP,0,0,NULL);
    if (!key_buf) {
	BIF_ERROR(BIF_P, BADARG);
    }
    value_buf = erts_convert_filename_to_native(BIF_ARG_2,def_buf_value,
						STATIC_BUF_SIZE,
						ERTS_ALC_T_TMP,1,0,
						NULL);
    if (!value_buf) {
	if (key_buf != def_buf_key) {
	    erts_free(ERTS_ALC_T_TMP, key_buf);
	}
	BIF_ERROR(BIF_P, BADARG);
    }
	    

    if (erts_sys_putenv(key_buf, value_buf)) {
	if (key_buf != def_buf_key) {
	    erts_free(ERTS_ALC_T_TMP, key_buf);
	}
	if (value_buf != def_buf_value) {
	    erts_free(ERTS_ALC_T_TMP, value_buf);
	}
	BIF_ERROR(BIF_P, BADARG);
    }
    if (key_buf != def_buf_key) {
	erts_free(ERTS_ALC_T_TMP, key_buf);
    }
    if (value_buf != def_buf_value) {
	erts_free(ERTS_ALC_T_TMP, value_buf);
    }
    BIF_RET(am_true);
}