void DOSFAM::CloseTableFile(PGLOBAL g) { int rc; if (UseTemp && T_Stream) { if (Tdbp->Mode == MODE_UPDATE) { // Copy eventually remaining lines bool b; fseek(Stream, 0, SEEK_END); Fpos = ftell(Stream); rc = MoveIntermediateLines(g, &b); } // endif Mode // Delete the old file and rename the new temp file. RenameTempFile(g); // Also close all files } else { rc = PlugCloseFile(g, To_Fb); if (trace) htrc("DOS Close: closing %s rc=%d\n", To_File, rc); } // endif UseTemp Stream = NULL; // So we can know whether table is open } // end of CloseTableFile
void BLKFAM::CloseTableFile(PGLOBAL g) { int rc, wrc = RC_OK; if (UseTemp && T_Stream) { if (Tdbp->GetMode() == MODE_UPDATE) { // Copy eventually remaining lines bool b; fseek(Stream, 0, SEEK_END); Fpos = ftell(Stream); rc = MoveIntermediateLines(g, &b); } else rc = RC_OK; if (rc == RC_OK) // Delete the old file and rename the new temp file. rc = RenameTempFile(g); // Also close all files else rc = PlugCloseFile(g, To_Fb); } else { // Closing is True if last Write was in error if (Tdbp->GetMode() == MODE_INSERT && CurNum && !Closing) { // Some more inserted lines remain to be written Rbuf = CurNum--; Closing = true; wrc = WriteBuffer(g); } else if (Modif && !Closing) { // Last updated block remains to be written Closing = true; wrc = ReadBuffer(g); } // endif's rc = PlugCloseFile(g, To_Fb); if (trace) htrc("BLK CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n", To_File, Tdbp->GetMode(), wrc, rc); } // endif UseTemp Stream = NULL; // So we can know whether table is open } // end of CloseTableFile
int DOSFAM::DeleteRecords(PGLOBAL g, int irc) { bool moved; int curpos = ftell(Stream); /*********************************************************************/ /* There is an alternative here: */ /* 1 - use a temporary file in which are copied all not deleted */ /* lines, at the end the original file will be deleted and */ /* the temporary file renamed to the original file name. */ /* 2 - directly move the not deleted lines inside the original */ /* file, and at the end erase all trailing records. */ /* This will be experimented, but method 1 must be used for Unix as */ /* the function needed to erase trailing records is not available. */ /*********************************************************************/ if (trace) htrc( "DOS DeleteDB: rc=%d UseTemp=%d curpos=%d Fpos=%d Tpos=%d Spos=%d\n", irc, UseTemp, curpos, Fpos, Tpos, Spos); if (irc != RC_OK) { /*******************************************************************/ /* EOF: position Fpos at the end-of-file position. */ /*******************************************************************/ fseek(Stream, 0, SEEK_END); Fpos = ftell(Stream); if (trace) htrc("Fpos placed at file end=%d\n", Fpos); } // endif irc if (Tpos == Spos) { /*******************************************************************/ /* First line to delete, Open temporary file. */ /*******************************************************************/ if (UseTemp) { if (OpenTempFile(g)) return RC_FX; } else { /*****************************************************************/ /* Move of eventual preceeding lines is not required here. */ /* Set the target file as being the source file itself. */ /* Set the future Tpos, and give Spos a value to block copying. */ /*****************************************************************/ T_Stream = Stream; Spos = Tpos = Fpos; } // endif UseTemp } // endif Tpos == Spos /*********************************************************************/ /* Move any intermediate lines. */ /*********************************************************************/ if (MoveIntermediateLines(g, &moved)) return RC_FX; if (irc == RC_OK) { /*******************************************************************/ /* Reposition the file pointer and set Spos. */ /*******************************************************************/ if (!UseTemp || moved) if (fseek(Stream, curpos, SEEK_SET)) { sprintf(g->Message, MSG(FSETPOS_ERROR), 0); return RC_FX; } // endif Spos = GetNextPos(); // New start position if (trace) htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos); } else { /*******************************************************************/ /* Last call after EOF has been reached. */ /* The UseTemp case is treated in CloseTableFile. */ /*******************************************************************/ if (!UseTemp) { /*****************************************************************/ /* Because the chsize functionality is only accessible with a */ /* system call we must close the file and reopen it with the */ /* open function (_fopen for MS ??) this is still to be checked */ /* for compatibility with Text files and other OS's. */ /*****************************************************************/ char filename[_MAX_PATH]; int h; // File handle, return code PlugSetPath(filename, To_File, Tdbp->GetPath()); /*rc=*/ PlugCloseFile(g, To_Fb); if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0) return RC_FX; /*****************************************************************/ /* Remove extra records. */ /*****************************************************************/ #if defined(UNIX) if (ftruncate(h, (off_t)Tpos)) { sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno)); close(h); return RC_FX; } // endif #else if (chsize(h, Tpos)) { sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno)); close(h); return RC_FX; } // endif #endif close(h); if (trace) htrc("done, h=%d irc=%d\n", h, irc); } // endif !UseTemp } // endif irc return RC_OK; // All is correct } // end of DeleteRecords
int DOSFAM::ReadBuffer(PGLOBAL g) { char *p; int rc; if (!Stream) return RC_EF; if (trace > 1) htrc("ReadBuffer: Tdbp=%p To_Line=%p Placed=%d\n", Tdbp, Tdbp->To_Line, Placed); if (!Placed) { /*******************************************************************/ /* Record file position in case of UPDATE or DELETE. */ /*******************************************************************/ if (RecordPos(g)) return RC_FX; CurBlk = (int)Rows++; if (trace > 1) htrc("ReadBuffer: CurBlk=%d\n", CurBlk); } else Placed = false; if (trace > 1) htrc(" About to read: stream=%p To_Buf=%p Buflen=%d\n", Stream, To_Buf, Buflen); if (fgets(To_Buf, Buflen, Stream)) { p = To_Buf + strlen(To_Buf) - 1; if (trace > 1) htrc(" Read: To_Buf=%p p=%c\n", To_Buf, To_Buf, p); #if defined(UNIX) if (true) { // Data files can be imported from Windows (having CRLF) #else if (Bin) { // Data file is read in binary so CRLF remains #endif if (*p == '\n' || *p == '\r') { // is this enough for Unix ??? *p = '\0'; // Eliminate ending CR or LF character if (p > To_Buf) { // is this enough for Unix ??? p--; if (*p == '\n' || *p == '\r') *p = '\0'; // Eliminate ending CR or LF character } // endif To_Buf } // endif p } else if (*p == '\n') *p = '\0'; // Eliminate ending new-line character if (trace > 1) htrc(" To_Buf='%s'\n", To_Buf); strcpy(Tdbp->To_Line, To_Buf); num_read++; rc = RC_OK; } else if (feof(Stream)) { rc = RC_EF; } else { #if defined(UNIX) sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(0)); #else sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL)); #endif if (trace) htrc("%s\n", g->Message); rc = RC_FX; } // endif's fgets if (trace > 1) htrc("ReadBuffer: rc=%d\n", rc); IsRead = true; return rc; } // end of ReadBuffer /***********************************************************************/ /* WriteBuffer: File write routine for DOS access method. */ /***********************************************************************/ int DOSFAM::WriteBuffer(PGLOBAL g) { char *crlf = "\n"; int curpos = 0; bool moved = true; // T_Stream is the temporary stream or the table file stream itself if (!T_Stream) if (UseTemp && Tdbp->Mode == MODE_UPDATE) { if (OpenTempFile(g)) return RC_FX; } else T_Stream = Stream; if (Tdbp->Mode == MODE_UPDATE) { /*******************************************************************/ /* Here we simply rewrite a record on itself. There are two cases */ /* were another method should be used, a/ when Update apply to */ /* the whole file, b/ when updating the last field of a variable */ /* length file. The method could be to rewrite a new file, then */ /* to erase the old one and rename the new updated file. */ /*******************************************************************/ curpos = ftell(Stream); if (trace) htrc("Last : %d cur: %d\n", Fpos, curpos); if (UseTemp) { /*****************************************************************/ /* We are using a temporary file. Before writing the updated */ /* record, we must eventually copy all the intermediate records */ /* that have not been updated. */ /*****************************************************************/ if (MoveIntermediateLines(g, &moved)) return RC_FX; Spos = curpos; // New start position } else // Update is directly written back into the file, // with this (fast) method, record size cannot change. if (fseek(Stream, Fpos, SEEK_SET)) { sprintf(g->Message, MSG(FSETPOS_ERROR), 0); return RC_FX; } // endif } // endif mode /*********************************************************************/ /* Prepare the write buffer. */ /*********************************************************************/ #if defined(WIN32) if (Bin) crlf = "\r\n"; #endif // WIN32 strcat(strcpy(To_Buf, Tdbp->To_Line), crlf); /*********************************************************************/ /* Now start the writing process. */ /*********************************************************************/ if ((fputs(To_Buf, T_Stream)) == EOF) { sprintf(g->Message, MSG(FPUTS_ERROR), strerror(errno)); return RC_FX; } // endif EOF if (Tdbp->Mode == MODE_UPDATE && moved) if (fseek(Stream, curpos, SEEK_SET)) { sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno)); return RC_FX; } // endif if (trace) htrc("write done\n"); return RC_OK; } // end of WriteBuffer
int BLKFAM::WriteBuffer(PGLOBAL g) { if (Tdbp->GetMode() == MODE_INSERT) { /*******************************************************************/ /* In Insert mode, blocks are added sequentially to the file end. */ /*******************************************************************/ if (!Closing) { // Add line to the write buffer strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf); if (++CurNum != Rbuf) { CurLine += strlen(CurLine); return RC_OK; // We write only full blocks } // endif CurNum } // endif Closing // Now start the writing process. NxtLine = CurLine + strlen(CurLine); BlkLen = NxtLine - To_Buf; if (fwrite(To_Buf, 1, BlkLen, Stream) != (size_t)BlkLen) { sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno)); Closing = true; // To tell CloseDB about a Write error return RC_FX; } // endif size CurBlk++; CurNum = 0; CurLine = To_Buf; } else { /*******************************************************************/ /* Mode == MODE_UPDATE. */ /*******************************************************************/ char *crlf; size_t len; int curpos = ftell(Stream); bool moved = true; // T_Stream is the temporary stream or the table file stream itself if (!T_Stream) if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) { if (OpenTempFile(g)) return RC_FX; } else T_Stream = Stream; if (UseTemp) { /*****************************************************************/ /* We are using a temporary file. Before writing the updated */ /* record, we must eventually copy all the intermediate records */ /* that have not been updated. */ /*****************************************************************/ if (MoveIntermediateLines(g, &moved)) return RC_FX; Spos = GetNextPos(); // New start position // Prepare the output buffer #if defined(WIN32) crlf = "\r\n"; #else crlf = "\n"; #endif // WIN32 strcat(strcpy(OutBuf, Tdbp->GetLine()), crlf); len = strlen(OutBuf); } else { if (fseek(Stream, Fpos, SEEK_SET)) { // Fpos is last position sprintf(g->Message, MSG(FSETPOS_ERROR), 0); return RC_FX; } // endif fseek // Replace the line inside read buffer (length has not changed) memcpy(CurLine, Tdbp->GetLine(), strlen(Tdbp->GetLine())); OutBuf = CurLine; len = (size_t)(NxtLine - CurLine); } // endif UseTemp if (fwrite(OutBuf, 1, len, T_Stream) != (size_t)len) { sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno)); return RC_FX; } // endif fwrite if (moved) if (fseek(Stream, curpos, SEEK_SET)) { sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno)); return RC_FX; } // endif } // endif Mode return RC_OK; } // end of WriteBuffer
void DBFFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc = RC_OK, wrc = RC_OK; MODE mode = Tdbp->GetMode(); Abort = abort; // Closing is True if last Write was in error if (mode == MODE_INSERT && CurNum && !Closing) { // Some more inserted lines remain to be written Rbuf = CurNum--; // Closing = true; wrc = WriteBuffer(g); } else if (mode == MODE_UPDATE || mode == MODE_DELETE) { if (Modif && !Closing) { // Last updated block remains to be written Closing = true; wrc = WriteModifiedBlock(g); } // endif Modif if (UseTemp && T_Stream && wrc == RC_OK) { if (!Abort) { // Copy any remaining lines bool b; Fpos = Tdbp->Cardinality(g); Abort = MoveIntermediateLines(g, &b) != RC_OK; } // endif Abort // Delete the old file and rename the new temp file. RenameTempFile(g); goto fin; } // endif UseTemp } // endif's mode if (Tdbp->GetMode() == MODE_INSERT) { int n = ftell(Stream) - Headlen; rc = PlugCloseFile(g, To_Fb); if (n >= 0 && !(n % Lrecl)) { n /= Lrecl; // New number of lines if (n > Records) { // Update the number of rows in the file header char filename[_MAX_PATH]; PlugSetPath(filename, To_File, Tdbp->GetPath()); if ((Stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r+b"))) { fseek(Stream, 4, SEEK_SET); // Get header.Records position fwrite(&n, sizeof(int), 1, Stream); fclose(Stream); Stream= NULL; Records= n; // Update Records value } } // endif n } // endif n } else // Finally close the file rc = PlugCloseFile(g, To_Fb); fin: if (trace) htrc("DBF CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n", To_File, mode, wrc, rc); Stream = NULL; // So we can know whether table is open } // end of CloseTableFile