Login
io.c at [6ecdbab284]
Login

File src/io.c artifact 0308118c51 part of check-in 6ecdbab284


/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 
/* vim: set ts=2 et sw=2 tw=80: */
/*
  Copyright 2013-2021 The Libfossil Authors, see LICENSES/BSD-2-Clause.txt

  SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  SPDX-FileCopyrightText: 2021 The Libfossil Authors
  SPDX-ArtifactOfProjectName: Libfossil
  SPDX-FileType: Code

  Heavily indebted to the Fossil SCM project (https://fossil-scm.org).
*/
/*************************************************************************
  This file implements the generic i/o-related parts of the library.
*/
#include "fossil-scm/internal.h"
#include <assert.h>
#include <errno.h>
#include <string.h> /* memcmp() */

/* 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 int fsl_output_f_fsl_output( void * state, void const * s,
                                    fsl_size_t n ){
  return fsl_output( (fsl_cx *)state, s, n );
}


int fsl_outputfv( fsl_cx * const f, char const * fmt, va_list args ){
  if(!f || !fmt) return FSL_RC_MISUSE;
  else if(!*fmt) return FSL_RC_RANGE;
  return fsl_appendfv( fsl_output_f_fsl_output, f, fmt, args );
}
    
int fsl_outputf( fsl_cx * const 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 * const cx, void const * const src, fsl_size_t n ){
  if(!n || !cx->output.out) return 0;
  else return cx->output.out( cx->output.state, src, n );
}

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


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

int fsl_output_f_FILE( void * state,
                       void const * src, fsl_size_t n ){
  if(!n) return 0;
  else return (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 ){
  if( !*n ) return FSL_RC_RANGE;
  FILE * f = (FILE*) state;
  *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);
  }
}

int fsl_stream( fsl_input_f inF, void * inState,
                fsl_output_f outF, void * outState ){
  if(!inF || !outF) return FSL_RC_MISUSE;
  else{
    int rc = 0;
    enum { BufSize = 1024 * 4 };
    unsigned char buf[BufSize];
    fsl_size_t rn = BufSize;
    for( ; !rc &&
           (rn==BufSize)
           && (0==(rc=inF(inState, buf, &rn)));
         rn = BufSize){
      if(rn) rc = outF(outState, buf, rn);
      else break;
    }
    return rc;
  }
}

int fsl_stream_compare( fsl_input_f in1, void * in1State,
                        fsl_input_f in2, void * in2State ){
  enum { BufSize = 1024 * 2 };
  unsigned char buf1[BufSize];
  unsigned char buf2[BufSize];
  fsl_size_t rn1 = BufSize;
  fsl_size_t rn2 = BufSize;
  int rc;
  while(1){
    rc = in1(in1State, buf1, &rn1);
    if(rc) return -1;
    rc = in2(in2State, buf2, &rn2);
    if(rc) return 1;
    else if(rn1!=rn2){
      rc = (rn1<rn2) ? -1 : 1;
      break;
    }
    else if(0==rn1 && 0==rn2) return 0;
    rc = memcmp( buf1, buf2, rn1 );
    if(rc) break;
    rn1 = rn2 = BufSize;
  }
  return rc;
}

#undef MARKER