/* -*- 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 implements the i/o-related parts of the library.
*/
#include "fossil-scm/fossil-internal.h"
#include <assert.h>
#include <errno.h>

/* Only for debugging */
#include <stdio.h>
#define MARKER(pfexp)                                               \
  do{ printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__);   \
    printf pfexp;                                                   \
  } while(0)

/**
 ** fsl_appendf_f() impl which sends its output to fsl_output(). state
 ** must be a (fsl_cx*).
 */
static fsl_int_t fsl_appendf_f_fsl_output( void * state, char const * s,
                                           fsl_int_t n ){
  return fsl_output( (fsl_cx *)state, s, (fsl_size_t)n )
    ? -1
    : n;
}

int fsl_outputfv( fsl_cx * f, char const * fmt, va_list args ){
  if(!f || !fmt) return FSL_RC_MISUSE;
  else if(!*fmt) return FSL_RC_RANGE;
  else{
    long const prc = fsl_appendfv( fsl_appendf_f_fsl_output,
                                   f, fmt, args );
    return (prc>=0) ? 0 : FSL_RC_IO;
  }
}

    
int fsl_outputf( fsl_cx * f, char const * fmt, ... ){
  if(!f || !fmt) return FSL_RC_MISUSE;
  else if(!*fmt) return FSL_RC_RANGE;
  else{
    int rc;
    va_list args;
    va_start(args,fmt);
    rc = fsl_outputfv( f, fmt, args );
    va_end(args);
    return rc;
  }
}


int fsl_output( fsl_cx * cx, void const * src, fsl_size_t n ){
  if(!cx || !src) return FSL_RC_MISUSE;
  else if(!n || !cx->output.out) return 0;
  else return cx->output.out( cx->output.state.state,
                              src, n );
}

int fsl_flush( fsl_cx * f ){
  return f
    ? (f->output.flush
       ? f->output.flush(f->output.state.state)
       : 0)
    : FSL_RC_MISUSE;
}


int fsl_flush_f_FILE(void * _FILE){
  return _FILE
    ? (fflush((FILE*)_FILE) ? fsl_errno_to_rc(errno, FSL_RC_IO) : 0)
    : FSL_RC_MISUSE;
}

int fsl_output_f_FILE( void * state,
                       void const * src, fsl_size_t n ){
  return !state
    ? FSL_RC_MISUSE
    : ((1 == fwrite(src, n, 1, state ? (FILE*)state : stdout))
       ? 0
       : FSL_RC_IO);
}

int fsl_input_f_FILE( void * state, void * dest, fsl_size_t * n ){
  FILE * f = (FILE*) state;
  if( !state || !dest || !n ) return FSL_RC_MISUSE;
  else if( !*n ) return FSL_RC_RANGE;
  *n = (fsl_size_t)fread( dest, 1, *n, f );
  return *n
    ? 0
    : (feof(f) ? 0 : FSL_RC_IO);
}

void fsl_finalizer_f_FILE( void * state, void * mem ){
  if(mem){
    fsl_fclose((FILE*)mem);
  }
}

#undef MARKER
