/*
 * Copyright (c) 2003-2015
 * Distributed Systems Software.  All rights reserved.
 * See the file LICENSE for redistribution information.
 *
 * $Id: misc.h 2837 2015-08-24 22:33:38Z brachman $
 */

#ifndef _MISC_H_
#define _MISC_H_

#include <time.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Little-endian 32-bit encode X into byte vector PP.
 */
static inline void
lendian_enc32(void *pp, uint32_t x)
{
  uint8_t *p = (uint8_t *) pp;

  p[0] = (x >>  0) & 0xff;
  p[1] = (x >>  8) & 0xff;
  p[2] = (x >> 16) & 0xff;
  p[3] = (x >> 24) & 0xff;
}

/*
 * Return the little-endian 32-bit decoding of byte vector PP.
 */
static inline uint32_t
lendian_dec32(const void *pp)
{
  const uint8_t *p = (uint8_t const *) pp;

  return((uint32_t) (p[0])
		 + ((uint32_t) (p[1]) << 8)
		 + ((uint32_t) (p[2]) << 16)
		 + ((uint32_t) (p[3]) << 24));
}

/*
 * Little-endian 64-bit encode X into byte vector PP.
 */
static inline void
lendian_enc64(void *pp, uint64_t x)
{
  uint8_t *p = (uint8_t *) pp;

  p[0] = (x >>  0) & 0xff;
  p[1] = (x >>  8) & 0xff;
  p[2] = (x >> 16) & 0xff;
  p[3] = (x >> 24) & 0xff;
  p[4] = (x >> 32) & 0xff;
  p[5] = (x >> 40) & 0xff;
  p[6] = (x >> 48) & 0xff;
  p[7] = (x >> 56) & 0xff;
}

/*
 * Return the little-endian 64-bit decoding of byte vector PP.
 */
static inline uint64_t
lendian_dec64(const void *pp)
{
  const uint8_t *p = (uint8_t const *) pp;

  return ((uint64_t) (p[0]) + ((uint64_t) (p[1]) << 8)
		  + ((uint64_t) (p[2]) << 16) + ((uint64_t) (p[3]) << 24)
		  + ((uint64_t) (p[4]) << 32) + ((uint64_t) (p[5]) << 40)
		  + ((uint64_t) (p[6]) << 48) + ((uint64_t) (p[7]) << 56));
}

static void inline
lendian_enc64_buf(unsigned char *to, uint64_t *from, size_t length)
{
  uint64_t *from_ptr;
  unsigned char *to_ptr;
  size_t nleft;

  to_ptr = to;
  from_ptr = from;
  nleft = length;

  while (nleft) {
	if (nleft >= sizeof(uint64_t)) {
	  lendian_enc64(to_ptr, *from_ptr);
	  to_ptr += sizeof(uint64_t);
	  from_ptr++;
	  nleft -= sizeof(uint64_t);
	}
	else if (nleft >= sizeof(uint32_t)) {
	  uint32_t *from_ptr32 = (uint32_t *) from_ptr;

	  lendian_enc32(to_ptr, *from_ptr32);
	  to_ptr += sizeof(uint32_t);
	  from_ptr32++;
	  nleft -= sizeof(uint32_t);
	}
	else {
	  fprintf(stderr, "Bug: unexpected copy remainder\n");
	  abort();
	}
  }
}

/*
 * Big-endian 32-bit encode X into byte vector PP.
 */
static inline void
bendian_enc32(void *pp, uint32_t x)
{
  uint8_t *p = (uint8_t *) pp;

  p[3] = (x >>  0) & 0xff;
  p[2] = (x >>  8) & 0xff;
  p[1] = (x >> 16) & 0xff;
  p[0] = (x >> 24) & 0xff;
}

/*
 * Return the big-endian 32-bit decoding of byte vector PP.
 */
static inline uint32_t
bendian_dec32(const void *pp)
{
  const uint8_t *p = (uint8_t const *) pp;

  return((uint32_t) (p[3])
		 + ((uint32_t) (p[2]) << 8)
		 + ((uint32_t) (p[1]) << 16)
		 + ((uint32_t) (p[0]) << 24));
}

/*
 * Big-endian 64-bit encode X into byte vector PP.
 */
static inline void
bendian_enc64(void *pp, uint64_t x)
{
  uint8_t *p = (uint8_t *) pp;

  p[7] = (x >>  0) & 0xff;
  p[6] = (x >>  8) & 0xff;
  p[5] = (x >> 16) & 0xff;
  p[4] = (x >> 24) & 0xff;
  p[3] = (x >> 32) & 0xff;
  p[2] = (x >> 40) & 0xff;
  p[1] = (x >> 48) & 0xff;
  p[0] = (x >> 56) & 0xff;
}

/*
 * Return the big-endian 64-bit decoding of byte vector PP.
 */
static inline uint64_t
bendian_dec64(const void *pp)
{
  const uint8_t *p = (uint8_t const *) pp;

  return((uint64_t) (p[7]) + ((uint64_t) (p[6]) << 8)
		 + ((uint64_t) (p[5]) << 16) + ((uint64_t) (p[4]) << 24)
		 + ((uint64_t) (p[3]) << 32) + ((uint64_t) (p[2]) << 40)
		 + ((uint64_t) (p[1]) << 48) + ((uint64_t) (p[0]) << 56));
}


extern int load_file(char *path, char **buf, size_t *size);
extern int filterthru(char **argv, char **env, int *read_fd, int *write_fd,
					  int *error_fd, pid_t *pidp);
extern char *make_rfc822_date_string(struct tm *tm, int yyyy, int use_gmt);
extern char *make_utc_date_string(struct tm *tm);
extern char *make_local_date_string(struct tm *tm, int show_zone);
extern char *make_short_local_date_string(struct tm *tm);
extern int utc_date_string_to_secs(time_t *secs, char *date);
extern char *make_datetime(struct tm *tm);
extern char *make_approx_relative_date(time_t rel_secs);
extern struct tm *parse_datetime(char *str, time_t *secs, char **endp);
extern char *tm_get_zone_name(struct tm *xtm);
extern long tm_get_gmtoff(struct tm *xtm);
extern char *escape_xml_attribute(char *str, int quote_char);

extern int touch_file(char *pathname, char *mode_str, char **errmsg);
extern int chmod_file(char *pathname, char *mode_str, char **errmsg);
extern int mkdir_file(char *dirname, char *mode_str, char **errmsg);

#ifdef __cplusplus
}
#endif

#endif
