text: /*
   *  SPRTF - Log output utility
   *
   *   Author: Geoff R. McLane <reports _at_ geoffair _dot_ info>
   *   License: GPL v2 (or later at your choice)
   *
   *   Revision 1.0.1  2012/11/06 13:01:25  geoff
   *   Revision 1.0.0  2012/10/17 00:00:00  geoff
   *
   *   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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, US
   *
   */
  
  // Module: sprtf.cxx
  // Debug log file output
  #include <stdio.h> // fopen()...
  #include <string.h> // strcpy
  #include <stdarg.h> // va_start, va_end, ...
  #ifdef _MSC_VER
  #include <WinSock2.h>
  #include <sys/timeb.h>
  #else /* !_MSC_VER */
  #include <sys/time.h> // gettimeoday(), struct timeval,...
  #endif /* _MSC_VER y/n */
  #include <time.h>
  #include <stdlib.h> // for exit() in unix
  #include "sprtf.h"
  
  #ifdef _MSC_VER
  #ifndef _CRT_SECURE_NO_DEPRECATE
  #define _CRT_SECURE_NO_DEPRECATE
  #endif // #ifndef _CRT_SECURE_NO_DEPRECATE
  #pragma warning( disable:4996 )
  #else
  #define strcmpi strcasecmp
  #endif 
  
  #ifndef MX_ONE_BUF
  #define MX_ONE_BUF 1024
  #endif
  #ifndef MX_BUFFERS
  #define MX_BUFFERS 1024
  #endif
  
  static char _s_strbufs[MX_ONE_BUF * MX_BUFFERS];
  static int iNextBuf = 0;
  
  char *GetNxtBuf()
  {
     iNextBuf++;
     if(iNextBuf >= MX_BUFFERS)
        iNextBuf = 0;
     return &_s_strbufs[MX_ONE_BUF * iNextBuf];
  }
  
  #define  MXIO     512
  #ifdef _MSC_VER // use local log
  static char def_log[] = "tempex.txt";
  #else
  static char def_log[] = "ex.log";
  #endif
  static char logfile[264] = "\0";
  static FILE * outfile = NULL;
  static int addsystime = 0;
  static int addsysdate = 0;
  static int addstdout = 1;
  static int addflush = 1;
  static int add2screen = 0;
  static int add2listview = 0;
  static int append_to_log = 0;
  
  #ifndef VFP
  #define VFP(a) ( a && ( a != (FILE *)-1 ) )
  #endif
  
  int   add_list_out( int val )
  {
     int i = add2listview;
     add2listview = val;
     return i;
  }
  
  int   add_std_out( int val )
  {
     int i = addstdout;
     addstdout = val;
     return i;
  }
  
  int   add_screen_out( int val )
  {
     int i = add2screen;
     add2screen = val;
     return i;
  }
  
  
  int   add_sys_time( int val )
  {
     int   i = addsystime;
     addsystime = val;
     return i;
  }
  
  int   add_sys_date( int val )
  {
     int   i = addsysdate;
     addsysdate = val;
     return i;
  }
  
  
  int   add_append_log( int val )
  {
     int   i = append_to_log;
     append_to_log = val;
     return i;
  }
  
  
  #ifdef _MSC_VER
  static const char *mode = "wb"; // in window sprtf looks after the line endings
  #else
  static const char *mode = "w";
  #endif
  
  int   open_log_file( void )
  {
     if (logfile[0] == 0)
        strcpy(logfile,def_log);
     if (append_to_log) {
  #ifdef _MSC_VER
          mode = "ab"; // in window sprtf looks after the line endings
  #else
          mode = "a";
  #endif
     }
     outfile = fopen(logfile, mode);
     if( outfile == 0 ) {
        outfile = (FILE *)-1;
        sprtf("ERROR: Failed to open log file [%s] ...\n", logfile);
        exit(1); /* failed */
        return 0;   /* failed */
     }
     return 1; /* success */
  }
  
  void close_log_file( void )
  {
     if( VFP(outfile) ) {
        fclose(outfile);
     }
     outfile = NULL;
  }
  
  char * get_log_file( void )
  {
     if (logfile[0] == 0)
        strcpy(logfile,def_log);
     if (outfile == (FILE *)-1) // disable the log file
         return (char *)"none";
     return logfile;
  }
  
  void   set_log_file( char * nf, int open )
  {
     if (logfile[0] == 0)
        strcpy(logfile,def_log);
     if ( nf && *nf && strcmpi(nf,logfile) ) {
        close_log_file(); // remove any previous
        strcpy(logfile,nf); // set new name
        if (strcmp(logfile,"none") == 0) { // if equal 'none'
            outfile = (FILE *)-1; // disable the log file
        } else if (open) {
            open_log_file();  // and open it ... anything previous written is 'lost'
        } else
            outfile = 0; // else set 0 to open on first write
     }
  }
  
  #ifdef _MSC_VER
  int gettimeofday(struct timeval *tp, void *tzp)
  {
  #ifdef WIN32
      struct _timeb timebuffer;
      _ftime(&timebuffer);
      tp->tv_sec = (long)timebuffer.time;
      tp->tv_usec = timebuffer.millitm * 1000;
  #else
      tp->tv_sec = time(NULL);
      tp->tv_usec = 0;
  #endif
      return 0;
  }
  
  #endif // _MSC_VER
  
  void add_date_stg( char *ps, struct timeval *ptv )
  {
      time_t curtime;
      struct tm * ptm;
      curtime = (ptv->tv_sec & 0xffffffff);
      ptm = localtime(&curtime);
      if (ptm) {
          strftime(EndBuf(ps),128,"%Y/%m/%d",ptm);
      }
  }
  
  void add_time_stg( char *ps, struct timeval *ptv )
  {
      time_t curtime;
      struct tm * ptm;
      curtime = (ptv->tv_sec & 0xffffffff);
      ptm = localtime(&curtime);
      if (ptm) {
          strftime(EndBuf(ps),128,"%H:%M:%S",ptm);
      }
  }
  
  char *get_date_stg()
  {
      char *ps;
      struct timeval tv;
      gettimeofday( (struct timeval *)&tv, (struct timezone *)0 );
      ps = GetNxtBuf();
      *ps = 0;
      add_date_stg( ps, &tv );
      return ps;
  }
  
  char *get_time_stg()
  {
      char *ps;
      struct timeval tv;
      gettimeofday( (struct timeval *)&tv, (struct timezone *)0 );
      ps = GetNxtBuf();
      *ps = 0;
      add_time_stg( ps, &tv );
      return ps;
  }
  
  char *get_date_time_stg()
  {
      char *ps;
      struct timeval tv;
      gettimeofday( (struct timeval *)&tv, (struct timezone *)0 );
      ps = GetNxtBuf();
      *ps = 0;
      add_date_stg( ps, &tv );
      strcat(ps," ");
      add_time_stg( ps, &tv );
      return ps;
  }
  
  static void oi( char * psin )
  {
      int len, w;
      char * ps = psin;
      if (!ps)
          return;
  
     len = (int)strlen(ps);
     if (len) {
  
        if( outfile == 0 ) {
           open_log_file();
        }
        if( VFP(outfile) ) {
            char *tb;
            if (addsysdate) {
                tb = GetNxtBuf();
                len = sprintf( tb, "%s - %s", get_date_time_stg(), ps );
                ps = tb;
            } else if( addsystime ) {
                tb = GetNxtBuf();
                len = sprintf( tb, "%s - %s", get_time_stg(), ps );
                ps = tb;
            }
  
           w = (int)fwrite( ps, 1, len, outfile );
           if( w != len ) {
              fclose(outfile);
              outfile = (FILE *)-1;
              sprtf("WARNING: Failed write to log file [%s] ...\n", logfile);
              exit(1);
           } else if (addflush) {
              fflush( outfile );
           }
        }
  
        if( addstdout ) {
           fwrite( ps, 1, len, stdout );
        }
  #ifdef ADD_LISTVIEW
         if (add2listview) {
             LVInsertItem(ps);
         } 
  #endif // ADD_LISTVIEW
  #ifdef ADD_SCREENOUT
         if (add2screen) {
            Add_String(ps);    // add string to screen list
         }
  #endif // #ifdef ADD_SCREENOUT
     }
  }
  
  #ifdef _MSC_VER
  // service to ensure line endings in windows only
  static void	prt( char * ps )
  {
      static char _s_buf[1024];
  	char * pb = _s_buf;
  	size_t i, j, k;
  	char   c, d;
      i = strlen(ps);
  	k = 0;
  	d = 0;
  	if(i) {
  		k = 0;
  		d = 0;
  		for( j = 0; j < i; j++ ) {
  			c = ps[j];
  			if( c == 0x0d ) {
  				if( (j+1) < i ) {
  					if( ps[j+1] != 0x0a ) {
  						pb[k++] = c;
  						c = 0x0a;
  					}
              } else {
  					pb[k++] = c;
  					c = 0x0a;
  				}
  			} else if( c == 0x0a ) {
  				if( d != 0x0d ) {
  					pb[k++] = 0x0d;
  				}
  			}
  			pb[k++] = c;
  			d = c;
  			if( k >= MXIO ) {
  				pb[k] = 0;
  				oi(pb);
  				k = 0;
  			}
  		}	// for length of string
  		if( k ) {
  			//if( ( gbCheckCrLf ) &&
  			//	( d != 0x0a ) ) {
  				// add Cr/Lf pair
  				//pb[k++] = 0x0d;
  				//pb[k++] = 0x0a;
  				//pb[k] = 0;
  			//}
  			pb[k] = 0;
  			oi( pb );
  		}
  	}
  }
  #endif // #ifdef _MSC_VER
  
  int direct_out_it( char *cp )
  {
  #ifdef _MSC_VER
      prt(cp);
  #else
      oi(cp);
  #endif
      return (int)strlen(cp);
  }
  
  // STDAPI StringCchVPrintf( OUT LPTSTR  pszDest,
  //   IN  size_t  cchDest, IN  LPCTSTR pszFormat, IN  va_list argList );
  int MCDECL sprtf( const char *pf, ... )
  {
     static char _s_sprtfbuf[M_MAX_SPRTF+4];
     char * pb = _s_sprtfbuf;
     int   i;
     va_list arglist;
     va_start(arglist, pf);
     i = vsprintf( pb, pf, arglist );
     va_end(arglist);
  #ifdef _MSC_VER
     prt(pb); // ensure CR/LF
  #else
     oi(pb);
  #endif
     return i;
  }
  
  #ifdef UNICODE
  // WIDE VARIETY
  static void wprt( PTSTR ps )
  {
     static char _s_woibuf[1024];
     char * cp = _s_woibuf;
     int len = (int)lstrlen(ps);
     if(len) {
        int ret = WideCharToMultiByte( CP_ACP, // UINT CodePage,            // code page
           0, // DWORD dwFlags,            // performance and mapping flags
           ps,   // LPCWSTR lpWideCharStr,    // wide-character string
           len,     // int cchWideChar,          // number of chars in string.
           cp,      // LPSTR lpMultiByteStr,     // buffer for new string
           1024,    // int cbMultiByte,          // size of buffer
           NULL,    // LPCSTR lpDefaultChar,     // default for unmappable chars
           NULL );  // LPBOOL lpUsedDefaultChar  // set when default char used
        //oi(cp);
        prt(cp);
     }
  }
  
  int MCDECL wsprtf( PTSTR pf, ... )
  {
     static WCHAR _s_sprtfwbuf[1024];
     PWSTR pb = _s_sprtfwbuf;
     int   i = 1;
     va_list arglist;
     va_start(arglist, pf);
     *pb = 0;
     StringCchVPrintf(pb,1024,pf,arglist);
     //i = vswprintf( pb, pf, arglist );
     va_end(arglist);
     wprt(pb);
     return i;
  }
  
  #endif // #ifdef UNICODE
  
  // eof - sprtf.cxx
  