replaced old numbered script file system with new "modules" system; "Include" is...
[k8-i-v-a-n.git] / src / felib / fesave.cpp
blob07e0efef050312e91a646b09de83c831dbedf133
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
22 #include <cctype>
24 #include "fesave.h"
25 #include "femath.h"
28 #ifdef USE_ZLIB
29 # define Xgetc gzgetc
30 # define Xfeof gzeof
31 # define Xungc gzungetc
32 # define Xseek gzseek
33 # define Xtell gztell
34 # define Xclre gzclearerr
35 #else
36 # define Xgetc fgetc
37 # define Xfeof feof
38 # define Xungc ungetc
39 # define Xseek fseek
40 # define Xtell ftell
41 # define Xclre clearerr
42 #endif
45 // ////////////////////////////////////////////////////////////////////////// //
46 outputfile::outputfile (cfestring &FileName, truth maxcomp, truth AbortOnErr) :
47 #ifdef USE_ZLIB
48 Buffer(gzopen(FileName.CStr(), (maxcomp?"wb9":"wb1"))),
49 #else
50 Buffer(fopen(FileName.CStr(), "wb")),
51 #endif
52 FileName(FileName)
54 if (AbortOnErr && !IsOpen()) ABORT("Can't open %s for output!", FileName.CStr());
58 outputfile::~outputfile () {
59 Close();
63 void outputfile::Close () {
64 if (Buffer) {
65 #ifdef USE_ZLIB
66 gzclose(Buffer);
67 #else
68 fclose(Buffer);
69 #endif
70 Buffer = 0;
75 void outputfile::Flush () {
76 #ifdef USE_ZLIB
77 gzflush(Buffer, Z_FINISH);
78 #else
79 fflush(Buffer);
80 #endif
84 void outputfile::Put (char What) {
85 #ifdef USE_ZLIB
86 gzputc(Buffer, What);
87 #else
88 fputc(What, Buffer);
89 #endif
93 void outputfile::Write (cchar *Offset, sLong Size) {
94 #ifdef USE_ZLIB
95 gzwrite(Buffer, Offset, Size);
96 #else
97 fwrite(Offset, 1, Size, Buffer);
98 #endif
102 sLong outputfile::TellPos () {
103 return Xtell(Buffer);
107 // ////////////////////////////////////////////////////////////////////////// //
108 truth inputfile::fileExists (const festring &fname) {
109 struct stat st;
110 if (stat(fname.CStr(), &st)) return false;
111 if (!S_ISREG(st.st_mode)) return false;
112 return access(fname.CStr(), R_OK) == 0;
116 festring inputfile::GetMyDir () {
117 #ifdef IVAN_DATA_DIR
118 return IVAN_DATA_DIR;
119 #else
120 char myDir[8192];
121 char buf[128];
122 pid_t mypid = getpid();
123 memset(myDir, 0, sizeof(myDir));
124 sprintf(buf, "/proc/%u/exe", (unsigned int)mypid);
125 if (readlink(buf, myDir, sizeof(myDir)-1) < 0) {
126 strcpy(myDir, ".");
127 } else {
128 char *p = (char *)strrchr(myDir, '/');
129 if (!p) strcpy(myDir, "."); else *p = '\0';
131 if (myDir[strlen(myDir)-1] == '/') myDir[strlen(myDir)-1] = '\0';
132 return myDir;
133 #endif
137 festring inputfile::buildIncludeName (cfestring &basename, cfestring incname) {
138 festring xname = incname;
139 while (xname.GetSize() > 0 && xname[0] == '/') xname.Erase(0, 1);
140 if (xname.GetSize() == 0) ABORT("Cannot include file with empty name");
141 festring res = basename;
142 // remove name
143 while (res.GetSize() && res[res.GetSize()-1] != '/') res.Erase(res.GetSize()-1, 1);
144 res += xname;
145 //fprintf(stderr, "buildIncludeName(\"%s\", \"%s\") -> \"%s\"\n", basename.CStr(), incname.CStr(), res.CStr());
146 return res;
150 ////////////////////////////////////////////////////////////////////////////////
151 inputfile::inputfile () :
152 Buffer(0),
153 FileName("")
154 #ifdef USE_ZLIB
155 , mFileSize(-1)
156 #endif
161 inputfile::inputfile (cfestring &aFileName, truth AbortOnErr) :
162 #ifdef USE_ZLIB
163 Buffer(gzopen(aFileName.CStr(), "rb")),
164 #else
165 Buffer(fopen(aFileName.CStr(), "rb")),
166 #endif
167 FileName(aFileName)
168 #ifdef USE_ZLIB
169 , mFileSize(-1)
170 #endif
172 if (AbortOnErr && !IsOpen()) ABORT("File %s not found!", FileName.CStr());
176 inputfile::~inputfile () {
177 Close();
181 bool inputfile::Open (cfestring &aFileName, truth AbortOnErr) {
182 Close();
183 #ifdef USE_ZLIB
184 mFileSize = -1;
185 Buffer = gzopen(aFileName.CStr(), "rb");
186 #else
187 Buffer = fopen(aFileName.CStr(), "rb");
188 #endif
189 FileName = aFileName;
190 mRetFName = aFileName;
191 auto mydir = GetMyDir();
192 if (mydir.GetSize() > 0 && mRetFName.startsWith(mydir)) {
193 mRetFName.Erase(0, mydir.GetSize()+(mydir[mydir.GetSize()-1] != '/' ? 1 : 0));
195 if (AbortOnErr && !IsOpen()) ABORT("File %s not found!", aFileName.CStr());
196 return IsOpen();
200 void inputfile::Close () {
201 if (Buffer) {
202 #ifdef USE_ZLIB
203 gzclose(Buffer);
204 #else
205 fclose(Buffer);
206 #endif
207 Buffer = 0;
212 int inputfile::Get () {
213 if (Buffer) {
214 int ch = Xgetc(Buffer);
215 return (ch < 0 ? EOF : ch);
216 } else {
217 return EOF;
222 truth inputfile::Eof () {
223 return (Buffer ? Xfeof(Buffer) : true);
227 void inputfile::Read (char *Offset, sLong Size) {
228 if (!Buffer) ABORT("Trying to read from unopened file '%s'!", FileName.CStr());
229 #ifdef USE_ZLIB
230 if (gzread(Buffer, Offset, Size) != Size) ABORT("File '%s' read error!", FileName.CStr());
231 #else
232 if (fread(Offset, Size, 1, Buffer) != 1) ABORT("File '%s' read error!", FileName.CStr());
233 #endif
237 void inputfile::SeekPosBegin (sLong Offset) {
238 if (Xseek(Buffer, Offset, SEEK_SET) < 0) ABORT("File '%s': seek error!", FileName.CStr());
242 void inputfile::SeekPosCurrent (sLong Offset) {
243 if (Xseek(Buffer, Offset, SEEK_CUR) < 0) ABORT("File '%s': seek error!", FileName.CStr());
247 #ifdef USE_ZLIB
248 void inputfile::SeekPosEnd (sLong Offset) {
249 //HACKHACK: emulate this
250 if (mFileSize < 0) {
251 //SLOOOW, but we have to do that
252 int opos;
253 char *buffer, buf[512];
254 int bufsize;
255 for (bufsize = 256*1024; bufsize > (int)sizeof(buf); bufsize /= 2) {
256 if ((buffer = (char *)malloc(bufsize)) != NULL) break;
258 if (buffer == NULL) { buffer = buf; bufsize = sizeof(buf); }
259 //fprintf(stderr, "determining file size...\n");
260 mFileSize = opos = gztell(Buffer);
261 for (;;) {
262 int len = gzread(Buffer, buffer, bufsize);
263 if (len < 0) { mFileSize = -1; break; } // error
264 mFileSize += len;
265 if (len < bufsize) break; // eof reached
267 if (buffer != buf) free(buffer);
268 //fprintf(stderr, "file size: %d\n", ctx->filesize);
270 if (mFileSize < 0) ABORT("File '%s': seek error!", FileName.CStr());
271 if (gzseek(Buffer, mFileSize+Offset, SEEK_SET) < 0) ABORT("File '%s': seek error!", FileName.CStr());
274 #else
276 void inputfile::SeekPosEnd (sLong Offset) {
277 if (fseek(Buffer, Offset, SEEK_END) < 0) ABORT("File '%s': seek error!", FileName.CStr());
279 #endif
282 sLong inputfile::TellPos () {
283 return Xtell(Buffer);
287 void inputfile::ClearFlags () {
288 Xclre(Buffer);
292 // ////////////////////////////////////////////////////////////////////////// //
293 outputfile &operator << (outputfile &SaveFile, cfestring &String) {
294 uShort Length = String.GetSize();
295 SaveFile << Length;
296 if (Length) SaveFile.Write(String.CStr(), Length);
297 return SaveFile;
301 inputfile &operator >> (inputfile &SaveFile, festring &String) {
302 char *RealBuffer, StackBuffer[1024];
303 uShort Length;
304 SaveFile >> Length;
305 RealBuffer = (Length < 1024 ? StackBuffer : new char[Length+1]);
306 String.Empty();
307 if (Length) {
308 SaveFile.Read(RealBuffer, Length);
309 RealBuffer[Length] = 0;
310 String << RealBuffer;
312 if (RealBuffer != StackBuffer) delete [] RealBuffer;
313 return SaveFile;
317 outputfile &operator << (outputfile &SaveFile, cchar *String) {
318 uShort Length = (String ? strlen(String) : 0);
319 SaveFile << Length;
320 if (Length) SaveFile.Write(String, Length);
321 return SaveFile;
325 inputfile &operator >> (inputfile &SaveFile, char *&String) {
326 uShort Length;
327 SaveFile >> Length;
328 if (Length) {
329 String = new char[Length+1];
330 SaveFile.Read(String, Length);
331 String[Length] = 0;
332 } else {
333 String = 0;
335 return SaveFile;