/**********************************************************************
*  Author:      Shawn Stoffer
*
*  File:        aux.c
*
*  Description: This file contains auxiliary function definitions 
*               which are needed by many of my programs.
*
*  Arguments:   None, this is not meant to be an executable program.
*
*  Systems:     SunOS, Solaris, though it should work on most system.
**********************************************************************/

/* 
 * These includes define basic stuff, like stdin, stdout, FILE*, and many more
 * goodies.
 */
#include <stdio.h>
#include <stdlib.h>

/* These are basically just prototypes for these functions. */
#include "aux.h"

/* Return the whether or not this line is backslash continued. */
/**********************************************************************
 * Name:      int get_line(char*, int, FILE*)
 *
 * Purpose:   Get a single line from the descriptor specified.  If 
 *            That line ends in a '\\' character, then cut it off and
 *            return 1.
 * 
 * Algorithm: Get characters one at a time from the input descriptor
 *            specified by the FILE* argument, upto the amount specified
 *            the second (int) argument, and stuff them all into the
 *            first (char*) argument, if the line ends with '\\' char,
 *            then cut it off.  Terminate the char* with a '\0'
 *            character.  If the line ended with a '\\' character, 
 *            return 1 otherwise, return 0;
 * 
 *********************************************************************/
int get_line(char * buf, int Ssize, FILE * fl) {
  int i;  /* Loop counter. */
  int num = 0;
  char c;

  /* loop until the size minus one, for the ending null character. */
  for (i = 0, c = getc(fl); 
       i < Ssize-1 && !feof(fl) && c != '\n'; 
       i++,c = getc(fl))
    buf[i] = c;

  /* 
   * If the last character is the '/' character (actually you have to escape
   * it, so '//', then cut it off the end by decrementing the counter and set
   * the return value.
   */
  if (buf[i-1] == '\\') { i--; num = 1; }
  
  /* end the C-string. */
  buf[i] = '\0';

  /* return if the line was continued by a backslash or not. */
  return num;
}

/**********************************************************************
 * Name: int getline(char* line, int end, FILE *fl);
 * Purpose: This function is meant to read until the 
 *          end of the line and return whether or not more can be read.
 * Algorithm: 
 *          This function is designed to read from FILE stream fl, one 
 *          character at a time, until:
 *             1. '\n' is encountered
 *             2. end is reached
 *             3. feof(fl) is reached
 *          And when feof is reached this function returns 0, otherwise
 *          it returns the number of characters read.
 **********************************************************************/

int getline(char* line, int end, FILE * fl)  {
  int i;  /* Loop counter. */
  char c;
  
  /* loop until the size minus one, for the ending null character. */
  for (i = 0, c = getc(fl); 
       i < end-1 && !feof(fl);
       i++, c = getc(fl)) {
    line[i] = c;
    /* 
     * If we encounter a newline, perform the increment of the loop and then
     * break.  This will ensure that the newline is kept on the end of the 
     * C-string, even though we broke the loop.
     */
    if (c == '\n') { i++; break; }
  }
  /* end the C-string. */
  line[i] = '\0';

  /* if we hit the end of file, return a special value. */
  if (feof(fl)) return 0;

  /* return the number of character read. */
  return i; 
}


/**********************************************************************
 * Name: int putline(char* line, FILE *fl);
 * Purpose: This function is meant to put an entire string into an
 *          output file, character by character.
 * Algorithm: 
 *          This function is designed to read from string buf, one 
 *          character at a time, until:
 *             The end of the string is reached
 *          This function returns the number of characters written.
 **********************************************************************/
int putline(char * buf, FILE * fl) {
  int i;  /* Loop counter. */
  char c;

  /* This will continue up until the NULL, but won't output the NULL. */
  for (i = 0, c = buf[i]; buf[i] != '\0';c = buf[++i])
    putc(c, fl);

  /* Number of characters output, more for accounting than anything. */
  return i;
}

/**********************************************************************
 * Name: int bgetline(char* buf, int Ssize, FILE *fl);
 * Purpose: This function is meant to read a binary line of size Ssize, 
 *          from a binary file, or until feof is reached.
 * Algorithm: 
 *         This function will read from file stream fl, one character 
 *         at a time, placing each character into the output array buf.
 *         This behavior will continue until all characters in the file
 *         are read, or until the maximum amount of characters allowed by
 *         the parameter Ssize are reached.
 * Returns:  0 is returned if feof is reached, otherwise 1 is returned.
 *           This is meant to symbolize whether or not more characters 
 *           can be read from the file.
 **********************************************************************/
int bgetline(char * buf, int Ssize, FILE *fl) {
  int i;
  char * p = buf;

  /* 
   * loop until the size is encountered, this is a straight output of Ssize
   * number of characters, no matter what they are, no NULL bound here.
   */
  for (p = buf, i = 0; i < Ssize && !feof(fl); p++, i++) {
    fread(p, sizeof(char), 1, fl);
  }

  /* If we encounter end of file, then we need to return that. */
  if (feof(fl)) i = 0;

  return i;
}


/**********************************************************************
 * Name: int bputline(char* buf, FILE *fl);
 * Purpose: This function is meant to write a character string of size 
 *          Ssize, from a binary file.
 * Algorithm: 
 *         This function will write to file stream fl, one character 
 *         at a time, reading each character from the input array buf.
 *         This behavior will continue until all characters in the array
 *         are read.  One should note that this function considers that 
 *         there are no characters after the first '\0' (null character)
 *         read.
 * Returns:  This function always returns the number of characters written.
 **********************************************************************/
int bputline(char * buf, FILE *fl) {
  int i;
  char * p;

  /* 
   * Simply output the characters specified, though we stop at 0s here, 
   * probably not a good idea... 
   */
  for (p = buf, i = 0; *p; p++, i++) {
    fwrite(p, sizeof(char), 1, fl);
  }

  return i;
}


/*****************************************************************************
 * Name:    int confirm(char* confirmString, FILE* in, FILE* out)
 *
 * Purpose: This function will read from the input specified (or stdin if 
 *          no input specified) and will output the specified specified 
 *          string, on out (or stdout if no out is specified), will output 
 *          the string specified.
 * 
 * Returns: if the user entered a yes.  (returns 1(yes) or 0(no))
 *****************************************************************************/
int confirm(char* confirmString, FILE* in, FILE* out) {
  char *s, buf[50];
  /* If they didn't specify input or output, reassign to standard. */
  if (!in) in = stdin;
  if (!out) out = stdout;

  /* Output the string given to us, no checking. */
  fprintf(out, confirmString);
  /* Get the answer */
  fgets(buf, 49, in); 
  /* Clear leading whitespace. */
  for (s = buf; isspace((int)s); s++);
  /* 
   * if the first non-whitespace character in the string is 'y', then we 
   * believe that the answer is yes.  We avoid the annoyance of trying the 
   * various forms of y by using tolower to make sure that it is converted
   * inefficient in the case of 'y', but we will take the small math 
   * calculation of converting the char against having to check the various 
   * forms of y.
   */
  
  if (tolower(*s) == 'y') return 1;
  return 0;
}

#ifndef isspace
/* 
 * Basically, isspace is a macro defined in ctype.h, so checking if it is 
 * defined is correct, normally though, you cannot do this to a function.
 */
/*****************************************************************************
 * Name:    int isspace(unsigned char a)
 *
 * Purpose: This function checks the character to see whether it is a
 *          printable character, or whitespace, where whitespace and 
 *          unprintable characters are defined as being outside the
 *          ranges of 32-126 and greater than 161.  There is the implied
 *          limit of 0 and 255 due to the fact that a char is defined as
 *          one byte.  
 *              
 * Returns: This function returns a 1 if the character is unprintable or
 *          whitespace, and returns a 0 if it is printable, and not whitespace.
 ****************************************************************************/
int isspace(unsigned char a) {
  if (a > 32 || a < 126 || a > 161)
    return 0;
  return 1;
}
#endif

/*****************************************************************************
 * Name:    char * skip_whitespace(char * buf)
 * 
 * Purpose: This function will skip all leading whitespace in a string, and
 *          return a pointer to the first non-whitespace character in the 
 *          string.
 *
 * Returns: The first non-whitespace character in the string, or the '\0' char
 *          if the string is entirely whitespace.
 ****************************************************************************/
char * skip_whitespace(char * buf) {
  int i = 0;
  /* find the first non-whitespace character. */
  for (; buf[i] && isspace(buf[i]); i++);
  return buf+i;
}

