- Now puts cursor position in window title properly instead of overwriting
[tangerine.git] / workbench / tools / Edit / DiskIO.c
blob425666d105eabb64169ddcde553331f607f50410
1 /**************************************************************
2 **** diskio.c : procedures for accessing/writing on disk ****
3 **** Free software under GNU license, started on 25/2/2000 ****
4 **** © T.Pierron, C.Guillaume. ****
5 **************************************************************/
7 #include <intuition/intuition.h>
8 #include <libraries/asl.h>
9 #include <exec/memory.h>
10 #include <dos/dos.h>
11 #include "Project.h"
12 #include "DiskIO.h"
13 #include "Gui.h"
14 #include "Utility.h"
15 #include "ProtoTypes.h"
17 #define CATCOMP_NUMBERS /* Error msg use strings id */
18 #include "strings.h"
20 #define MEM_CHUNK 8192 /* To save file */
22 extern struct Library *AslBase;
24 extern struct Screen *Scr;
25 struct FileRequester *fr=NULL;
27 /* ASL load or save requester tags */
28 static ULONG tags[] = {
29 ASLFR_InitialLeftEdge, 0,
30 ASLFR_InitialTopEdge, 0,
31 ASLFR_InitialWidth, 320,
32 ASLFR_InitialHeight, 256,
33 ASLFR_Window, (IPTR) NULL,
34 ASLFR_Screen, (IPTR) NULL,
35 ASLFR_Flags1, 0,
36 ASLFR_SleepWindow, TRUE,
37 ASLFR_InitialDrawer, (IPTR) NULL,
38 ASLFR_InitialFile, (IPTR) NULL,
39 ASLFR_InitialPattern, (IPTR) NULL,
40 ASLFR_TitleText, (IPTR) NULL,
41 TAG_DONE
44 /* Different End Of Line marker */
45 UBYTE chEOL[] = {'\n', '\r', '\r', '\n'};
46 UBYTE szEOL[] = {1, 1, 2};
48 /*** Find the correctly spelled path ***/
49 BYTE get_full_path( STRPTR filename, STRPTR *dest )
51 STRPTR file = NULL, path;
52 BPTR lock;
53 WORD len;
55 len = sizeof(STR_MODIF) + 1;
56 lock = (BPTR) Lock(filename, SHARED_LOCK);
58 /* Can't get lock, surely because file does not exist */
59 if( lock == NULL ) {
60 file = (STRPTR) FilePart(filename); len += strlen(file);
61 if(file != filename) {
62 char svg = *file; *file = 0;
63 lock = (BPTR) Lock(filename, SHARED_LOCK); *file = svg;
67 /* Be sure the locked object is of the desired type */
68 if(lock != NULL)
70 struct FileInfoBlock *fib;
71 if((fib = (void *) AllocVec(sizeof(*fib), MEMF_PUBLIC)) && Examine(lock, fib))
73 /* That's particularly nasty, but prevent user of doing mistakes */
74 if(file == NULL ? fib->fib_EntryType > 0 : fib->fib_EntryType < 0)
75 /* Filename sucks, get a generic one */
76 UnLock(lock), lock = NULL;
78 if( fib ) FreeVec( fib );
79 else { UnLock(lock); return ERR_NOMEM; }
80 /* User has given a directory as file to edit! */
81 if(file == NULL && lock == NULL) return ERR_WRONG_TYPE;
84 /* The directory/file exists, Get its correctly spelled name */
85 for(len += 256; ;)
87 if( ( path = (STRPTR) AllocVec(len, MEMF_PUBLIC) ) ) {
88 /* If no directory provide, try to get the current wd */
89 if( lock ? NameFromLock(lock, path, len) :
90 GetCurrentDirName(path, len) )
92 /* At last if there was a file name, add it to the buffer */
93 if( file ) AddPart(path, file, len);
94 *dest = path;
95 break;
97 } else return ERR_NOMEM;
98 /* Fucking name! reallocate a longer buffer! */
99 FreeVec(path); len += 64;
101 if( lock ) UnLock(lock);
103 return 0;
106 /*** Extract path and file into 2 separate pointers (for ASL) ***/
107 void split_path(AskArgs *src, STRPTR *dir, STRPTR *file)
109 extern UBYTE BufTxt[256];
110 if( src->dir != NULL )
112 /* TODO cleanup */
113 UWORD Len = src->file - src->dir;
114 if(dir != NULL) {
115 if(Len >= sizeof(BufTxt)) Len = sizeof(BufTxt)-1;
116 CopyMem(src->dir, BufTxt, Len); BufTxt[Len] = '\0';
117 *dir = BufTxt;
118 } else Len = 0;
120 /* Copy file name */
121 *file = BufTxt+Len+1; Len = strlen( src->file );
122 if( src->modifmark ) Len -= sizeof(STR_MODIF)-1;
123 CopyMem(src->file, *file, Len); (*file)[Len] = '\0';
125 else
127 *file = src->file;
128 if ( dir != NULL ) *dir = NULL;
132 /*** Encapsulated cleaning procedure of allocated things ***/
133 void free_diskio_alloc(void)
135 if(fr) FreeFileRequest(fr);
138 /*** Save width and height of an ASL requester ***/
139 void save_asl_dim(struct FileRequester *fr)
141 tags[5] = fr->fr_Width;
142 tags[7] = fr->fr_Height;
145 /*** Init the ASL tags table ***/
146 struct TagItem *init_tags(struct Window *wnd, ULONG flags)
148 /* Init LeftEdge */
149 tags[1] = wnd->LeftEdge + (wnd->Width-tags[5]) / 2;
150 /* TopEdge */
151 tags[3] = wnd->TopEdge + wnd->BorderTop;
152 /* Window, Screen, Flags */
153 tags[9] = (ULONG) wnd;
154 tags[11] = (ULONG) wnd->WScreen;
155 tags[13] = flags;
156 tags[21] = (IPTR) "#?";
157 return (struct TagItem *)tags;
160 /*** Popup a file requester to choose a save file ***/
161 STRPTR ask_save(struct Window *wnd, AskArgs *path, CONST_STRPTR title)
163 split_path(path, (STRPTR *)&tags[17], (STRPTR *)&tags[19]);
164 tags[23] = (ULONG)title;
166 /* If requester hasn't been allocated yet */
167 if(fr==NULL && !(fr = (void *)AllocAslRequest(ASL_FileRequest,NULL)))
168 ThrowError(Wnd, ErrMsg(ERR_NOASLREQ));
169 else
170 /* Display the file requester */
171 if(AslRequest(fr,init_tags(wnd, FRF_DOSAVEMODE | FRF_DOPATTERNS)))
173 STRPTR path;
174 save_asl_dim(fr);
175 /* User may choose strange path like "CPROG://docs/prog.c" **
176 ** get_full_path will search for the correct pathname */
177 if( ( path = CatPath(fr->fr_Drawer, fr->fr_File) ) )
179 STRPTR fullpath;
180 WORD err = get_full_path(path, &fullpath);
181 /* get_full_path, allocate a new buffer since size may varry */
182 FreeVec( path );
183 if( err == 0 ) return fullpath;
184 ThrowError(Wnd, ErrMsg(err));
185 } else
186 ThrowError(Wnd, ErrMsg(ERR_NOMEM));
188 return NULL;
191 /** Original FWrite has a too small buffer **/
192 static STRPTR buffer = NULL;
193 static ULONG usage = 0;
194 char myFWrite(BPTR file, STRPTR buf, ULONG size)
196 if(buffer == NULL && NULL == (buffer = (STRPTR) AllocVec(MEM_CHUNK, MEMF_PUBLIC)))
197 goto emergency;
199 if(size+usage > MEM_CHUNK) {
200 if( Write(file, buffer, usage) != usage ) return 0;
201 else usage = 0;
203 if(size > MEM_CHUNK)
204 emergency: return (char) (Write(file, buf, size) == size ? 1 : 0);
205 else
206 CopyMem(buf, buffer+usage, size), usage+=size;
207 return 1;
210 char myFClose( BPTR file )
212 char retcode = 1;
213 /* Flush buffer before closing */
214 if(buffer) {
215 /* Everything must be controlled */
216 if(usage > 0 && Write(file, buffer, usage) != usage)
217 retcode = 0;
218 FreeVec(buffer); buffer=NULL; usage=0;
220 Close(file);
221 return retcode;
224 /** Redirect functions **/
225 #ifdef FWrite
226 #undef FWrite
227 #endif
229 #define FWrite(x,y,z,t) myFWrite(x,y,z)
231 #ifdef FClose
232 #undef FClose
233 #endif
235 #define FClose(x) myFClose(x)
237 /*** Write the lines svg in the file `name', returns 1 if all's OK ***/
238 BYTE save_file(STRPTR name, LINE *svg, unsigned char eol, LONG protection)
240 STRPTR buf;
241 LONG i;
242 BYTE szeol = szEOL[eol];
243 LINE *ln; BPTR fh;
245 BusyWindow(Wnd);
247 if( ( fh = Open(name, MODE_NEWFILE) ) )
249 for(ln=svg, buf=NULL, i=0; ln; ln=ln->next)
251 if(i == 0) buf = ln->stream;
252 /* An unmodified line (2nd cond. is for deleted lines) */
253 if(ln->max == 0 && ln->stream-buf == i) i+=ln->size+szeol;
255 else {
256 /* Flush preceding unmodified buffer */
257 i -= szeol;
258 if( i>=0 && (FWrite(fh, buf, i, 1) != 1 ||
259 FWrite(fh, chEOL+eol, szeol, 1) != 1 ) )
261 wrterr: ThrowDOSError(Wnd, name);
262 i=0; break;
265 /* Writes the modified line */
266 if( FWrite(fh, ln->stream, ln->size, 1) != 1 || (ln->next != NULL &&
267 FWrite(fh, chEOL+eol, szeol, 1) != 1 ) )
268 goto wrterr;
269 i=0;
272 /* Flush buffer */
273 if( i>szeol && FWrite(fh,buf,i-szeol,1)!=1 ) goto wrterr;
274 FClose( fh );
276 } else if(IoErr() == ERROR_OBJECT_EXISTS)
277 ThrowError(Wnd, ErrMsg(ERR_WRONG_TYPE));
278 else
279 ThrowDOSError(Wnd, name);
281 SetProtection(name, protection);
282 WakeUp(Wnd);
283 return 1;
286 /*** Show a requester to choose a file to load ***/
287 STRPTR ask_load(struct Window *wnd, AskArgs *path, BYTE set_file, CONST_STRPTR title)
289 split_path(path, (STRPTR *)&tags[17], (STRPTR *)&tags[19]);
290 if(set_file == 0) tags[19] = 0;
291 tags[23] = (ULONG)title;
293 /* Alloc a file requester, if it hasn't been done yet */
294 if(fr==NULL && !(fr = (void *)AllocAslRequest(ASL_FileRequest,NULL)))
295 ThrowError(Wnd, ErrMsg(ERR_NOASLREQ));
296 else
297 /* Display the load requester */
298 if(AslRequest(fr, init_tags(wnd, (set_file ? FRF_DOPATTERNS : FRF_DOMULTISELECT|FRF_DOPATTERNS))))
300 STRPTR path;
301 save_asl_dim(fr);
302 /* This is actually a (StartUpArgs *) */
303 if( set_file == 0 ) return (STRPTR) &fr->fr_NumArgs;
305 if( ( path = CatPath(fr->fr_Drawer, fr->fr_File) ) )
307 STRPTR fullpath;
308 WORD err = get_full_path(path, &fullpath);
309 FreeVec( path );
310 if( err == 0 ) return fullpath;
311 ThrowError(Wnd, ErrMsg(err));
312 } else
313 ThrowError(Wnd, ErrMsg(ERR_NOMEM));
315 return NULL;
319 /*** Simple proc to read a file ***/
320 WORD read_file( LoadFileArgs *args, ULONG *len )
322 BPTR fh;
323 WORD err = RETURN_OK;
325 args->buffer = NULL;
326 args->lines = NULL;
327 args->protection = 0;
328 *len = 0;
330 if( ( fh = Open(args->filename, MODE_OLDFILE) ) )
332 /* First: Get file size */
333 struct FileInfoBlock *fib;
334 if( ( fib = (APTR) AllocDosObject( DOS_FIB, NULL ) ) )
336 if( ExamineFH(fh, fib) )
338 args->protection = fib->fib_Protection;
339 /* Then reads it in one large buffer */
340 if( (*len = fib->fib_Size) > 0 )
342 /* This is a critical call, with a high probability to fail ! */
343 if( ( args->buffer = (STRPTR) AllocVec(*len, MEMF_PUBLIC) ) )
345 if( Read(fh, args->buffer, *len) != *len )
346 err = ERR_LOADFILE;
348 else err = ERR_NOMEM;
350 /* This file is empty: we still need to allocate one line */
352 else err = ERR_LOADFILE;
353 FreeDosObject( DOS_FIB, fib );
355 else err = ERR_NOMEM;
357 Close( fh );
359 return err;
362 /*** load specified file from disk ***/
363 WORD load_file( LoadFileArgs *args )
365 ULONG len;
366 WORD err;
367 LINE * new;
369 BusyWindow(Wnd);
371 /* We have read the file in a buffer: create the lines */
372 if( RETURN_OK == (err = read_file( args, &len )) )
374 STRPTR p, q; char eol = '\n';
375 ULONG i;
377 args->eol = AMIGA_EOL;
378 /* Search in the very first line, the End Of Line type */
379 for(args->nblines=1, i=0, q=p=args->buffer;
380 i<len && *p!='\r' && *p!='\n'; p++, i++);
382 if( i < len && *p == '\r' )
383 args->eol = (p[1] == '\n' ? MSDOS_EOL : MACOS_EOL),
384 eol = '\r';
386 /* Build lines list */
387 if( ( args->lines = new = new_line(NULL) ) )
389 /* This loop is the most CPU consuming part */
390 for(; i<len; p++, i++)
391 if (*p == eol)
393 new->size = p-q; *p = '\n';
394 new->stream = q;
395 args->nblines++;
396 if(args->eol == MSDOS_EOL && p[1]=='\n') p++,i++; q = p+1;
397 if(NULL == (new = new_line(new))) {
398 err = ERR_NOMEM; break;
401 new->size = p-q;
402 new->stream = q;
403 } else err = ERR_NOMEM;
405 /* If there was errors: cleanup all things */
406 if( err != 0 && args->lines ) trash_file(args->lines);
408 WakeUp(Wnd);
409 return err;