summaryrefslogtreecommitdiff
path: root/tvision/classes/tfileedi.cc
blob: 6f57f88b3eb45164f6a4d0472c2eed37233280c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/* Modified by Robert Hoehne and Salvador Eduardo Tropea for the gcc port */
/* Modified by Vadim Beloborodov to be used on WIN32 console */
/* Modified to compile with gcc v3.x by Salvador E. Tropea, with the help of
   Andris Pavenis. */
/* Modified by Salvador E. Tropea to avoid using C++ streams (just C code) */
/*----------------------------------------------------------*/
/*                                                          */
/*   Turbo Vision 1.0                                       */
/*   Copyright (c) 1991 by Borland International            */
/*                                                          */
/*----------------------------------------------------------*/
#include <tv/configtv.h>

#define Uses_filelength
#define Uses_limits
#define Uses_string
#define Uses_fcntl
#ifdef TVComp_MSC
 #include <io.h>
#else
 #define Uses_unistd
#endif
#define Uses_stdio
#define Uses_sys_stat

#define Uses_TGroup
#define Uses_TEditor
#define Uses_TFileEditor
#define Uses_TEvent
#define Uses_opstream
#define Uses_ipstream
#define Uses_TStreamableClass
#define Uses_IOS_BIN
#include <tv.h>

UsingNamespaceStd

inline uint32 min( uint32 u1, uint32 u2 )
{
    return u1 < u2 ? u1 : u2;
}

TFileEditor::TFileEditor( const TRect& bounds,
                          TScrollBar *aHScrollBar,
                          TScrollBar *aVScrollBar,
                          TIndicator *aIndicator,
                          const char *aFileName
                        ) :
    TEditor( bounds, aHScrollBar, aVScrollBar, aIndicator, 4096 )
{
    if( aFileName == 0 )
        fileName[0] = EOS;
    else
        {
        strcpy( fileName, aFileName );
        if( isValid )
            isValid = loadFile();
        }
}

void TFileEditor::doneBuffer()
{
    DeleteArray(buffer);
}

void TFileEditor::handleEvent( TEvent& event )
{
    TEditor::handleEvent(event);
    switch( event.what )
        {
        case evCommand:
            switch( event.message.command )
                {
                case cmSave:
                    save();
                    break;
                case cmSaveAs:
                    saveAs();
                    break;
                default:
                    return;
                }
            break;
        default:
            return;
        }
    clearEvent(event);
}

void TFileEditor::initBuffer()
{
    buffer = new char[bufSize];
}

Boolean TFileEditor::loadFile()
{
    int crfound = 0;
    char tmp[PATH_MAX];
    FILE *f=fopen(fileName,"rb");
    if( !f )
        {
        setBufLen( 0 );
        return True;
        }
    else
        {
        #ifdef TVOS_DOS
        int i;
/* check for a unix text file (is a heuristic, because only 1024 chars checked */
        {
          char tmpbuf[1024];
          long fsize=filelength(fileno(f));
          if (fsize > 1024) fsize = 1024;
          fread(tmpbuf,fsize,1,f);
          for (i=0;i<1024;i++)
          {
            if (tmpbuf[i] == '\r') crfound = 1;
            else if (tmpbuf[i] == '\n') break;
          }
          if (crfound)
          {
            fseek(f,0,SEEK_SET);
          }
          else
          {
            int readhandle,writehandle;
            fclose(f);
            readhandle = open(fileName,O_RDONLY|O_BINARY);
            tmpnam(tmp);
            writehandle = open(tmp,O_WRONLY|O_CREAT|O_TRUNC|O_TEXT,0600);
            while ((fsize = ::read(readhandle,tmpbuf,1024)) > 0)
              ::write(writehandle,tmpbuf,fsize);
            close(readhandle);
            close(writehandle);
            f=fopen(tmp,"rb");
          }
        }
        #endif
        long fSize=filelength(fileno(f));;
        if( setBufSize((uint32)(fSize)) == False )
            {
            editorDialog( edOutOfMemory );
            if (!crfound) remove(tmp);
            return False;
            }
        else
            {
            if ( fSize > INT_MAX )
            {
               fread( &buffer[bufSize - (uint32)(fSize)], INT_MAX, 1, f );
               fread( &buffer[bufSize - (uint32)(fSize) + INT_MAX],
                                (uint32)(fSize - INT_MAX), 1, f );

            }
            else
               fread( &buffer[bufSize - (uint32)(fSize)], (uint32)(fSize), 1, f );
            int error=ferror(f);
            if( fclose(f) || error )
                {
                editorDialog( edReadError, fileName );
                if (!crfound) remove(tmp);
                return False;
                }
            else
                {
                setBufLen((uint32)(fSize));
                if (!crfound) remove(tmp);
                return True;
                }
            }
        }
}

Boolean TFileEditor::save()
{
    if( *fileName == EOS )
        return saveAs();
    else
        return saveFile();
}

Boolean TFileEditor::saveAs()
{
    Boolean res = False;
    if( editorDialog( edSaveAs, fileName ) != cmCancel )
        {
        CLY_fexpand( fileName );
        message( owner, evBroadcast, cmUpdateTitle, 0 );
        res = saveFile();
        if( isClipboard() == True )
            *fileName = EOS;
        }
    return res;
}

static void writeBlock( FILE *f, char *buf, unsigned len )
{
    while( len > 0 )
        {
        int l = len < INT_MAX ? len : INT_MAX;
        fwrite( buf, l, 1, f );
        buf += l;
        len -= l;
        }
}

// SET: from my editor:
static
int edTestForFile(const char *name)
{
 struct stat st;

 if (stat(name,&st)==0)
    return S_ISREG(st.st_mode);
 return 0;
}

Boolean TFileEditor::saveFile()
{
    // SET: That's similar to what I use in TCEdit and is partially a hack
    // to avoid fnsplit & fnmerge in Linux (originally from Robert).
    if ((editorFlags & efBackupFiles) &&
        edTestForFile(fileName)) // Forget about it if that's a new file
      {
       char *dot,*slash;
       int flen = strlen(fileName);
       char backupName[PATH_MAX];
       strcpy(backupName,fileName);
       dot = strrchr(backupName,'.');
       slash = strrchr(backupName,DIRSEPARATOR);
       if (dot < slash) // directory has a dot but not the filename
         dot = NULL;
       if (!dot)
         dot = backupName + flen;
       strcpy(dot,backupExt);
       unlink( backupName );
       rename( fileName, backupName );
      }

    FILE *f=fopen(fileName,"wb");

    if( !f )
        {
        editorDialog( edCreateError, fileName );
        return False;
        }
    else
        {
        writeBlock( f, buffer, curPtr );
        writeBlock( f, buffer+curPtr+gapLen, bufLen-curPtr );

        int error=ferror(f); // SET: Is that needed? Or fclose will inform the error?
        if( fclose(f) || error )
            {
            editorDialog( edWriteError, fileName );
            return False;
            }
        else
            {
            modified = False;
            update(ufUpdate);
            }
        }
    return True;
}

Boolean TFileEditor::setBufSize( uint32 newSize )
{
   newSize = (newSize + 0x0FFF) & 0xFFFFF000L;
    if( newSize != bufSize )
        {
        char *temp = buffer;
        if( (buffer = new char[newSize]) == 0 )
            {
            delete temp;
            return False;
            }
        uint32 n = bufLen - curPtr + delCount;
        memcpy( buffer, temp, min( newSize, bufSize ) );
        memmove( &buffer[newSize - n], &temp[bufSize - n], n );
        delete temp;
        bufSize = newSize;
        gapLen = bufSize - bufLen;
        }
    return True;
}

void TFileEditor::shutDown()
{
    setCmdState(cmSave, False);
    setCmdState(cmSaveAs, False);
    TEditor::shutDown();
}

void TFileEditor::updateCommands()
{
    TEditor::updateCommands();
    setCmdState(cmSave, True);
    setCmdState(cmSaveAs, True);
}

Boolean TFileEditor::valid( ushort command )
{
    if( command == cmValid )
        return isValid;
    else
        {
        if( modified == True )
            {
            int d;
            if( *fileName == EOS )
                d = edSaveUntitled;
            else
                d = edSaveModify;

            switch( editorDialog( d, fileName ) )
                {
                case cmYes:
                    return save();
                case cmNo:
                    modified = False;
                    return True;
                case cmCancel:
                    return False;
                }
            }
        }
    return True;
}

#ifndef NO_STREAM

void TFileEditor::write( opstream& os )
{
    TEditor::write( os );
    os.writeString( fileName );
    os << selStart << selEnd << curPtr;
}

void *TFileEditor::read( ipstream& is )
{
    TEditor::read( is );
    is.readString( fileName, sizeof( fileName ) );
    if( isValid )
        {
        isValid = loadFile();
        uint32 sStart, sEnd, curs;
        is >> sStart >> sEnd >> curs;
        if( isValid && sEnd <= bufLen )
            {
            setSelect( sStart, sEnd, Boolean(curs == sStart) );
            trackCursor( True );
            }
        }
    return this;
}

TStreamable *TFileEditor::build()
{
    return new TFileEditor( streamableInit );
}

TFileEditor::TFileEditor( StreamableInit ) : TEditor( streamableInit )
{
}

#endif

// SET: Changed to lower case because it looks much better when using LFNs
const char *TFileEditor::backupExt = ".bak";