(root)/
gawk-5.2.2/
extension/
time.c
       1  /*
       2   * time.c - Builtin functions that provide time-related functions.
       3   */
       4  
       5  /*
       6   * Copyright (C) 2012, 2013, 2014, 2018, 2022, 2023,
       7   * the Free Software Foundation, Inc.
       8   *
       9   * This file is part of GAWK, the GNU implementation of the
      10   * AWK Programming Language.
      11   *
      12   * GAWK is free software; you can redistribute it and/or modify
      13   * it under the terms of the GNU General Public License as published by
      14   * the Free Software Foundation; either version 3 of the License, or
      15   * (at your option) any later version.
      16   *
      17   * GAWK is distributed in the hope that it will be useful,
      18   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      19   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20   * GNU General Public License for more details.
      21   *
      22   * You should have received a copy of the GNU General Public License
      23   * along with this program; if not, write to the Free Software
      24   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
      25   */
      26  
      27  #ifdef HAVE_CONFIG_H
      28  #include <config.h>
      29  #endif
      30  
      31  #include <stdio.h>
      32  #include <assert.h>
      33  #include <errno.h>
      34  #include <stdlib.h>
      35  #include <string.h>
      36  #include <stdbool.h>
      37  #include <unistd.h>
      38  
      39  #include <sys/types.h>
      40  #include <sys/stat.h>
      41  
      42  #ifdef __VMS
      43  #define HAVE_NANOSLEEP
      44  #define HAVE_GETTIMEOFDAY
      45  #ifdef gettimeofday
      46  #undef gettimeofday
      47  #endif
      48  #ifdef __ia64__
      49  /* nanosleep not working correctly on IA64 */
      50  static int
      51  vms_fake_nanosleep(struct timespec *rqdly, struct timespec *rmdly)
      52  {
      53  	int result;
      54  	struct timespec mtime1, mtime2;
      55  
      56  	result = nanosleep(rqdly, &mtime1);
      57  	if (result == 0)
      58  		return 0;
      59  
      60  	/* On IA64 it returns 100 nanoseconds early with an error */
      61  	if ((mtime1.tv_sec == 0) && (mtime1.tv_nsec <= 100)) {
      62  		mtime1.tv_nsec += 100;
      63  		result = nanosleep(&mtime1, &mtime2);
      64  		if (result == 0)
      65  			return 0;
      66  		if ((mtime2.tv_sec == 0) && (mtime2.tv_nsec <= 100)) {
      67  			return 0;
      68  		}
      69  	}
      70  	return result;
      71  }
      72  #define nanosleep(x,y) vms_fake_nanosleep(x, y)
      73  #endif
      74  #endif
      75  
      76  #include "gawkapi.h"
      77  
      78  #include "gettext.h"
      79  #define _(msgid)  gettext(msgid)
      80  #define N_(msgid) msgid
      81  
      82  static const gawk_api_t *api;	/* for convenience macros to work */
      83  static awk_ext_id_t ext_id;
      84  static const char *ext_version = "time extension: version 1.2";
      85  static awk_bool_t (*init_func)(void) = NULL;
      86  
      87  int plugin_is_GPL_compatible;
      88  
      89  #include <time.h>
      90  #if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
      91  #include <sys/time.h>
      92  #endif
      93  #if defined(HAVE_SELECT) && defined(HAVE_SYS_SELECT_H)
      94  #include <sys/select.h>
      95  #endif
      96  #if defined(HAVE_GETSYSTEMTIMEASFILETIME)
      97  #define WIN32_LEAN_AND_MEAN
      98  #include <windows.h>
      99  #endif
     100  
     101  /*
     102   * Returns time since 1/1/1970 UTC as a floating point value; should
     103   * have sub-second precision, but the actual precision will vary based
     104   * on the platform
     105   */
     106  static awk_value_t *
     107  do_gettimeofday(int nargs, awk_value_t *result, struct awk_ext_func *unused)
     108  {
     109  	double curtime;
     110  
     111  	assert(result != NULL);
     112  
     113  #if defined(HAVE_GETTIMEOFDAY)
     114  	{
     115  		struct timeval tv;
     116  		gettimeofday(&tv,NULL);
     117  		curtime = tv.tv_sec+(tv.tv_usec/1000000.0);
     118  	}
     119  #elif defined(HAVE_GETSYSTEMTIMEASFILETIME)
     120  	/* based on perl win32/win32.c:win32_gettimeofday() implementation */
     121  	{
     122  		union {
     123  			unsigned __int64 ft_i64;
     124  			FILETIME ft_val;
     125  		} ft;
     126  
     127  		/* # of 100-nanosecond intervals since January 1, 1601 (UTC) */
     128  		GetSystemTimeAsFileTime(&ft.ft_val);
     129  #ifdef __GNUC__
     130  #define Const64(x) x##LL
     131  #else
     132  #define Const64(x) x##i64
     133  #endif
     134  /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
     135  #define EPOCH_BIAS  Const64(116444736000000000)
     136  		curtime = (ft.ft_i64 - EPOCH_BIAS)/10000000.0;
     137  #undef Const64
     138  	}
     139  #else
     140  	/* no way to retrieve system time on this platform */
     141  	curtime = -1;
     142  	update_ERRNO_string(_("gettimeofday: not supported on this platform"));
     143  #endif
     144  
     145  	return make_number(curtime, result);
     146  }
     147  
     148  /*
     149   * Returns 0 if successful in sleeping the requested time;
     150   * returns -1 if there is no platform support, or if the sleep request
     151   * did not complete successfully (perhaps interrupted)
     152   */
     153  static awk_value_t *
     154  do_sleep(int nargs, awk_value_t *result, struct awk_ext_func *unused)
     155  {
     156  	awk_value_t num;
     157  	double secs;
     158  	int rc;
     159  
     160  	assert(result != NULL);
     161  
     162  	if (! get_argument(0, AWK_NUMBER, &num)) {
     163  		update_ERRNO_string(_("sleep: missing required numeric argument"));
     164  		return make_number(-1, result);
     165  	}
     166  	secs = num.num_value;
     167  
     168  	if (secs < 0) {
     169  		update_ERRNO_string(_("sleep: argument is negative"));
     170  		return make_number(-1, result);
     171  	}
     172  
     173  #if defined(HAVE_NANOSLEEP)
     174  	{
     175  		struct timespec req;
     176  
     177  		req.tv_sec = secs;
     178  		req.tv_nsec = (secs-(double)req.tv_sec)*1000000000.0;
     179  		if ((rc = nanosleep(&req,NULL)) < 0)
     180  			/* probably interrupted */
     181  			update_ERRNO_int(errno);
     182  	}
     183  #elif defined(HAVE_SELECT)
     184  	{
     185  		struct timeval timeout;
     186  
     187  		timeout.tv_sec = secs;
     188  		timeout.tv_usec = (secs-(double)timeout.tv_sec)*1000000.0;
     189  		if ((rc = select(0,NULL,NULL,NULL,&timeout)) < 0)
     190  			/* probably interrupted */
     191  			update_ERRNO_int(errno);
     192  	}
     193  #elif defined(HAVE_GETSYSTEMTIMEASFILETIME)
     194  	{
     195  		DWORD milliseconds = secs * 1000;
     196  
     197  		Sleep (milliseconds);
     198  		rc = 0;
     199  	}
     200  #else
     201  	/* no way to sleep on this platform */
     202  	rc = -1;
     203  	update_ERRNO_string(_("sleep: not supported on this platform"));
     204  #endif
     205  
     206  	return make_number(rc, result);
     207  }
     208  
     209  #ifndef HAVE_STRPTIME
     210  #include "../missing_d/strptime.c"
     211  #endif
     212  
     213  /*  do_strptime --- call strptime */
     214  
     215  static awk_value_t *
     216  do_strptime(int nargs, awk_value_t *result, struct awk_ext_func *unused)
     217  {
     218  	awk_value_t string, format;
     219  
     220  	assert(result != NULL);
     221  	make_number(0.0, result);
     222  
     223  	if (do_lint) {
     224  		if (nargs == 0) {
     225  			lintwarn(ext_id, _("strptime: called with no arguments"));
     226  			make_number(-1.0, result);
     227  			goto done0;
     228  		}
     229  	}
     230  
     231  	/* string is first arg, format is second arg */
     232  	if (! get_argument(0, AWK_STRING, & string)) {
     233  		fprintf(stderr, _("do_strptime: argument 1 is not a string\n"));
     234  		errno = EINVAL;
     235  		goto done1;
     236  	}
     237  	if (! get_argument(1, AWK_STRING, & format)) {
     238  		fprintf(stderr, _("do_strptime: argument 2 is not a string\n"));
     239  		errno = EINVAL;
     240  		goto done1;
     241  	}
     242  
     243  	struct tm broken_time;
     244  	memset(& broken_time, 0, sizeof(broken_time));
     245  	broken_time.tm_isdst = -1;
     246  	if (strptime(string.str_value.str, format.str_value.str, & broken_time) == NULL) {
     247  		make_number(-1.0, result);
     248  		goto done0;
     249  	}
     250  
     251  	time_t epoch_time = mktime(& broken_time);
     252  	make_number((double) epoch_time, result);
     253  	goto done0;
     254  
     255  done1:
     256  	update_ERRNO_int(errno);
     257  
     258  done0:
     259  	return result;
     260  }
     261  
     262  static awk_ext_func_t func_table[] = {
     263  	{ "gettimeofday", do_gettimeofday, 0, 0, awk_false, NULL },
     264  	{ "sleep", do_sleep, 1, 1, awk_false, NULL },
     265  	{ "strptime", do_strptime, 2, 2, awk_false, NULL },
     266  };
     267  
     268  /* define the dl_load function using the boilerplate macro */
     269  
     270  dl_load_func(func_table, time, "")