//
// bufin.h ("buffered input")
//
// Written by John A deLaubenfels, https://www.adaptune.com/steg.htm .
// Permission granted to use freely in any non-fraudulent way.
//
//
// purpose:
//    provide text input w/ 1-line look-ahead.
//
// details:
//    constructor takes a file-name; opens the file.
//    get_line() returns cp to line; no worries about length.
//       (null returned at eof).
//       new call to get_line() invalidates prev cp returned.
//       performance specification: no extra copies.
//    next_line() returns cp to line without advancing.
//       (null returned at eof).
//       calling next_line does NOT invalidate the prev get_line()
//          result!  We specify that we want this feature!
//       performance specification: no extra copies.
//    destructor closes the file.
//
//
// qxl: disable copy constructor?
// how can a constructor indicate failure by returning NULL?
//
// words:
//    each call to get_line() pre-fetches the following line, so that
//    a call to next_line() merely returns a pointer already known.
//
//    To avoid extra copying, we alternate reading into two buffers
//    in more fixed location (but still allocated): cp_a and cp_b
//
//    When get_line() is called, we re-point cp_main to where cp_next
//    previously pointed (it may be cp_a or cp_b); cp_next points to
//    where cp_main previously pointed, and this value is now
//    OVERWRITTEN by the next line from the file.
//
//    Stinky: what if we need to call lengthen()?  It makes sense to
//    lengthen both cp_a and cp_b to the same values.  Then, we can
//    just arbitrarily assign cp_main to cp_a and cp_next to cp_b...
//
//    What happens at the end?  We set cp_next to NULL when we first
//    encounter EOF; cp_main will point to the previously SUCCESSFULLY
//    read last line that was in cp_next.  The next time we come to
//    get_line(), uhhh, we swap the pointers...: now cp_main points to
//    NULL and cp_next points to a stale line; we can simply say, if
//    the swap causes cp_main to be set to null, just set cp_next to
//    NULL as well...
//
//
//
//
//


#ifndef BUFIN_BE_LOADED

#define BUFIN_BE_LOADED


#include <vector>
#include <string>

#ifndef _WIN32
#include <cstdio>
#include <cstddef>
#include <cstring>
#endif  // !_WIN32



#define NADA    (-1)
#define CRR   (0x000D)
#undef  LF
#define LF    (0x000A)



class Bufin {
private:
   char *m_file_name;
   FILE *m_fp;
   char *cp_main;
   char *cp_next;
   char *cp_edge;      // 03-09-05 (jdl): where the next cp_next will go.
   char *cp_endd;      // 03-09-05 (jdl): end of the long allocated char *..
   char *cp_a;
   char *cp_b;
   long long  m_alloc_len;
   int  m_nlines;                     // 12-18-09 (jdl)
   int  m_il;                         // 12-18-09 (jdl)
   // int  m_nullReplaceChar;         // 11-09-05 (jdl); out: we will replace at construction...
   int  m_nNull;                      // 11-09-05 (jdl)
   unsigned int  m_do_fclose : 1;
   unsigned int  m_trimTrSp  : 1;     // 10-09-02
   std::vector<const char *>m_vecOfLines; // 12-18-09 (jdl)
   int  lengthen();   // private function...
   const char *getLineOld();          // 12-18-09 (jdl)
   inline void swap(char *&cpx, char *&cpy) {char *cpt=cpx; cpx=cpy; cpy=cpt;}
   int closit();
public:
   Bufin(const char *file_to_read, int trimTrSp=0, int nullReplaceChar=-1);  // nullReplaceChar 11-09-05 (jdl)
   // Bufin(FILE *fp_existing);      // xptl: out 03-08-05 (jdl)
   ~Bufin();
   int bfopen(const char *file_to_read);
   int bfopen(FILE *fp_existing);
   int bfclose();

   // int is_active() const {return (m_fp!=NULL);}
   int is_active() const;             // 03-08-05 (jdl): different between the two versions.
   int setTrSp(int trimTrSp);
   // int setNullReplace(int nullReplaceChar);  // 11-09-05 (jdl); out: we will replace at construction.
   int nNull() const {return m_nNull;}          // 11-09-05 (jdl)
   // const char *get_line(int trimTrSp=NADA);     // const 12-27-08 (jdl)
   const char *get_line();                      // param removed 12-18-09 (jdl); specified in constructor.
   // const char *next_line() {return cp_next;}    // const 12-27-08 (jdl)
   const char *next_line();                     // 12-18-09 (jdl)
   int nlines() const {return m_nlines;}        // 12-18-09 (jdl); const 08-27-11 (jdl)
   const char *operator[](int iline) const;     // 12-18-09 (jdl); const 08-26-11 (jdl)
   int fillVcStr(std::vector<std::string> &vcFillMe);

}; // class Bufin


#endif // ! BUFIN_BE_LOADED

