~hilaire-fernandes/drgeo/trunk

« back to all changes in this revision

Viewing changes to VMs/iPad/source/Cross/plugins/FilePlugin/sqFilePluginBasicPrims.c

  • Committer: Hilaire Fernandes
  • Date: 2012-01-27 21:15:40 UTC
  • Revision ID: hilaire.fernandes@gmail.com-20120127211540-912spf97bhpx6mve
Initial additions

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
*   PROJECT: File Interface
 
3
*   FILE:    sqFilePluginBasicPrims.c
 
4
*   CONTENT: 
 
5
*
 
6
*   AUTHOR:  
 
7
*   ADDRESS: 
 
8
*   EMAIL:   ]
 
9
*   RCSID:   $Id: sqFilePluginBasicPrims.c 2161 2010-04-01 19:10:46Z andreas $
 
10
*
 
11
*   NOTES: See change log below.
 
12
*       2008-08-29 bf  add stdin/stdout/stderr support
 
13
*       2005-03-26 IKP fix unaligned accesses to file[Size] members
 
14
*       2004-06-10 IKP 64-bit cleanliness
 
15
*       1/28/02    Tim remove non-ansi stuff
 
16
*                               unistd.h
 
17
                                ftello
 
18
                                fseeko
 
19
                                ftruncate & fileno
 
20
                                macro-ise use of sqFTruncate to avoid non-ansi
 
21
*       1/22/2002  JMM Use squeakFileOffsetType versus off_t
 
22
*
 
23
*****************************************************************************/
 
24
 
 
25
/* The basic prim code for file operations. See also the platform specific
 
26
* files typically named 'sq{blah}Directory.c' for details of the directory
 
27
* handling code. Note that the win32 platform #defines NO_STD_FILE_SUPPORT
 
28
* and thus bypasses this file
 
29
*/
 
30
                                                      
 
31
#include "sq.h"
 
32
#ifndef NO_STD_FILE_SUPPORT
 
33
#include "FilePlugin.h"
 
34
 
 
35
/***
 
36
        The state of a file is kept in the following structure,
 
37
        which is stored directly in a Squeak bytes object.
 
38
        NOTE: The Squeak side is responsible for creating an
 
39
        object with enough room to store sizeof(SQFile) bytes.
 
40
 
 
41
        The session ID is used to detect stale file objects--
 
42
        files that were still open when an image was written.
 
43
        The file pointer of such files is meaningless.
 
44
 
 
45
        Files are always opened in binary mode; Smalltalk code
 
46
        does (or someday will do) line-end conversion if needed.
 
47
 
 
48
        Writeable files are opened read/write. The stdio spec
 
49
        requires that a positioning operation be done when
 
50
        switching between reading and writing of a read/write
 
51
        filestream. The lastOp field records whether the last
 
52
        operation was a read or write operation, allowing this
 
53
        positioning operation to be done automatically if needed.
 
54
 
 
55
        typedef struct {
 
56
                File    *file;
 
57
                int             sessionID;
 
58
                int             writable;
 
59
                squeakFileOffsetType            fileSize;  //JMM Nov 8th 2001 64bits we hope
 
60
                int             lastOp;  // 0 = uncommitted, 1 = read, 2 = write //
 
61
        } SQFile;
 
62
 
 
63
***/
 
64
 
 
65
/*** Constants ***/
 
66
#define UNCOMMITTED     0
 
67
#define READ_OP         1
 
68
#define WRITE_OP        2
 
69
 
 
70
#ifndef SEEK_SET
 
71
#define SEEK_SET        0
 
72
#define SEEK_CUR        1
 
73
#define SEEK_END        2
 
74
#endif
 
75
 
 
76
/*** Variables ***/
 
77
int thisSession = 0;
 
78
extern struct VirtualMachine * interpreterProxy;
 
79
 
 
80
static void setFile(SQFile *f, FILE *file)
 
81
{
 
82
  void *in= (void *)&file;
 
83
  void *out= (void *)&f->file;
 
84
  memcpy(out, in, sizeof(FILE *));
 
85
}
 
86
 
 
87
static void setSize(SQFile *f, squeakFileOffsetType size)
 
88
{
 
89
  void *in= (void *)&size;
 
90
  void *out= (void *)&f->fileSize;
 
91
  memcpy(out, in, sizeof(squeakFileOffsetType));
 
92
}
 
93
 
 
94
static FILE *getFile(SQFile *f)
 
95
{
 
96
  FILE *file;
 
97
  void *in= (void *)&f->file;
 
98
  void *out= (void *)&file;
 
99
  memcpy(out, in, sizeof(FILE *));
 
100
  return file;
 
101
}
 
102
 
 
103
static squeakFileOffsetType getSize(SQFile *f)
 
104
{
 
105
  squeakFileOffsetType size;
 
106
  void *in= (void *)&f->fileSize;
 
107
  void *out= (void *)&size;
 
108
  memcpy(out, in, sizeof(squeakFileOffsetType));
 
109
  return size;
 
110
}
 
111
 
 
112
 
 
113
sqInt sqFileAtEnd(SQFile *f) {
 
114
        /* Return true if the file's read/write head is at the end of the file. */
 
115
 
 
116
        if (!sqFileValid(f)) return interpreterProxy->success(false);
 
117
        return ftell(getFile(f)) >= getSize(f);
 
118
}
 
119
 
 
120
sqInt sqFileClose(SQFile *f) {
 
121
        /* Close the given file. */
 
122
 
 
123
        FILE *file;
 
124
        if (!sqFileValid(f)) return interpreterProxy->success(false);
 
125
        file = getFile(f);
 
126
        if (file != stdin && file != stdout && file != stderr)
 
127
          fclose(file);
 
128
        setFile(f, 0);
 
129
        f->sessionID = 0;
 
130
        f->writable = false;
 
131
        setSize(f, 0);
 
132
        f->lastOp = UNCOMMITTED;
 
133
}
 
134
 
 
135
sqInt sqFileDeleteNameSize(char* sqFileName, sqInt sqFileNameSize) {
 
136
        char cFileName[1000];
 
137
        int err;
 
138
 
 
139
        if (sqFileNameSize >= 1000) {
 
140
                return interpreterProxy->success(false);
 
141
        }
 
142
 
 
143
        /* copy the file name into a null-terminated C string */
 
144
        interpreterProxy->ioFilenamefromStringofLengthresolveAliases(cFileName, sqFileName, sqFileNameSize, false);
 
145
 
 
146
        err = remove(cFileName);
 
147
        if (err) {
 
148
                return interpreterProxy->success(false);
 
149
        }
 
150
}
 
151
 
 
152
squeakFileOffsetType sqFileGetPosition(SQFile *f) {
 
153
        /* Return the current position of the file's read/write head. */
 
154
 
 
155
        squeakFileOffsetType position;
 
156
 
 
157
        if (!sqFileValid(f)) return interpreterProxy->success(false);
 
158
        position = ftell(getFile(f));
 
159
        if (position == -1) return interpreterProxy->success(false);
 
160
        return position;
 
161
}
 
162
 
 
163
sqInt sqFileInit(void) {
 
164
        /* Create a session ID that is unlikely to be repeated.
 
165
           Zero is never used for a valid session number.
 
166
           Should be called once at startup time.
 
167
        */
 
168
#if VM_PROXY_MINOR > 6
 
169
        thisSession = (int) interpreterProxy->getThisSessionID();
 
170
#else
 
171
        thisSession = ioLowResMSecs() + time(NULL);
 
172
        if (thisSession == 0) thisSession = 1;  /* don't use 0 */
 
173
#endif
 
174
        return 1;
 
175
}
 
176
 
 
177
sqInt sqFileShutdown(void) {
 
178
        return 1;
 
179
}
 
180
 
 
181
static int setStdFilename(char* stdFilename, char *cFileName, char *sqFileName, sqInt sqFileNameSize)
 
182
{
 
183
  if (!strncmp(stdFilename, sqFileName,sqFileNameSize)) {
 
184
    strcpy(cFileName, stdFilename);
 
185
    return 1;
 
186
  } else
 
187
    return 0;
 
188
}
 
189
 
 
190
sqInt sqFileOpen(SQFile *f, char* sqFileName, sqInt sqFileNameSize, sqInt writeFlag) {
 
191
        /* Opens the given file using the supplied sqFile structure
 
192
           to record its state. Fails with no side effects if f is
 
193
           already open. Files are always opened in binary mode;
 
194
           Squeak must take care of any line-end character mapping.
 
195
        */
 
196
 
 
197
        char cFileName[1001];
 
198
 
 
199
        /* don't open an already open file */
 
200
        if (sqFileValid(f)) return interpreterProxy->success(false);
 
201
 
 
202
        /* copy the file name into a null-terminated C string */
 
203
        if (sqFileNameSize > 1000) {
 
204
                return interpreterProxy->success(false);
 
205
        }
 
206
 
 
207
        if (setStdFilename("/dev/stdin", cFileName, sqFileName, sqFileNameSize)) 
 
208
          setFile(f, stdin);
 
209
        else if (setStdFilename("/dev/stdout", cFileName, sqFileName, sqFileNameSize))
 
210
          setFile(f, stdout);
 
211
        else if (setStdFilename("/dev/stderr", cFileName, sqFileName, sqFileNameSize))
 
212
          setFile(f, stderr);
 
213
        else
 
214
          interpreterProxy->ioFilenamefromStringofLengthresolveAliases(cFileName, sqFileName, sqFileNameSize, true);
 
215
 
 
216
        if (writeFlag) {
 
217
                /* First try to open an existing file read/write: */
 
218
                if (getFile(f) == NULL)
 
219
                        setFile(f, fopen(cFileName, "r+b"));
 
220
                if (getFile(f) == NULL) {
 
221
                        /* Previous call fails if file does not exist. In that case,
 
222
                           try opening it in write mode to create a new, empty file.
 
223
                        */
 
224
                        setFile(f, fopen(cFileName, "w+b"));
 
225
                        if (getFile(f) != NULL) {
 
226
                            char type[4],creator[4];
 
227
                                dir_GetMacFileTypeAndCreator(sqFileName, sqFileNameSize, type, creator);
 
228
                                if (strncmp(type,"BINA",4) == 0 || strncmp(type,"????",4) == 0 || *(int *)type == 0 ) 
 
229
                                    dir_SetMacFileTypeAndCreator(sqFileName, sqFileNameSize,"TEXT","R*ch");     
 
230
                        }
 
231
                }
 
232
                f->writable = true;
 
233
        } else {
 
234
                if (getFile(f) == NULL)
 
235
                        setFile(f, fopen(cFileName, "rb"));
 
236
                f->writable = false;
 
237
        }
 
238
 
 
239
        if (getFile(f) == NULL) {
 
240
                f->sessionID = 0;
 
241
                setSize(f, 0);
 
242
                return interpreterProxy->success(false);
 
243
        } else {
 
244
                FILE *file= getFile(f);
 
245
                f->sessionID = thisSession;
 
246
                /* compute and cache file size */
 
247
                fseek(file, 0, SEEK_END);
 
248
                setSize(f, ftell(file));
 
249
                fseek(file, 0, SEEK_SET);
 
250
        }
 
251
        f->lastOp = UNCOMMITTED;
 
252
}
 
253
 
 
254
size_t sqFileReadIntoAt(SQFile *f, size_t count, char* byteArrayIndex, size_t startIndex) {
 
255
        /* Read count bytes from the given file into byteArray starting at
 
256
           startIndex. byteArray is the address of the first byte of a
 
257
           Squeak bytes object (e.g. String or ByteArray). startIndex
 
258
           is a zero-based index; that is a startIndex of 0 starts writing
 
259
           at the first byte of byteArray.
 
260
        */
 
261
 
 
262
        char *dst;
 
263
        size_t bytesRead;
 
264
        FILE *file;
 
265
 
 
266
        if (!sqFileValid(f)) return interpreterProxy->success(false);
 
267
        file= getFile(f);
 
268
        if (f->writable && (f->lastOp == WRITE_OP)) fseek(file, 0, SEEK_CUR);  /* seek between writing and reading */
 
269
        dst = byteArrayIndex + startIndex;
 
270
        bytesRead = fread(dst, 1, count, file);
 
271
        f->lastOp = READ_OP;
 
272
        return bytesRead;
 
273
}
 
274
 
 
275
sqInt sqFileRenameOldSizeNewSize(char* oldNameIndex, sqInt oldNameSize, char* newNameIndex, sqInt newNameSize) {
 
276
        char cOldName[1000], cNewName[1000];
 
277
        int err;
 
278
 
 
279
        if ((oldNameSize >= 1000) || (newNameSize >= 1000)) {
 
280
                return interpreterProxy->success(false);
 
281
        }
 
282
 
 
283
        /* copy the file names into null-terminated C strings */
 
284
        interpreterProxy->ioFilenamefromStringofLengthresolveAliases(cOldName, oldNameIndex, oldNameSize, false);
 
285
 
 
286
        interpreterProxy->ioFilenamefromStringofLengthresolveAliases(cNewName, newNameIndex, newNameSize, false);
 
287
 
 
288
        err = rename(cOldName, cNewName);
 
289
        if (err) {
 
290
                return interpreterProxy->success(false);
 
291
        }
 
292
}
 
293
 
 
294
sqInt sqFileSetPosition(SQFile *f, squeakFileOffsetType position) {
 
295
        /* Set the file's read/write head to the given position. */
 
296
 
 
297
        if (!sqFileValid(f)) return interpreterProxy->success(false);
 
298
        fseek(getFile(f), position, SEEK_SET);
 
299
        f->lastOp = UNCOMMITTED;
 
300
}
 
301
 
 
302
squeakFileOffsetType sqFileSize(SQFile *f) {
 
303
        /* Return the length of the given file. */
 
304
 
 
305
        if (!sqFileValid(f)) return interpreterProxy->success(false);
 
306
        return getSize(f);
 
307
}
 
308
 
 
309
sqInt sqFileFlush(SQFile *f) {
 
310
        /* Return the length of the given file. */
 
311
 
 
312
        if (!sqFileValid(f)) return interpreterProxy->success(false);
 
313
        fflush(getFile(f));
 
314
        return 1;
 
315
}
 
316
 
 
317
sqInt sqFileTruncate(SQFile *f,squeakFileOffsetType offset) {
 
318
        /* Truncate the file*/
 
319
 
 
320
        if (!sqFileValid(f)) return interpreterProxy->success(false);
 
321
        if (sqFTruncate(getFile(f), offset)) {
 
322
            return interpreterProxy->success(false);
 
323
        } 
 
324
        setSize(f, ftell(getFile(f)));
 
325
        return 1;
 
326
}
 
327
 
 
328
 
 
329
sqInt sqFileValid(SQFile *f) {
 
330
        return (
 
331
                (f != NULL) &&
 
332
                (getFile(f) != NULL) &&
 
333
                (f->sessionID == thisSession));
 
334
}
 
335
 
 
336
size_t sqFileWriteFromAt(SQFile *f, size_t count, char* byteArrayIndex, size_t startIndex) {
 
337
        /* Write count bytes to the given writable file starting at startIndex
 
338
           in the given byteArray. (See comment in sqFileReadIntoAt for interpretation
 
339
           of byteArray and startIndex).
 
340
        */
 
341
 
 
342
        char *src;
 
343
        size_t bytesWritten;
 
344
        squeakFileOffsetType position;
 
345
        FILE *file;
 
346
 
 
347
        if (!(sqFileValid(f) && f->writable)) return interpreterProxy->success(false);
 
348
        file= getFile(f);
 
349
        if (f->lastOp == READ_OP) fseek(file, 0, SEEK_CUR);  /* seek between reading and writing */
 
350
        src = byteArrayIndex + startIndex;
 
351
        bytesWritten = fwrite(src, 1, count, file);
 
352
 
 
353
        position = ftell(file);
 
354
        if (position > getSize(f)) {
 
355
                setSize(f, position);  /* update file size */
 
356
        }
 
357
 
 
358
        if (bytesWritten != count) {
 
359
                interpreterProxy->success(false);
 
360
        }
 
361
        f->lastOp = WRITE_OP;
 
362
        return bytesWritten;
 
363
}
 
364
 
 
365
sqInt sqFileThisSession() {
 
366
        return thisSession;
 
367
}
 
368
 
 
369
#endif /* NO_STD_FILE_SUPPORT */
 
370