Login
fsl.c at [d846a10d99]
Login

File src/fsl.c artifact c38bd0c046 part of check-in d846a10d99


/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 
/* vim: set ts=2 et sw=2 tw=80: */
/*
   Copyright (c) 2013 D. Richard Hipp
  
   This program is free software; you can redistribute it and/or
   modify it under the terms of the Simplified BSD License (also
   known as the "2-Clause License" or "FreeBSD License".)
  
   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.
  
   Author contact information:
     drh@hwaci.com
     http://www.hwaci.com/drh/
  
  *****************************************************************************
   This file houses some context-independent API routines as well as
   some of the generic helper functions and types.
*/

#include "fossil-scm/fossil-internal.h"
#include <assert.h>
#include <stdlib.h> /* malloc() and friends, qsort() */
#include <memory.h> /* memset() */
#include <time.h> /* strftime() and gmtime() */

#if defined(_WIN32) || defined(WIN32)
# include <io.h>
#define isatty(h) _isatty(h)
#else
# include <unistd.h> /* isatty() */
#endif
/* extern int isatty(int); */

#define MARKER(pfexp)                                               \
  do{ printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__);   \
    printf pfexp;                                                   \
  } while(0)

/*
  Please keep all fsl_XXX_empty initializers in one place (here)
  and lexically sorted.
*/
const fsl_acache fsl_acache_empty = fsl_acache_empty_m;
const fsl_branch_opt fsl_branch_opt_empty = fsl_branch_opt_empty_m;
const fsl_buffer fsl_buffer_empty = fsl_buffer_empty_m;
const fsl_card_F fsl_card_F_empty = fsl_card_F_empty_m;
const fsl_card_J fsl_card_J_empty = fsl_card_J_empty_m;
const fsl_card_Q fsl_card_Q_empty = fsl_card_Q_empty_m;
const fsl_card_T fsl_card_T_empty = fsl_card_T_empty_m;
const fsl_checkin_opt fsl_checkin_opt_empty = fsl_checkin_opt_empty_m;
const fsl_confirmer fsl_confirmer_empty = fsl_confirmer_empty_m;
const fsl_cx fsl_cx_empty = fsl_cx_empty_m;
const fsl_cx_config fsl_cx_config_empty = fsl_cx_config_empty_m;
const fsl_db fsl_db_empty = fsl_db_empty_m;
const fsl_deck fsl_cardset_empty = fsl_deck_empty_m;
const fsl_deck fsl_deck_empty = fsl_deck_empty_m;
const fsl_error fsl_error_empty = fsl_error_empty_m;
const fsl_fstat fsl_fstat_empty = fsl_fstat_empty_m;
const fsl_cx_init_opt fsl_cx_init_opt_default = fsl_cx_init_opt_default_m;
const fsl_cx_init_opt fsl_cx_init_opt_empty = fsl_cx_init_opt_empty_m;
const fsl_list fsl_list_empty = fsl_list_empty_m;
const fsl_outputer fsl_outputer_FILE = fsl_outputer_FILE_m;
const fsl_outputer fsl_outputer_empty = fsl_outputer_empty_m;
const fsl_pathfinder fsl_pathfinder_empty = fsl_pathfinder_empty_m;
const fsl_pq fsl_pq_empty = fsl_pq_empty_m;
const fsl_repo_create_opt fsl_repo_create_opt_empty = fsl_repo_create_opt_empty_m;
const fsl_sha1_cx fsl_sha1_cx_empty = fsl_sha1_cx_empty_m;
const fsl_state fsl_state_empty = fsl_state_empty_m;
const fsl_stmt fsl_stmt_empty = fsl_stmt_empty_m;
const fsl_timer_state fsl_timer_state_empty = fsl_timer_state_empty_m;
const fsl_xlinker fsl_xlinker_empty = fsl_xlinker_empty_m;
const fsl_xlinker_list fsl_xlinker_list_empty = fsl_xlinker_list_empty_m;
const fsl_zip_writer fsl_zip_writer_empty = fsl_zip_writer_empty_m;

const fsl_allocator fsl_allocator_stdalloc = {
fsl_realloc_f_stdalloc,
NULL
};

fsl_lib_configurable_t fsl_lib_configurable = {
  {/*allocator*/ fsl_realloc_f_stdalloc, NULL}
};

void * fsl_malloc( fsl_size_t n ){
  return n
    ? fsl_realloc(NULL, n)
    : NULL;
}

void fsl_free( void * mem ){
  if(mem) fsl_realloc(mem, 0);
}

void * fsl_realloc( void * mem, fsl_size_t n ){
#define FLCA fsl_lib_configurable.allocator
  if(!mem){
    /* malloc() */
    return n
      ? FLCA.f(FLCA.state, NULL, n)
      : NULL;
  }else if(!n){
    /* free() */
    FLCA.f(FLCA.state, mem, 0);
    return NULL;
  }else{
    /* realloc() */
    return FLCA.f(FLCA.state, mem, n);
  }
#undef FLC
}

#if 0
/* highly arguable */
  /**
      A convenience form of fsl_free() which frees multiple memory
      blocks of memory. It expects n to reflect the number of
      arugments after n, and it passes each argument to fsl_free().
      Results are undefined (but guaranteed to be poor!) if passed
      fewer than n additional arguments. It will leak if passed more
      than n additional arguments.
     
      This is a no-op if n is 0.
     
      Example:
     
      @code
      fsl_free_multiple( 3, foo, bar, baz );
      @endcode
     
      Design note: we "could" use a trailing NULL entry to signal end
      of list (and the original implementation did), but for the cases
      where this utility helps, it could lead to leaks because not all
      values need to have been allocated at the time this would be
      called.
   */
 void fsl_free_multiple( fsl_size_t n, ... );

void fsl_free_multiple( fsl_size_t n, ... ){
  fsl_size_t i;
  va_list va;
  va_start(va, n);
  for( i = 0; i < n; ++i ){
    fsl_free(va_arg(va,void *));
  }
  va_end(va);
}
  /**
      A convenience form of fsl_free() which frees multiple
      memory blocks. It calls fsl_free() on mem, then on
      each subsequent (void*) argument until an argument with
      the value 0/NULL is reached, at which point it stops.
      If !mem then this is a no-op.
     
      Results are undefined if the argument list has no trailing 0
      entry.
     
      Example:
     
      @code
      fsl_free_n( foo, bar, baz, 0 );
      @endcode
     
   */
void fsl_free_n( void * mem, ... ){
  va_list va;
  if(!mem) return;
  fsl_free(mem);
  va_start(va, mem);
  while( (mem = va_arg(va,void *)) ){
    fsl_free(mem);
  }
  va_end(va);
}
#endif

void * fsl_realloc_f_stdalloc(void * state, void * mem, fsl_size_t n){
  if(!mem){
    return malloc(n);
  }else if(!n){
    free(mem);
    return NULL;
  }else{
    return realloc(mem, n);
  }
}

char fsl_is_uuid(char const * str){
  fsl_size_t const len = fsl_strlen(str);
  return (FSL_UUID_STRLEN==len)
    && fsl_validate16(str, FSL_UUID_STRLEN);
}


void fsl_error_clear( fsl_error * err ){
  if(err){
    fsl_buffer_clear(&err->msg);
    *err = fsl_error_empty;
  }
}

void fsl_error_reset( fsl_error * err ){
  if(err){
    err->code = 0;
    err->msg.used = 0;
    if(err->msg.mem) err->msg.mem[0] = 0;
  }
}


int fsl_error_copy( fsl_error const * src, fsl_error * dest ){
  if(!src || !dest || (src==dest)) return FSL_RC_MISUSE;
  else {
    int rc = 0;
    dest->msg.used = 0;
    dest->code = src->code;
    if(FSL_RC_OOM!=src->code){
      rc = fsl_buffer_append( &dest->msg, src->msg.mem, src->msg.used );
    }
    return rc;
  }
}

void fsl_error_move( fsl_error * lower, fsl_error * higher ){
  fsl_error const err = *lower;
  *lower = *higher;
  lower->code = 0;
  lower->msg.used = 0;
  *higher = err;
}


int fsl_error_setv( fsl_error * err, int code, char const * fmt,
                    va_list args ){
  if(!err) return FSL_RC_MISUSE;
  else if(!code){ /* clear error state */
    err->code = 0;
    err->msg.used = 0;
    if(err->msg.mem){
      err->msg.mem[0] = 0;
    }
    return 0;
  }else{
    int rc = 0;
    err->msg.used = 0;
    err->code = code;
    if(FSL_RC_OOM!=code){
      rc = fmt
        ? fsl_buffer_appendfv(&err->msg, fmt, args)
        : fsl_buffer_append(&err->msg, fsl_rc_cstr(code), -1);
    }
    return rc ? rc : code;
  }
}

int fsl_error_set( fsl_error * err, int code, char const * fmt,
                   ... ){
  int rc;
  va_list args;
  va_start(args,fmt);
  rc = fsl_error_setv(err, code, fmt, args);
  va_end(args);
  return rc;
}


int fsl_error_get( fsl_error const * err, char const ** str, fsl_size_t * len ){
  if(!err) return FSL_RC_MISUSE;
  else{
    if(str) *str = err->msg.used
      ? (char const *)err->msg.mem
      : NULL;
    if(len) *len = err->msg.used;
    return err->code;
  }
}


char const * fsl_rc_cstr(int rc){
  fsl_rc_t const RC = (fsl_rc_t)rc
    /* we do this so that gcc will warn if the switch() below is
       missing any fsl_rc_t entries. */
    ;
  switch(RC){
#define STR(T) case FSL_RC_##T: return "FSL_RC_" #T
    STR(ACCESS);
    STR(ALREADY_EXISTS);
    STR(AMBIGUOUS);
    STR(BREAK);
    STR(CA_SYNTAX);
    STR(CHECKSUM_MISMATCH);
    STR(CONSISTENCY);
    STR(DB);
    STR(DELTA_INVALID_OPERATOR);
    STR(DELTA_INVALID_SEPARATOR);
    STR(DELTA_INVALID_SIZE);
    STR(DELTA_INVALID_TERMINATOR);
    STR(ERROR);
    STR(IO);
    STR(MISUSE);
    STR(NOT_A_CHECKOUT);
    STR(NOT_A_REPO);
    STR(NOT_FOUND);
    STR(NYI);
    STR(OK);
    STR(OOM);
    STR(RANGE);
    STR(REPO_MISMATCH);
    STR(REPO_NEEDS_REBUILD);
    STR(REPO_VERSION);
    STR(SIZE_MISMATCH);
    STR(STEP_DONE);
    STR(STEP_ERROR);
    STR(STEP_ROW);
    STR(TYPE);
#undef STR
  }
  return "Unknown result code";
}

char const * fsl_library_version(){
  return FSL_LIBRARY_VERSION;
}

char fsl_library_version_matches(char const * yourLibVersion){
  return 0 == fsl_strcmp(FSL_LIBRARY_VERSION, yourLibVersion);
}

fsl_double_t fsl_unix_to_julian( fsl_time_t unix_ ){
  return (unix_ * 1.0 / 86400.0 ) + 2440587.5;
}

fsl_double_t fsl_julian_now(){
  return fsl_unix_to_julian( time(0) );
}


int fsl_strcmp(const char *zA, const char *zB){
  if( zA==0 ){
    if( zB==0 ) return 0;
    return -1;
  }else if( zB==0 ){
    return +1;
  }else{
    int a, b;
    do{
      a = *zA++;
      b = *zB++;
    }while( a==b && a!=0 );
    return ((unsigned char)a) - (unsigned char)b;
  }
}


int fsl_strcmp_cmp( void const * lhs, void const * rhs ){
  return fsl_strcmp((char const *)lhs, (char const *)rhs);
}

int fsl_strncmp(const char *zA, const char *zB, fsl_size_t nByte){
  if( !zA ) return zB ? -1 : 0;
  else if( !zB ) return +1;
  else if(!nByte) return 0;
  else{
    int a, b;
    do{
      a = *zA++;
      b = *zB++;
    }while( a==b && a!=0 && (--nByte)>0 );
    return (nByte>0) ? (((unsigned char)a) - (unsigned char)b) : 0;
  }
}

  
int fsl_uuidcmp( fsl_uuid_cstr lhs, fsl_uuid_cstr rhs ){
  return fsl_strncmp( lhs, rhs, FSL_UUID_STRLEN );
}

int fsl_strnicmp(const char *zA, const char *zB, fsl_int_t nByte){
  if( zA==0 ){
    if( zB==0 ) return 0;
    return -1;
  }else if( zB==0 ){
    return +1;
  }
  if( nByte<0 ) nByte = (fsl_int_t)fsl_strlen(zB);
  return sqlite3_strnicmp(zA, zB, nByte);
}

int fsl_stricmp(const char *zA, const char *zB){
  fsl_int_t nByte;
  int rc;
  if( zA==0 ){
    if( zB==0 ) return 0;
    return -1;
  }else if( zB==0 ){
    return +1;
  }
  nByte = (fsl_int_t)fsl_strlen(zB);
  rc = sqlite3_strnicmp(zA, zB, nByte);
  if( rc==0 && zA[nByte] ) rc = 1;
  return rc;
}

int fsl_stricmp_cmp( void const * lhs, void const * rhs ){
  return fsl_stricmp((char const *)lhs, (char const *)rhs);
}

fsl_size_t fsl_strlen( char const * src ){
  fsl_size_t i = 0;
  if(src) for( ; *src; ++i, ++src ){}
  return i;
}

char * fsl_strndup( char const * src, fsl_int_t len ){
  if(!src) return NULL;
  else{
    fsl_buffer b = fsl_buffer_empty;
    if(len<0) len = (fsl_int_t)fsl_strlen(src);
    fsl_buffer_append( &b, src, len );
    return (char*)b.mem;
  }
}

char * fsl_strdup( char const * src ){
  return fsl_strndup(src, -1);
}


/*
   Return TRUE if the string begins with something that looks roughly
   like an ISO date/time string.  The SQLite date/time functions will
   have the final say-so about whether or not the date/time string is
   well-formed.
*/
char fsl_str_is_date(const char *z){
  if(!z || !*z) return 0;
  if( !fsl_isdigit(z[0]) ) return 0;
  if( !fsl_isdigit(z[1]) ) return 0;
  if( !fsl_isdigit(z[2]) ) return 0;
  if( !fsl_isdigit(z[3]) ) return 0;
  if( z[4]!='-') return 0;
  if( !fsl_isdigit(z[5]) ) return 0;
  if( !fsl_isdigit(z[6]) ) return 0;
  if( z[7]!='-') return 0;
  if( !fsl_isdigit(z[8]) ) return 0;
  if( !fsl_isdigit(z[9]) ) return 0;
  return 1;
}

char fsl_str_bool( char const * s ){
  switch(s ? *s : 0){
    case 0: case '0':
    case 'f': case 'F':
    case 'n': case 'N':
      return 0;
    case '1':
    case 't': case 'T':
    case 'y': case 'Y':
      return 1;
    default: {
      char buf[5] = {0,0,0,0,0};
      int i;
      for( i = 0; (i<5) && *s; ++i, ++s ){
        buf[i] = fsl_tolower(*s);
      }
      if(0==fsl_strncmp(buf, "off", 3)) return 0;
      return 1;
    }
  }
}

char * fsl_guess_user_name(){
  char const ** e;
  static char const * list[] = {
  "FOSSIL_USER",
#if defined(_WIN32)
  "USERNAME",
#else
  "USER",
  "LOGNAME",
#endif
  NULL /* sentinel */
  };
  char * rv = NULL;
  for( e = list; *e; ++e ){
    rv = fsl_getenv(*e);
    if(rv){
      /*
        Because fsl_getenv() has the odd requirement of needing
        fsl_filename_free(), and we want strings returned from this
        function to be safe for passing to fsl_free(), we have to dupe
        the string. We "could" block this off to happen only on the
        platforms for which fsl_getenv() requires an extra encoding
        step, but that would likely eventually lead to a bug.
      */
      char * kludge = fsl_strdup(rv);
      fsl_filename_free(rv);
      rv = kludge;
      break;
    }
  }
  return rv;
}

void fsl_fatal( int code, char const * fmt, ... ){
  static char inFatal = 0;
  if(inFatal){
    /* This can only happen if the fsl_appendv() bits
       call this AND trigger it via fsl_fprintf() below,
       neither of which is currently the case.
    */
    assert(!"fsl_fatal() called recursively.");
    abort();
  }else{
    va_list args;
    inFatal = 1;
    fsl_fprintf(stderr, "FATAL ERROR: code=%d (%s)\n",
                code, fsl_rc_cstr(code));
    va_start(args,fmt);
    fsl_fprintfv(stderr, fmt, args);
    va_end(args);
    fwrite("\n", 1, 1, stderr);
    exit(EXIT_FAILURE);
  }
}

#if 0
char * fsl_unix_to_iso8601( fsl_time_t u ){
  enum { BufSize = 20 };
  char buf[BufSize]= {0,};
  time_t const tt = (time_t)u;
  fsl_strftime( buf, BufSize, "%Y-%m-%dT%H:%M:%S", gmtime(&tt) );
  return fsl_strdup(buf);
}
#endif


char fsl_iso8601_to_julian( char const * zDate, fsl_double_t * out ){
  /* Adapted from this article:

     http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
  */
  char const * p = zDate;
  int y = 0, m = 0, d = 0;
  int h = 0, mi = 0, s = 0, f = 0;
  double j = 0;
  if(!zDate || !*zDate){
    return 0;
  }
#define DIG(NUM) if(!fsl_isdigit(*p)) return 0; \
  NUM=(NUM*10)+(*(p++)-'0')

  DIG(y);DIG(y);DIG(y);DIG(y);
  if('-'!=*p++) return 0;
  DIG(m);DIG(m);
  if('-'!=*p++) return 0;
  DIG(d);DIG(d);
  if('T' != *p++) return 0;
  DIG(h);DIG(h);
  if(':'!=*p++) return 0;
  DIG(mi);DIG(mi);
  if(':'!=*p++) return 0;
  DIG(s);DIG(s);
  if('.'==*p++){
    DIG(f);DIG(f);DIG(f);
  }
  if(out){
    typedef fsl_int64_t TI;
    TI A, B, C, E, F;
    if(m<3){
      --y;
      m += 12;
    }
    A = y/100;
    B = A/4;
    C = 2-A+B;
    E = (TI)(365.25*(y+4716));
    F = (TI)(30.6001*(m+1));
    j = C + d + E + F - 1524.5;
    j += ((1.0*h)/24) + ((1.0*mi)/1440) + ((1.0*s)/86400);
    if(0 != f){
      j += (1.0*f)/86400000;
    }
    *out = j;
  }
  return 1;
#undef DIG
}

fsl_time_t fsl_julian_to_unix( fsl_double_t JD ){
  return (JD - 2440587.5) * 86400;
}

char fsl_julian_to_iso8601( fsl_double_t J, char * out, char addMs ){
  /* Adapted from this article:

     http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
  */
  typedef fsl_int64_t TI;
  int Y, M, D, H, MI, S, F;
  TI ms;
  char * z = out;
  if(!out || (J<=0)) return 0;
  else{
    double Z;
    TI W, X;
    TI A, B;
    TI C, DD, E, F;

    Z = J + 0.5;
    W = (TI)((Z-1867216.25)/36524.25);
    X = W/4;
    A = (TI)(Z+1+W-X);
    B = A+1524;
    C = (TI)((B-122.1)/365.25);
    DD = (TI)(365.25 * C);
    E = (TI)((B-DD)/30.6001);
    F = (TI)(30.6001 * E);
    D = (int)(B - DD - F);
    M = (E<=13) ? (E-1) : (E-13);
    Y = (M<3) ? (C-4715) : (C-4716);
  }

  if(Y<0 || Y>9999) return 0;
  else if(M<1 || M>12) return 0;
  else if(D<1 || D>31) return 0;

  ms = (TI)((J-(TI)J) * 86400001.0)
    /* number of milliseconds in the fraction part of the JDay. The
       non-0 at the end works around a problem where SS.000 converts
       to (SS-1).999. This will only hide the bug for the cases i've
       seen it, and might introduce other inaccuracies
       elsewhere. Testing it against the current libfossil event table
       produces good results - at most a 1ms round-trip fidelity loss
       for the (currently ~1157) records being checked. The suffix of
       1.0 was found to be a decent value via much testing with the
       libfossil and fossil(1) source repos.
    */;

  if( (H = ms / 3600000) ){
    ms -= H * 3600000;
    H = (H + 12) % 24;
  }else{
    H = 12 /* astronomers start their day at noon. */;
  }
  if( (MI = ms / 60000) ) ms -= MI * 60000;
  if( (S = ms / 1000) ) ms -= S * 1000;
  assert(ms<1000);
  F = (int)(ms);

  assert(H>=0 && H<24);
  assert(MI>=0 && MI<60);
  assert(S>=0 && S<60);
  assert(F>=0 && F<1000);

  if(H<0 || H>23) return 0;
  else if(MI<0 || MI>59) return 0;
  else if(S<0 || S>59) return 0;
  else if(F<0 || F>999) return 0;
#define UGLY_999_KLUDGE 1
  /* The fossil(1) repo has 27 of 10041 records which exhibit the
     SS.999 behaviour commented on above. With this kludge, that
     number drops to 0. But it's still an ugly, ugly kludge.
     OTOH, the chance of the .999 being correct is 1 in 1000,
     whereas we see "correct" behaviour more often (2.7 in 1000)
     with this workaround.
   */
#if UGLY_999_KLUDGE
  if(999==F){
    char oflow = 0;
    int s2 = S, mi2 = MI, h2 = H;
    if(++s2 == 60){ /* Overflow minute */
      s2 = 0;
      if(++mi2 == 60){ /* Overflow hour */
        mi2 = 0;
        if(++h2 == 24){ /* Overflow day */
          /* leave this corner-corner case in place */
          oflow = 1;
        }
      }
    }
    /* MARKER(("UGLY 999 KLUDGE (A): H=%d MI=%d S=%d F=%d\n", H, MI, S, F)); */
    if(!oflow){
      F = 0;
      S = s2;
      MI = mi2;
      H = h2;
      /* MARKER(("UGLY 999 KLUDGE (B): H=%d MI=%d S=%d F=%d\n", H, MI, S, F)); */
    }
  }
#endif
#undef UGLY_999_KLUDGE
  *(z++) = '0'+(Y/1000);
  *(z++) = '0'+(Y%1000/100);
  *(z++) = '0'+(Y%100/10);
  *(z++) = '0'+(Y%10);
  *(z++) = '-';
  *(z++) = '0'+(M/10);
  *(z++) = '0'+(M%10);
  *(z++) = '-';
  *(z++) = '0'+(D/10);
  *(z++) = '0'+(D%10);
  *(z++) = 'T';
  *(z++) = '0'+(H/10);
  *(z++) = '0'+(H%10);
  *(z++) = ':';
  *(z++) = '0'+(MI/10);
  *(z++) = '0'+(MI%10);
  *(z++) = ':';
  *(z++) = '0'+(S/10);
  *(z++) = '0'+(S%10);
  if(addMs){
    *(z++) = '.';
    *(z++) = '0'+(F%1000/100);
    *(z++) = '0'+(F%100/10);
    *(z++) = '0'+(F%10);
  }
  *z = 0;
  return 1;
}

int fsl_confirmv( fsl_confirmation_f f, void * state, char const * fmt, va_list va ){
  int rc;
  fsl_buffer msg = fsl_buffer_empty;
  rc = fsl_buffer_appendfv(&msg, fmt, va);
  if(!rc){
    rc = f(state, (char const *)msg.mem, msg.used);
  }else{
    rc = 1;
  }
  fsl_buffer_clear(&msg);
  return rc;
}

int fsl_confirm( fsl_confirmation_f f, void * state, char const * fmt, ... ){
  int rc;
  va_list va;
  va_start(va, fmt);
  rc = fsl_confirmv( f, state, fmt, va );
  va_end(va);
  return rc;
}

int fsl_confirmation_f_int(void * state, char const * msg, fsl_size_t msgLen){
  int const rc = state ? *((int*)state) : FSL_CONFIRM_ERROR;
  switch(rc){
    case FSL_CONFIRM_ERROR:
    case FSL_CONFIRM_YES:
    case FSL_CONFIRM_YES_ALL:
    case FSL_CONFIRM_NO:
    case FSL_CONFIRM_NO_ALL:
      return rc;
    default:
      return FSL_CONFIRM_ERROR;
  }
}

#if FSL_CONFIG_ENABLE_TIMER
/**
   For the fsl_timer_xxx() family of functions...
*/
#ifdef _WIN32
# include <windows.h>
#else
# include <sys/time.h>
# include <sys/resource.h>
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
#endif
#endif
/* FSL_CONFIG_ENABLE_TIMER */

/**
   Get user and kernel times in microseconds.
*/
static void fsl_cpu_times(fsl_uint64_t *piUser, fsl_uint64_t *piKernel){
#if !FSL_CONFIG_ENABLE_TIMER
  *piUser = *piKernel = 0U;
#else
#ifdef _WIN32
  FILETIME not_used;
  FILETIME kernel_time;
  FILETIME user_time;
  GetProcessTimes(GetCurrentProcess(), &not_used, &not_used,
                  &kernel_time, &user_time);
  if( piUser ){
     *piUser = ((((fsl_uint64_t)user_time.dwHighDateTime)<<32) +
                         (fsl_uint64_t)user_time.dwLowDateTime + 5)/10;
  }
  if( piKernel ){
     *piKernel = ((((fsl_uint64_t)kernel_time.dwHighDateTime)<<32) +
                         (fsl_uint64_t)kernel_time.dwLowDateTime + 5)/10;
  }
#else
  struct rusage s;
  getrusage(RUSAGE_SELF, &s);
  if( piUser ){
    *piUser = ((fsl_uint64_t)s.ru_utime.tv_sec)*1000000 + s.ru_utime.tv_usec;
  }
  if( piKernel ){
    *piKernel =
              ((fsl_uint64_t)s.ru_stime.tv_sec)*1000000 + s.ru_stime.tv_usec;
  }
#endif
#endif
/* FSL_CONFIG_ENABLE_TIMER */
}


void fsl_timer_start(fsl_timer_state * ft){
  fsl_cpu_times( &ft->user, &ft->system );
}

fsl_uint64_t fsl_timer_fetch(fsl_timer_state const * t){
  fsl_uint64_t eu = 0, es = 0;
  fsl_cpu_times( &eu, &es );
  return (eu - t->user) + (es - t->system);
}

fsl_uint64_t fsl_timer_reset(fsl_timer_state * t){
  fsl_uint64_t const rc = fsl_timer_fetch(t);
  fsl_cpu_times( &t->user, &t->system );
  return rc;
}

fsl_uint64_t fsl_timer_stop(fsl_timer_state *t){
  fsl_uint64_t const rc = fsl_timer_fetch(t);
  *t = fsl_timer_state_empty;
  return rc;
}

unsigned int fsl_rgb_encode( int r, int g, int b ){
  return (unsigned int)(((r&0xFF)<<16) + ((g&0xFF)<<8) + (b&0xFF));
}

void fsl_rgb_decode( unsigned int src, int *r, int *g, int *b ){
  if(r) *r = (src&0xFF0000)>>16;
  if(g) *g = (src&0xFF00)>>8;
  if(b) *b = src&0xFF;
}

unsigned fsl_gradient_color(unsigned c1, unsigned c2, unsigned int n, unsigned int i){
  unsigned c;   /* Result color */
  unsigned x1, x2;
  if( i==0 || n==0 ) return c1;
  else if(i>=n) return c2;
  x1 = (c1>>16)&0xff;
  x2 = (c2>>16)&0xff;
  c = (x1*(n-i) + x2*i)/n<<16 & 0xff0000;
  x1 = (c1>>8)&0xff;
  x2 = (c2>>8)&0xff;
  c |= (x1*(n-i) + x2*i)/n<<8 & 0xff00;
  x1 = c1&0xff;
  x2 = c2&0xff;
  c |= (x1*(n-i) + x2*i)/n & 0xff;
  return c;
}


fsl_size_t fsl_simplify_sql( char * sql, fsl_int_t len ){
  char * wat = sql /* write pos */;
  char * rat = sql /* read pos */;
  char const * end /* one-past-the-end */;
  char inStr = 0 /* in an SQL string? */;
  char prev = 0 /* previous character. Sometimes. */;
  if(!sql || !*sql) return 0;
  else if(len < 0) len = fsl_strlen(sql);
  if(!len) return 0;
  end = sql + len;
  while( *rat && (rat < end) ){
    switch(*rat){
      case 0: break;
      case '\r':
      case '\n':
        /* Bug: we don't handle \r\n pairs. Because nobody
           should never have to :/. */
        if(inStr || (prev!=*rat)){
          /* Keep them as-is */
          prev = *wat++ = *rat++;
        }else{
          /* Collapse multiples into one. */
          ++rat;
        }
        continue;
      case ' ':
      case '\t':
      case '\v':
      case '\f':
        if(inStr){
          /* Keep them as-is */
          prev = *wat++ = *rat++;
        }else{
          /* Reduce to a single space. */
          /* f_out("prev=[%c] rat=[%c]\n", prev, *rat); */
          if(prev != *rat){
            *wat++ = ' ';
            prev = *rat;
          }
          ++rat;
        }
        continue;
      case '\'': /* SQL strings */
        prev = *wat++ = *rat++;
        if(!inStr){
          inStr = 1;
        }else if('\'' == *rat){
          /* Escaped quote */
          *wat++ = *rat++;
        }else{
          /* End of '...' string. */
          inStr = 0;
        }
        continue;
      default:
        prev = *wat++ = *rat++;
        continue;
    }
  }
  *wat = 0;
  return (fsl_size_t)(wat - sql);
}

/**
   Convenience form of fsl_simplify_sql() which assumes b holds an SQL
   string. It gets processed by fsl_simplify_sql() and its 'used'
   length potentially gets adjusted to match the adjusted SQL string.
*/
fsl_size_t fsl_simplify_sql_buffer( fsl_buffer * b ){
  return b->used = fsl_simplify_sql( (char *)b->mem, (fsl_int_t)b->used );
}


char fsl_isatty(int fd){
  return isatty(fd) ? 1 : 0;
}


#undef MARKER
#if defined(_WIN32) || defined(WIN32)
#undef isatty
#endif