source: branches/port5/SL/FILE_BUFFER/FileBuffer.cxx

Last change on this file was 6287, checked in by westram, 15 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 4.6 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : FileBuffer.cxx                                     //
4//   Purpose   :                                                    //
5//                                                                  //
6//   Coded by Ralf Westram (coder@reallysoft.de) in December 2006   //
7//   Institute of Microbiology (Technical University Munich)        //
8//   http://www.arb-home.de/                                        //
9//                                                                  //
10// ================================================================ //
11
12#include "FileBuffer.h"
13#include <cstdlib>
14#include <cstring>
15#include <cstdio>
16#include <errno.h>
17
18using namespace std;
19
20void FileBuffer::fillBuffer()
21{
22    if (read==BUFFERSIZE) {
23        read = fread(buf, sizeof(buf[0]), BUFFERSIZE, fp);
24        offset = 0;
25    }
26    else {
27        offset = read;
28    }
29}
30
31static char eol[3] = "\n\r";
32static inline bool is_EOL(char c) { return c == eol[0] || c == eol[1]; }
33
34bool FileBuffer::getLine_intern(string& line)
35{
36    if (offset==read) return false;
37
38    size_t lineEnd;
39    {
40        size_t  rest   = read-offset;
41        char   *eolPos = (char*)memchr(buf+offset, eol[0], rest);
42
43        if (!eolPos) {
44            eolPos = (char*)memchr(buf+offset, eol[1], rest);
45            if (!eolPos) {
46                lineEnd = read;
47            }
48            else {
49                swap(eol[0], eol[1]);
50                lineEnd = eolPos-buf;
51            }
52        }
53        else {
54            lineEnd = eolPos-buf;
55            if (lineEnd>0 && buf[lineEnd-1] == eol[1]) {
56                swap(eol[0], eol[1]);
57                lineEnd--;
58            }
59        }
60    }
61
62    if (lineEnd<read) { // found end of line char
63        line    = string(buf+offset, lineEnd-offset);
64        char lf = buf[lineEnd];
65
66        offset = lineEnd+1;
67        if (offset == read) fillBuffer();
68
69        if (offset<read) { // otherwise EOF!
70            char nextChar = buf[offset];
71            if (is_EOL(nextChar) && nextChar != lf) offset++; // skip DOS linefeed
72            if (offset == read) fillBuffer();
73        }
74    }
75    else { // reached end of buffer
76        line = string(buf+offset, read-offset);
77        fillBuffer();
78        string rest;
79        if (getLine_intern(rest)) line = line+rest;
80    }
81
82    return true;
83}
84
85string FileBuffer::lineError(const char *msg) {
86    static char   *buffer;
87    static size_t  allocated = 0;
88
89    size_t len;
90    if (showFilename) {
91        len = strlen(msg)+filename.length()+100;
92    }
93    else {
94        len = strlen(msg)+100;
95    }
96
97    if (len>allocated) {
98        allocated = len;
99        free(buffer);
100        buffer    = (char*)malloc(allocated);
101    }
102
103    if (showFilename) {
104#if defined(DEBUG)
105        int printed =
106#endif // DEBUG
107            sprintf(buffer, "while reading %s (line #%li):\n%s", filename.c_str(), lineNumber, msg);
108        fb_assert((size_t)printed < allocated);
109    }
110    else {
111#if defined(DEBUG)
112        int printed =
113#endif // DEBUG
114            sprintf(buffer, "while reading line #%li:\n%s", lineNumber, msg);
115        fb_assert((size_t)printed < allocated);
116    }
117   
118    return buffer;
119}
120
121void FileBuffer::rewind() {
122    errno = 0;
123    std::rewind(fp);
124    fb_assert(errno == 0); // not handled yet
125   
126    read = BUFFERSIZE;
127    fillBuffer();
128
129    if (next_line) {
130        delete next_line;
131        next_line = 0;
132    }
133    lineNumber = 0;
134}
135
136// --------------------------------------------------------------------------------
137// C interface
138
139inline FileBuffer *to_FileBuffer(FILE_BUFFER fb) {
140    FileBuffer *fileBuffer = reinterpret_cast<FileBuffer*>(fb);
141    fb_assert(fileBuffer);
142    fb_assert(fileBuffer->good());
143    return fileBuffer;
144}
145
146extern "C" FILE_BUFFER create_FILE_BUFFER(const char *filename, FILE *in) {
147    FileBuffer *fb = new FileBuffer(filename, in);
148    return reinterpret_cast<FILE_BUFFER>(fb);
149}
150
151extern "C" void destroy_FILE_BUFFER(FILE_BUFFER file_buffer) {
152    delete to_FileBuffer(file_buffer);
153}
154
155extern "C" const char *FILE_BUFFER_read(FILE_BUFFER file_buffer, size_t *lengthPtr) {
156    static string  line;
157
158    if (to_FileBuffer(file_buffer)->getLine(line)) {
159        if (lengthPtr) *lengthPtr = line.length();
160        return line.c_str();
161    }
162    return 0;
163}
164
165extern "C" void FILE_BUFFER_back(FILE_BUFFER file_buffer, const char *backline) {
166    static string line;
167    line = backline;
168    to_FileBuffer(file_buffer)->backLine(line);
169}
170
171extern "C" void FILE_BUFFER_rewind(FILE_BUFFER file_buffer) {
172    to_FileBuffer(file_buffer)->rewind();
173}
Note: See TracBrowser for help on using the repository browser.