source: trunk/tools/common/kFile.cpp

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 26.6 KB
RevLine 
[8003]1/* $Id: kFile.cpp,v 1.10 2002-02-24 02:47:24 bird Exp $
[3592]2 *
3 * kFile - Simple (for the time being) file class.
4 *
[4358]5 * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@mynd.no)
[3592]6 *
7 * Project Odin Software License can be found in LICENSE.TXT
8 *
9 */
10
11/*******************************************************************************
12* Defined Constants And Macros *
13*******************************************************************************/
14#define INCL_DOSFILEMGR
15#define INCL_DOSERRORS
16
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
[21916]21#if defined (__EMX__) && !defined (USE_OS2_TOOLKIT_HEADERS)
22#define __OS2DEF__
23#endif
[3592]24#include <os2.h>
[3629]25
26#include <malloc.h>
[3592]27#include <string.h>
[3629]28#include <stdarg.h>
29#include <stdio.h>
[4402]30#include <stdlib.h>
[3592]31
[8003]32#include "kTypes.h"
33#include "kError.h"
[4358]34#include "kFile.h"
[3592]35
[4358]36/*******************************************************************************
37* Global Variables *
38*******************************************************************************/
39kFile kFile::StdIn((HFILE)0, TRUE);
40kFile kFile::StdOut((HFILE)1, FALSE);
41kFile kFile::StdErr((HFILE)2, FALSE);
[3592]42
[4358]43
[3592]44/**
45 * Updates the internal filestatus struct.
46 * @returns Success indicator.
47 * On success filestatus is refreshed.
48 * @remark
49 */
[21916]50KBOOL kFile::refreshFileStatus() throw (kError)
[3592]51{
[4358]52 if (fStdDev)
53 return fStatusClean = TRUE;
54
[3592]55 if (!fStatusClean)
56 {
[8003]57 rc = DosQueryFileInfo(OSData.os2.hFile, FIL_QUERYEASIZE, &OSData.os2.filestatus, sizeof(OSData.os2.filestatus));
[3592]58 fStatusClean = (rc == NO_ERROR);
59 if (!fStatusClean && fThrowErrors)
[8003]60 throw (kError(rc));
[3592]61 }
62 else
63 rc = NO_ERROR;
64
65 return fStatusClean;
66}
67
68
69/**
70 * Changes the real file position to match the virtual file position.
71 * @returns Success indicator.
72 */
[21916]73KBOOL kFile::position() throw (kError)
[3592]74{
75 /*
76 * If virtual file offset is different from the real,
77 * issue a set file pointer call.
78 */
79 if (offVirtual != offReal)
80 {
81 ULONG off;
[8003]82 rc = DosSetFilePtr(OSData.os2.hFile, offVirtual, FILE_BEGIN, &off);
[3592]83 if (rc != NO_ERROR || off != offVirtual)
84 {
85 if (fThrowErrors)
[8003]86 throw (kError(rc));
[3592]87 return FALSE;
88 }
89 offReal = offVirtual;
90 }
[4426]91 else
92 rc = NO_ERROR;
[3592]93
94 return TRUE;
95}
96
[4426]97
[4358]98/**
[4426]99 * Reads data from the file into the buffer from the given file offset.
100 * @returns Success indicator.
101 * @param offFile File offset to read from.
102 * (If readonly and beyond end of file the offset used
103 * may be addjusted.)
104 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
105 */
[8003]106KBOOL kFile::bufferRead(unsigned long offFile) throw(kError)
[4426]107{
108 ULONG cbRead;
109
110 /* refresh file status (cbFile) */
111 if (!refreshFileStatus())
112 return FALSE;
113
114 /* check that the request is valid */
[8003]115 if (offFile > OSData.os2.filestatus.cbFile)
[4426]116 return FALSE;
117
118 /* commit dirty buffer */
119 if (fBufferDirty)
120 {
121 if (!bufferCommit())
122 return TRUE;
123
124 /* refresh file status (cbFile) */
125 if (!refreshFileStatus())
126 return FALSE;
127 }
128
129 /* If readonly file optimize end of file */
[8003]130 if (fReadOnly && cbBuffer + offFile > OSData.os2.filestatus.cbFile)
131 offFile = OSData.os2.filestatus.cbFile > cbBuffer ? OSData.os2.filestatus.cbFile - cbBuffer : 0UL;
[4426]132
133 /* need to change file ptr? */
134 if (offFile != offReal)
135 {
136 ULONG ul;
[8003]137 rc = DosSetFilePtr(OSData.os2.hFile, offFile, FILE_BEGIN, &ul);
[4426]138 if (rc != NO_ERROR)
139 {
140 if (fThrowErrors)
[8003]141 throw (kError(rc));
[4426]142 return FALSE;
143 }
144 offReal = offFile;
145 }
146
147 /* read from the file */
[8003]148 cbRead = KMIN(OSData.os2.filestatus.cbFile - offFile, cbBuffer);
149 rc = DosRead(OSData.os2.hFile, pachBuffer, cbRead, &cbRead);
[4426]150 if (rc == NO_ERROR)
151 {
152 cbBufferValid = cbRead;
153 offBuffer = offFile;
154 offReal = offFile + cbRead;
155 fBufferDirty = FALSE;
156 }
157 else
158 {
159 cbBufferValid = 0;
160 offBuffer = ~0UL;
161 fBufferDirty = FALSE;
162 if (fThrowErrors)
[8003]163 throw (kError(rc));
[4426]164 return FALSE;
165 }
166
167 return TRUE;
168}
169
170
171/**
172 * Commits the data in the buffer.
173 * @returns Success indicator.
174 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
175 */
[8003]176KBOOL kFile::bufferCommit(void) throw(kError)
[4426]177{
178 ULONG cbWrote;
179 ULONG ul;
180
181 /* don't commit clean buffers! */
182 if (!fBufferDirty)
183 return TRUE;
184
185 /* need to change file ptr? */
186 if (offBuffer != offReal)
187 {
[8003]188 rc = DosSetFilePtr(OSData.os2.hFile, offBuffer, FILE_BEGIN, &ul);
[4426]189 if (rc != NO_ERROR)
190 {
191 if (fThrowErrors)
[8003]192 throw (kError(rc));
[4426]193 return FALSE;
194 }
195 offReal = offBuffer;
196 }
197
198 /* write to the file */
[8003]199 rc = DosWrite(OSData.os2.hFile, pachBuffer, cbBufferValid, &cbWrote);
[4426]200 fStatusClean = FALSE;
201 if (rc == NO_ERROR)
202 {
203 fBufferDirty = FALSE;
204 offReal += cbWrote;
205 }
206 else
207 {
[8003]208 DosSetFilePtr(OSData.os2.hFile, offReal, FILE_BEGIN, &ul);
[4426]209 if (fThrowErrors)
[8003]210 throw (kError(rc));
[4426]211 return FALSE;
212 }
213
214 return TRUE;
215}
216
217
218/**
[4358]219 * Creates a kFile object for a file that is opened allready.
220 * Intended use for the three standard handles only.
221 *
222 * @returns <object> with state updated.
223 * @param pszFilename Filename.
224 * @param fReadOnly TRUE: Open the file readonly.
225 * FALSE: Open the file readwrite appending
226 * existing files.
227 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
228 */
[8003]229kFile::kFile(HFILE hFile, KBOOL fReadOnly)
[4358]230: fReadOnly(fReadOnly),
231 fStatusClean(FALSE),
232 fThrowErrors(FALSE),
233 offVirtual(0),
234 offReal(0),
235 pszFilename(NULL),
[4426]236 fStdDev(TRUE),
237 pachBuffer(NULL),
238 cbBufferValid(0UL),
239 offBuffer(~0UL),
240 fBufferDirty(FALSE)
[4358]241{
[8003]242 OSData.os2.hFile = hFile;
[4358]243 if (!refreshFileStatus())
[8003]244 throw (kError(rc));
[4358]245 this->pszFilename = strdup("");
246}
[3592]247
[4358]248
[3592]249/**
250 * Opens a file for binary reading or readwrite.
251 * @returns <object> with state updated.
252 * Throws OS/2 error on error.
253 * @param pszFilename Filename.
254 * @param fReadOnly TRUE: Open the file readonly. (default)
255 * FALSE: Open the file readwrite appending
256 * existing files.
[4358]257 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
[3592]258 */
[21916]259kFile::kFile(const char *pszFilename, KBOOL fReadOnly/*=TRUE*/) throw (kError)
[3592]260: fReadOnly(fReadOnly),
261 fStatusClean(FALSE),
262 fThrowErrors(FALSE),
263 offVirtual(0),
[4129]264 offReal(0),
[4358]265 pszFilename(NULL),
[4426]266 fStdDev(FALSE),
267 pachBuffer(NULL),
268 cbBufferValid(0UL),
269 offBuffer(~0UL),
270 fBufferDirty(FALSE)
[3592]271{
272 ULONG fulOpenFlags;
273 ULONG fulOpenMode;
274 ULONG ulAction;
275
276 /*
277 * Determin open flags according to fReadOnly.
278 */
279 if (fReadOnly)
280 {
281 fulOpenFlags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
282 fulOpenMode = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY;
283 }
284 else
285 {
286 fulOpenFlags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
287 fulOpenMode = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READWRITE;
288 }
289
[8003]290 rc = DosOpen((PCSZ)pszFilename, &OSData.os2.hFile, &ulAction, 0, FILE_NORMAL,
[4129]291 fulOpenFlags, fulOpenMode, NULL);
[3592]292 if (rc != NO_ERROR)
[8003]293 throw (kError(rc));
[3592]294
[3613]295 if (!refreshFileStatus())
[8003]296 throw (kError(rc));
[4129]297
298 char szFullName[CCHMAXPATH];
299 if (DosQueryPathInfo(pszFilename, FIL_QUERYFULLNAME, szFullName, sizeof(szFullName)))
300 strcpy(szFullName, pszFilename);
301 this->pszFilename = strdup(szFullName);
302 if (this->pszFilename == NULL)
303 throw (ERROR_NOT_ENOUGH_MEMORY);
[4426]304
305 /* Buffering */
[8003]306 cbBuffer = (fReadOnly && OSData.os2.filestatus.cbFile < 32768) ? OSData.os2.filestatus.cbFile : 8192;
[4426]307 pachBuffer = new char[cbBuffer];
308 if (pachBuffer == NULL)
309 throw (ERROR_NOT_ENOUGH_MEMORY);
[8003]310 if (fReadOnly && OSData.os2.filestatus.cbFile < 32768)
[4426]311 {
312 if (!bufferRead(0))
[8003]313 throw (kError(rc));
[4426]314 }
[3592]315}
316
317
318/**
319 * Closes the file.
320 */
321kFile::~kFile()
322{
[4426]323 if (fBufferDirty)
324 bufferCommit();
325 if (pachBuffer)
326 delete pachBuffer;
[8003]327 DosClose(OSData.os2.hFile);
[3592]328}
329
330
331/**
332 * Reads <cbBuffer> bytes from the current file posistion into the buffer.
[8003]333 * @returns 0 on success. kError error number.
[3592]334 * @param pvBuffer Output buffer.
335 * @param cbBuffer Amount of bytes to read.
336 */
[21916]337int kFile::read(void *pvBuffer, long cbBuffer) throw (kError)
[3592]338{
[4426]339 ULONG cbRead;
340
341 /* Validate parameters */
342 if (cbBuffer == 0)
[8003]343 return NO_ERROR;
[4426]344 if (cbBuffer < 0)
[3592]345 {
[4426]346 rc = ERROR_INVALID_PARAMETER;
347 if (fThrowErrors)
[8003]348 throw (kError(rc));
349 return rc;
[4426]350 }
351
352 /* refresh file status (cbFile) */
353 if (!refreshFileStatus())
[8003]354 return rc;
[4426]355
356 /* check if valid request */
[8003]357 if ( offVirtual > OSData.os2.filestatus.cbFile
358 || offVirtual + cbBuffer > OSData.os2.filestatus.cbFile
[4426]359 )
360 { /* invalid request */
361 rc = ERROR_NO_DATA;
362 }
[8003]363 else if (this->cbBufferValid == OSData.os2.filestatus.cbFile && offBuffer == 0)
[4426]364 {
365 /*
366 * The entire file is buffered
367 * Complete the request.
368 */
369 memcpy(pvBuffer, &pachBuffer[offVirtual], (size_t)cbBuffer);
370 offVirtual += cbBuffer;
371 rc = NO_ERROR;
372 }
373 else if (pachBuffer && cbBuffer <= this->cbBuffer)
374 { /*
375 * Buffered read. (request not bigger than the buffer!)
376 * Update status (filesize).
377 * Check if the request is with the bounds of the file.
378 * Not in buffer?
379 * Then read more data into buffer.
380 * In buffer?
381 * Then complete the request.
382 *
383 */
384 while (cbBuffer > 0)
385 {
386 /* Part or all in buffer? */
387 if (pachBuffer != NULL &&
388 offVirtual >= offBuffer &&
389 offVirtual < offBuffer + cbBufferValid
390 )
391 { /* copy data from buffer */
392 cbRead = cbBufferValid - offVirtual + offBuffer;
[8003]393 cbRead = KMIN(cbRead, cbBuffer);
[4426]394 memcpy(pvBuffer, &pachBuffer[offVirtual - offBuffer], (size_t)cbRead);
395 offVirtual += cbRead;
396 pvBuffer = (char*)pvBuffer + cbRead;
397 cbBuffer -= cbRead;
398 }
399 else
400 {
401 /* read into buffer */
402 if (!bufferRead(offVirtual))
[8003]403 return rc;
[4426]404 }
405 }
406
407 rc = NO_ERROR;
408 }
409 else if (position())
410 { /*
411 * unbuffered read.
412 */
[8003]413 rc = DosRead(OSData.os2.hFile, pvBuffer, cbBuffer, &cbRead);
[3592]414 if (rc == NO_ERROR)
415 offVirtual = offReal += cbRead;
416 }
417
[4426]418 /* check for error and return accordingly */
[8003]419 if (rc && fThrowErrors)
420 throw (kError(rc));
421 return rc;
[3592]422}
423
424
425/**
426 * Reads <cbBuffer> bytes at file offset <off>.
[8003]427 * @returns 0 on success. kError error number.
[3592]428 * @param pvBuffer Output buffer.
429 * @param cbBuffer Amount of bytes to read.
430 * @param off Absolute file offset.
431 */
[21916]432int kFile::readAt(void *pvBuffer, long cbBuffer, long off) throw (kError)
[3592]433{
[8003]434 if (set(off))
435 return rc;
436 read(pvBuffer, cbBuffer);
437 return rc;
[3592]438}
439
440
441/**
[4129]442 * Reads the entire file into a single memory block.
443 * (The memory block has a '\0' at the end just in case you
444 * are using it as a long string.)
[8003]445 * Must call the static kFile::mapFree function to free the memory block.
[4129]446 * @returns Pointer to file in memory.
447 */
[8003]448void * kFile::mapFile() throw(kError)
[4129]449{
450 void *pv;
451
452 /* allocate memory for the file */
453 pv = calloc((size_t)this->getSize() + 1, 1);
454 if (pv == NULL)
455 {
456 if (fThrowErrors)
[8003]457 throw (kError(kError::NOT_ENOUGH_MEMORY));
[4129]458 return NULL;
459 }
460
461 /* go the start of the file and read it. */
[8003]462 if (!start() && !read(pv, this->getSize()))
[4129]463 return pv; // successfull exit!
464
465 /* we failed, cleanup and return NULL */
466 free(pv);
467 return NULL;
468}
469
470
471/**
[4402]472 * Reads a single line from the file into the given buffer.
473 * Newline is stripped!
[8003]474 * @returns 0 on success. kError error number.
[4402]475 * @param pszBuffer Pointer to string buffer.
476 * Will hold a zero-string upon successful return.
477 * @param cchBuffer Buffer size.
478 * @sketch
479 * @status partially implemented.
480 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
481 */
[21916]482int kFile::readln(char *pszBuffer, long cchBuffer)
[4402]483{
[4426]484 long cbRead;
[4402]485
[4426]486 /* refresh file status (cbFile) */
487 if (!refreshFileStatus())
[8003]488 return rc;
[4426]489
[4402]490 /*
[4426]491 * Buffered read.
492 * Calc max read size.
493 * Loop buffer by buffer looking for a newline.
[4402]494 */
[8003]495 cbRead = KMIN(KMAX((long)OSData.os2.filestatus.cbFile - (long)offVirtual, 0), cchBuffer-1);
[4426]496 if (cbRead == 0)
[8003]497 return rc = ERROR_HANDLE_EOF;
[4402]498
[4426]499 while (cbRead > 0)
500 {
501 char *pszNewLine;
502 char *pszReturn;
503 char *pszEnd;
504 unsigned long cch;
[4402]505
[4426]506 /* read more buffer ? */
507 if (offVirtual >= offBuffer + cbBufferValid || offVirtual < offBuffer)
508 if (!bufferRead(offVirtual))
[8003]509 return rc;
[4426]510
511 /* Scan buffer for new line */
512 pszNewLine = (char*)memchr(&pachBuffer[offVirtual - offBuffer], '\r', (size_t)(cbBufferValid - offVirtual + offBuffer));
513 pszReturn = (char*)memchr(&pachBuffer[offVirtual - offBuffer], '\n', (size_t)(cbBufferValid - offVirtual + offBuffer));
514 if (pszNewLine != NULL || pszReturn != NULL)
[4402]515 {
[4426]516 pszEnd = pszReturn != NULL && (pszNewLine == NULL || pszReturn < pszNewLine) ?
517 pszReturn : pszNewLine;
518 cch = pszEnd - &pachBuffer[offVirtual - offBuffer];
[4402]519 }
[4426]520 else
521 {
522 pszEnd = NULL;
523 cch = cbBufferValid - offVirtual + offBuffer;
524 }
[4402]525
[4426]526 /* copy into result buffer */
527 memcpy(pszBuffer, &pachBuffer[offVirtual - offBuffer], (size_t)cch);
528 cbRead -= cch;
529 offVirtual += cch;
530 pszBuffer += cch;
531 *pszBuffer = '\0';
[4402]532
[4426]533 /* check for completion */
534 if (pszEnd != NULL)
535 { /* skip newline */
536 if (pszEnd[0] == '\r')
537 {
538 if (cch + 1 > cbBufferValid)
539 {
540 if (bufferRead(offBuffer + cbBufferValid))
541 pszEnd = pachBuffer;
542 }
543 else
544 pszEnd++;
545 offVirtual += pszEnd != NULL && *pszEnd == '\n' ? 2 : 1;
546 }
547 else
548 offVirtual++;
[8003]549 return NO_ERROR;
[4426]550 }
[4402]551 }
552
[8003]553 return NO_ERROR;
[4402]554}
555
556
557/**
[3592]558 * Writes <cbBuffer> bytes to the file at the current file position.
[8003]559 * @returns 0 on success. kError error number.
[3592]560 * @param pvBuffer Output buffer.
561 * @param cbBuffer Amount of bytes to write.
562 */
[21916]563int kFile::write(const void *pv, long cb) throw (kError)
[3592]564{
565 if (fReadOnly)
566 rc = ERROR_ACCESS_DENIED;
567 else
568 {
[4426]569 /* buffered writes? */
570 if (pachBuffer != NULL)
[7093]571 {
572 ULONG cbWrite;
573 ULONG cbAddPost = 0;
574
575 /*
576 * New buffer algorithm.
577 * Init buffer if it's invalid.
578 * Loop until no more to write
579 * If All fits into current buffer Then
580 * Insert it. COMPLETED.
581 * If Start fits into the current buffer Then
582 * Insert it.
583 * Else If End fits into the current buffer Then
584 * Insert it.
585 * Else //nothing fit's into the buffer
586 * Commit the buffer.
587 * Initiate the buffer to the current offset.
588 * Insert as much as possible.
589 * Endif
590 * EndLoop
[4426]591 */
592 if (offBuffer == ~0UL)
593 { /* Empty buffer at current virtual offset */
[7093]594 fBufferDirty = 0;
595 cbBufferValid = 0;
596 offBuffer = offVirtual;
[4426]597 }
598
[7093]599 while (cb > 0)
600 {
601 if ( offBuffer <= offVirtual
602 && offBuffer + cbBufferValid >= offVirtual
603 && offBuffer + cbBuffer >= offVirtual + cb
604 )
605 { /* everything fits into the buffer */
606 memcpy(&pachBuffer[offVirtual - offBuffer], pv, cb);
607 if (cbBufferValid < cb + offVirtual - offBuffer)
608 cbBufferValid = cb + offVirtual - offBuffer;
609 offVirtual += cb + cbAddPost;
610 fBufferDirty = TRUE;
[8003]611 return NO_ERROR;
[7093]612 }
613
614 if ( offBuffer <= offVirtual
615 && offBuffer + cbBufferValid >= offVirtual
616 && offBuffer + cbBuffer < offVirtual
617 )
618 { /* start fits into the buffer */
619 cbWrite = cbBuffer - (offVirtual - offBuffer);
620 memcpy(&pachBuffer[offVirtual - offBuffer], pv, cbWrite);
621 cbBufferValid = cbBuffer;
622 offVirtual += cbWrite;
623 cb -= cbWrite;
624 pv = (char*)pv + cbWrite;
625 }
626 else if ( offBuffer > offVirtual
627 && offBuffer <= offVirtual + cb
628 && offBuffer + cbBuffer >= offVirtual + cb
629 )
630 { /* end fits into the buffer */
631 cbWrite = offVirtual + cb - offBuffer;
632 memcpy(pachBuffer, pv, cbWrite);
633 if (cbBufferValid < cbWrite)
634 cbBufferValid = cbWrite;
635 cbAddPost += cbWrite;
636 cb -= cbWrite;
637 }
638 else
639 { /* don't fit anywhere... */
640 if (!bufferCommit())
[8003]641 return rc;
[7093]642 offBuffer = offVirtual;
643 cbWrite = cbBufferValid = cb > cbBuffer ? cbBuffer : cb;
644 memcpy(pachBuffer, pv, cbWrite);
645 cb -= cbWrite;
646 pv = (char*)pv + cbWrite;
647 offVirtual += cbWrite;
648 }
[4426]649 fBufferDirty = TRUE;
650
651
[7093]652 } /* loop */
653 offVirtual += cbAddPost;
654
[8003]655 return NO_ERROR;
[4426]656 }
657 else if (position())
658 { /* non-buffered write! */
[3592]659 ULONG cbWrote;
660
[8003]661 rc = DosWrite(OSData.os2.hFile, (PVOID)pv, cb, &cbWrote);
[3592]662 if (rc == NO_ERROR)
663 {
664 offVirtual = offReal += cbWrote;
[8003]665 return NO_ERROR;
[3592]666 }
667 }
668 }
669
670 if (fThrowErrors)
[8003]671 throw (kError(rc));
672 return rc;
[3592]673}
674
675
676/**
677 * Write <cbBuffer> bytes at file offset <off> from <pvBuffer>.
[8003]678 * @returns 0 on success. kError error number.
[3592]679 * @param pvBuffer Output buffer.
680 * @param cbBuffer Amount of bytes to write.
681 * @param off Absolute file offset.
682 */
[21916]683int kFile::writeAt(const void *pvBuffer, long cbBuffer, long off) throw (kError)
[3592]684{
[8003]685 if (set(off))
686 return rc;
687 return write(pvBuffer, cbBuffer);
[3592]688}
689
690
691/**
[3629]692 * printf - formatted write.
693 *
694 * Lonely '\n's are prefixed with a '\r' to make output conform with
695 * PC line ending.
696 *
697 * @returns Number of bytes written.
698 * @param pszFormat Format string.
699 * @param ... Ellipcis.
700 * @remark Currently limited to 64KB of result data.
701 */
[8003]702int kFile::printf(const char *pszFormat, ...) throw(kError)
[3629]703{
704 long offStart = getPos();
705 va_list arg;
706
707 /* !QUICK AND DIRTY! */
708 char * psz, * pszEnd;
[4426]709 static char szBuffer[1024*64]; //64KB should normally be enough for anyone...
[3629]710
711 va_start(arg, pszFormat);
[4426]712 pszEnd = vsprintf(szBuffer, pszFormat, arg) + szBuffer;
[3629]713 va_end(arg);
714
715 psz = pszEnd;
[4426]716 while (psz > szBuffer)
[3629]717 {
718 if (*psz-- == '\n' && *psz != '\r')
719 {
720 memmove(psz+2, psz+1, pszEnd - psz + 1);
721 psz[1] = '\r';
722 pszEnd++;
723 }
724 }
725
[4426]726 write(szBuffer, pszEnd - szBuffer);
[3629]727
[4129]728 return (int)(getPos() - offStart);
[3629]729}
730
731
[4129]732/**
733 * Sets the filesize.
[8003]734 * @returns 0 on success. kError error number.
[4129]735 * @param cbFile New filesize.
736 * Defaults to 0xffffffff, which results in
737 * cutting the file at the current position.
738 */
[8003]739int kFile::setSize(unsigned long cbFile/*= ~0UL*/)
[4129]740{
741 if (cbFile == ~0UL)
742 cbFile = offVirtual;
[8003]743 rc = DosSetFileSize(OSData.os2.hFile, cbFile);
[4129]744 if (rc != NO_ERROR && fThrowErrors)
[8003]745 throw (kError(rc));
[3629]746
[8003]747 return rc;
[4129]748}
[3629]749
[4129]750
[3629]751/**
[4402]752 * Appends the AppendFile to this file.
753 * @returns Reference to this file.
754 * @param AppendFile Reference to the file we're to append.
755 */
756kFile & kFile::operator+=(kFile &AppendFile)
757{
758 long cb;
759 char * pachBuffer = new char[1024*256];
760 long pos = AppendFile.getPos();
[8003]761 KBOOL fAppend = AppendFile.fThrowErrors;
762 KBOOL fThis = fThrowErrors;
[4402]763
764 setThrowOnErrors();
765 AppendFile.setThrowOnErrors();
766
767 end();
768 AppendFile.start();
769 AppendFile.refreshFileStatus();
770
[8003]771 cb = KMIN(1024*256, AppendFile.OSData.os2.filestatus.cbFile);
[4402]772 while (cb > 0)
773 {
774 AppendFile.read(pachBuffer, cb);
775 write(pachBuffer, cb);
[8003]776 cb = KMIN(1024*256, (long)AppendFile.OSData.os2.filestatus.cbFile - (long)AppendFile.offVirtual);
[4402]777 }
778
779 delete pachBuffer;
780 AppendFile.set(pos);
781 AppendFile.fThrowErrors = fAppend;
782 fThrowErrors = fThis;
783
784 return *this;
785}
786
787
788/**
[3592]789 * Seek relative to the current position.
[8003]790 * @returns 0 on success. kError error number.
[3592]791 * @param off Relative reposition.
792 */
[21916]793int kFile::move(long off) throw (kError)
[3592]794{
795 if ((off + offVirtual) & 0x80000000UL) /* above 2GB or negative */
796 rc = ERROR_NEGATIVE_SEEK;
797 else
798 {
[8003]799 if (off + offVirtual > OSData.os2.filestatus.cbFile && fReadOnly) /* can't expand readonly file. */
[3592]800 rc = ERROR_HANDLE_EOF;
801 else
802 {
803 offVirtual += off;
[8003]804 return rc = NO_ERROR;
[3592]805 }
806 }
807
808 if (fThrowErrors)
[8003]809 throw (kError(rc));
810 return rc;
[3592]811}
812
813
814/**
815 * Seek to an absolute position in the file (off).
[8003]816 * @returns 0 on success. kError error number.
[3592]817 * @param off New file position.
818 */
[21916]819int kFile::set(long off) throw (kError)
[3592]820{
821 if (off < 0)
822 rc = ERROR_NEGATIVE_SEEK;
823 else
824 {
[8003]825 if ((unsigned long)off > OSData.os2.filestatus.cbFile && fReadOnly)
[3592]826 rc = ERROR_HANDLE_EOF;
827 else
828 {
829 offVirtual = off;
[8003]830 return rc = NO_ERROR;
[3592]831 }
832 }
833 if (fThrowErrors)
[8003]834 throw (kError(rc));
835 return rc;
[3592]836}
837
838
839/**
840 * Seek to the end of the file.
[8003]841 * @returns 0 on success. kError error number.
[3592]842 * @remark Will only throw error if refreshFileStatus failes.
843 */
[21916]844int kFile::end() throw (kError)
[3592]845{
846 if (!refreshFileStatus())
[8003]847 return rc;
[4426]848
[8003]849 if (!fReadOnly && pachBuffer && offBuffer != ~0UL && offBuffer + cbBufferValid > OSData.os2.filestatus.cbFile)
[4426]850 /* a writable file with buffer might have uncommited data in the buffer. */
851 offVirtual = offBuffer + cbBufferValid;
852 else
[8003]853 offVirtual = OSData.os2.filestatus.cbFile;
[4426]854
[8003]855 return rc = NO_ERROR;
[3592]856}
857
858
859/**
860 * Seek to the start of the file.
[8003]861 * @returns 0 on success. kError error number.
[3592]862 * @remark Will never throw errors.
863 */
[8003]864int kFile::start()
[3592]865{
866 offVirtual = 0;
[8003]867 return rc = NO_ERROR;
[3592]868}
869
870
871/**
872 * Get the size of the file.
873 * @returns Returns file size on success.
874 * -1 on error.
875 * @remark Will only throw error if refreshFileStatus failes.
876 */
[21916]877long kFile::getSize() throw (kError)
[3592]878{
879 if (!refreshFileStatus())
880 return -1;
881
[8003]882 return OSData.os2.filestatus.cbFile;
[3592]883}
884
885
[3613]886/**
887 * Get current position.
888 * @returns The current file position.
889 * @remark Will only throw error if refreshFileStatus failes.
890 */
[21916]891long kFile::getPos() const throw (kError)
[3613]892{
893 return offVirtual;
894}
[3592]895
[3613]896
[3592]897/**
898 * Checks if we have reached the file end.
899 * @returns TRUE if end-of-file is reached.
900 * FALSE is not end-of-file.
901 * @remark Will only throw error if refreshFileStatus failes.
902 */
[21916]903KBOOL kFile::isEOF() throw (kError)
[3592]904{
905 #if 0
[8003]906 throw (kError(kError::NOT_SUPPORTED)); //this method don't currently work! Need to use flag!
[3592]907 #else
[4402]908 if (!fReadOnly && !refreshFileStatus())
[8003]909 return (KBOOL)-1;
[3592]910
[8003]911 return OSData.os2.filestatus.cbFile <= offVirtual; //??? - !!!
[3592]912 #endif
913}
914
915
916/**
917 * Set error behaviour to fail by throwing the OS/2 return code when an
918 * error occures.
919 * @remark Will never throw errors.
920 */
[8003]921void kFile::setThrowOnErrors()
[3592]922{
923 fThrowErrors = TRUE;
924 rc = NO_ERROR;
925}
926
927
928/**
929 * Set error behaviour to fail by return FALSE when an error has occures.
930 * @remark Will never throw errors.
931 */
[8003]932void kFile::setFailOnErrors()
[3592]933{
934 fThrowErrors = FALSE;
935 rc = NO_ERROR;
936}
937
938
939/**
940 * Gets the last error code.
941 * @returns OS/2 error code for the last operation.
942 * @remark Will never throw errors.
943 */
[3613]944int kFile::getLastError() const
[3592]945{
946 return rc;
947}
948
[5531]949
950
951/**
952 * Reads the specified file in to a memory block and returns it.
953 * @returns Pointer to memory mapping on success.
954 * NULL on error.
955 * @param pszFilename Name of the file.
956 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
957 * @remark May throw errors.
958 */
[21916]959void *kFile::mapFile(const char *pszFilename) throw (kError)
[5531]960{
961 kFile file(pszFilename);
[8003]962 file.setThrowOnErrors();
963 return file.mapFile();
[5531]964}
965
[8003]966
967
968/**
969 * Frees a file mapping done by one of the mapFile members of kFile.
970 * @param pvFileMapping The pointer mapFile returned.
971 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
972 */
[21916]973void kFile::mapFree(void *pvFileMapping) throw (kError)
[8003]974{
975 if (pvFileMapping)
976 free(pvFileMapping);
977}
978
Note: See TracBrowser for help on using the repository browser.