revert between 56095 -> 55830 in arch
[AROS.git] / workbench / tools / Edit / DiskIO.c
blob9a31cad135d35cdc211a7c48f6681ed7b24cfc96
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 #define DEBUG 0
23 #include <aros/debug.h>
25 extern struct Library *AslBase;
27 extern struct Screen *Scr;
28 struct FileRequester *fr=NULL;
30 /* ASL load or save requester tags */
31 static IPTR tags[] = {
32 ASLFR_InitialLeftEdge, 0,
33 ASLFR_InitialTopEdge, 0,
34 ASLFR_InitialWidth, 320,
35 ASLFR_InitialHeight, 256,
36 ASLFR_Window, (IPTR) NULL,
37 ASLFR_Screen, (IPTR) NULL,
38 ASLFR_Flags1, 0,
39 ASLFR_SleepWindow, TRUE,
40 ASLFR_InitialDrawer, (IPTR) NULL,
41 ASLFR_InitialFile, (IPTR) NULL,
42 ASLFR_InitialPattern, (IPTR) NULL,
43 ASLFR_TitleText, (IPTR) NULL,
44 TAG_DONE
47 /*** Find the correctly spelled path ***/
48 BYTE get_full_path( STRPTR filename, STRPTR *dest )
50 STRPTR file = NULL, path;
51 BPTR lock;
52 WORD len;
54 len = sizeof(STR_MODIF) + 1;
55 lock = (BPTR) Lock(filename, SHARED_LOCK);
57 /* Can't get lock, surely because file does not exist */
58 if( lock == BNULL ) {
59 file = (STRPTR) FilePart(filename); len += strlen(file);
60 if(file != filename) {
61 char svg = *file; *file = 0;
62 lock = (BPTR) Lock(filename, SHARED_LOCK); *file = svg;
66 /* Be sure the locked object is of the desired type */
67 if(lock != BNULL)
69 struct FileInfoBlock *fib;
70 if((fib = (void *) AllocVec(sizeof(*fib), MEMF_PUBLIC)) && Examine(lock, fib))
72 /* That's particularly nasty, but prevent user of doing mistakes */
73 if(file == NULL ? fib->fib_EntryType > 0 : fib->fib_EntryType < 0)
74 /* Filename sucks, get a generic one */
75 UnLock(lock), lock = BNULL;
77 if( fib ) FreeVec( fib );
78 else { UnLock(lock); return ERR_NOMEM; }
79 /* User has given a directory as file to edit! */
80 if(file == NULL && lock == BNULL) return ERR_WRONG_TYPE;
83 /* The directory/file exists, Get its correctly spelled name */
84 for(len += 256; ;)
86 if( ( path = (STRPTR) AllocVec(len, MEMF_PUBLIC) ) ) {
87 /* If no directory provide, try to get the current wd */
88 if( lock ? NameFromLock(lock, path, len) :
89 GetCurrentDirName(path, len) )
91 /* At last if there was a file name, add it to the buffer */
92 if( file ) AddPart(path, file, len);
93 *dest = path;
94 break;
96 } else return ERR_NOMEM;
97 /* Fucking name! reallocate a longer buffer! */
98 FreeVec(path); len += 64;
100 if( lock ) UnLock(lock);
102 return 0;
105 /*** Extract path and file into 2 separate pointers (for ASL) ***/
106 void split_path(AskArgs *src, STRPTR *dir, STRPTR *file)
108 extern UBYTE BufTxt[256];
109 if( src->dir != NULL )
111 /* TODO cleanup */
112 UWORD Len = src->file - src->dir;
113 if(dir != NULL) {
114 if(Len >= sizeof(BufTxt)) Len = sizeof(BufTxt)-1;
115 CopyMem(src->dir, BufTxt, Len); BufTxt[Len] = '\0';
116 *dir = BufTxt;
117 } else Len = 0;
119 /* Copy file name */
120 *file = BufTxt+Len+1; Len = strlen( src->file );
121 CopyMem(src->file, *file, Len); (*file)[Len] = '\0';
123 else
125 *file = src->file;
126 if ( dir != NULL ) *dir = NULL;
130 /*** Encapsulated cleaning procedure of allocated things ***/
131 void free_diskio_alloc(void)
133 if(fr) FreeFileRequest(fr);
136 /*** Save width and height of an ASL requester ***/
137 void save_asl_dim(struct FileRequester *fr)
139 tags[5] = fr->fr_Width;
140 tags[7] = fr->fr_Height;
143 /*** Init the ASL tags table ***/
144 struct TagItem *init_tags(struct Window *wnd, ULONG flags)
146 /* Init LeftEdge */
147 tags[1] = wnd->LeftEdge + (wnd->Width-tags[5]) / 2;
148 /* TopEdge */
149 tags[3] = wnd->TopEdge + wnd->BorderTop;
150 /* Window, Screen, Flags */
151 tags[9] = (IPTR) wnd;
152 tags[11] = (IPTR) wnd->WScreen;
153 tags[13] = flags;
154 tags[21] = (IPTR) "#?";
155 return (struct TagItem *)tags;
158 /*** Popup a file requester to choose a save file ***/
159 STRPTR ask_save(struct Window *wnd, AskArgs *path, CONST_STRPTR title)
161 split_path(path, (STRPTR *)&tags[17], (STRPTR *)&tags[19]);
162 tags[23] = (IPTR)title;
164 /* If requester hasn't been allocated yet */
165 if(fr==NULL && !(fr = (void *)AllocAslRequest(ASL_FileRequest,NULL)))
166 ThrowError(Wnd, ErrMsg(ERR_NOASLREQ));
167 else
168 /* Display the file requester */
169 if(AslRequest(fr,init_tags(wnd, FRF_DOSAVEMODE | FRF_DOPATTERNS)))
171 STRPTR path;
172 save_asl_dim(fr);
173 /* User may choose strange path like "CPROG://docs/prog.c" **
174 ** get_full_path will search for the correct pathname */
175 if( ( path = CatPath(fr->fr_Drawer, fr->fr_File) ) )
177 STRPTR fullpath;
178 WORD err = get_full_path(path, &fullpath);
179 /* get_full_path, allocate a new buffer since size may vary */
180 FreeVec( path );
181 if( err == 0 ) return fullpath;
182 ThrowError(Wnd, ErrMsg(err));
183 } else
184 ThrowError(Wnd, ErrMsg(ERR_NOMEM));
186 return NULL;
189 /** Original FWrite has a too small buffer **/
190 static STRPTR buffer = NULL;
191 static ULONG usage = 0;
192 char myFWrite(BPTR file, CONST_STRPTR buf, ULONG size)
194 if(buffer == NULL && NULL == (buffer = (STRPTR) AllocVec(MEM_CHUNK, MEMF_PUBLIC)))
195 goto emergency;
197 if(size+usage > MEM_CHUNK) {
198 if( Write(file, buffer, usage) != usage ) return 0;
199 else usage = 0;
201 if(size > MEM_CHUNK)
202 emergency: return (char) (Write(file, buf, size) == size ? 1 : 0);
203 else
204 CopyMem(buf, buffer+usage, size), usage+=size;
205 return 1;
208 char myFClose( BPTR file )
210 char retcode = 1;
211 /* Flush buffer before closing */
212 if(buffer) {
213 /* Everything must be controlled */
214 if(usage > 0 && Write(file, buffer, usage) != usage)
215 retcode = 0;
216 FreeVec(buffer); buffer=NULL; usage=0;
218 Close(file);
219 return retcode;
222 /** Redirect functions **/
223 #ifdef FWrite
224 #undef FWrite
225 #endif
227 #define FWrite(x,y,z,t) myFWrite(x,y,z)
229 #ifdef FClose
230 #undef FClose
231 #endif
233 #define FClose(x) myFClose(x)
235 /*** Write the lines svg in the file `name', returns 1 if all's OK ***/
236 BYTE save_file(STRPTR name, LINE *svg, unsigned char eol, LONG protection)
238 STRPTR buf;
239 LONG i;
240 BYTE szeol = szEOL[eol];
241 LINE *ln; BPTR fh=BNULL;
242 BYTE retval = 0;
244 BusyWindow(Wnd);
246 if( ( fh = Open( name, MODE_OLDFILE) ) )
248 /* The file exists, Get protection flags */
249 struct FileInfoBlock *fib;
250 if( ( fib = (APTR) AllocDosObject( DOS_FIB, NULL ) ) )
252 if( ExamineFH(fh, fib) )
254 protection = fib->fib_Protection;
256 FreeDosObject( DOS_FIB, fib );
258 Close( fh );
261 fh = Open(name, MODE_NEWFILE);
263 if( fh )
265 for(ln=svg, buf=NULL, i=0; ln; ln=ln->next)
267 if(i == 0) buf = ln->stream;
268 /* An unmodified line (2nd cond. is for deleted lines) */
269 if(ln->max == 0 && ln->stream-buf == i) i+=ln->size+szeol;
271 else {
272 /* Flush preceding unmodified buffer */
273 i -= szeol;
274 if( i>=0 && (FWrite(fh, buf, i, 1) != 1 ||
275 FWrite(fh, chEOL+eol, szeol, 1) != 1 ) )
277 wrterr: ThrowDOSError(Wnd, name);
278 i=0; break;
281 /* Writes the modified line */
282 if( FWrite(fh, ln->stream, ln->size, 1) != 1 || (ln->next != NULL &&
283 FWrite(fh, chEOL+eol, szeol, 1) != 1 ) )
284 goto wrterr;
285 i=0;
288 /* Flush buffer */
289 if( i>szeol && FWrite(fh,buf,i-szeol,1)!=1 ) goto wrterr;
291 FClose( fh );
292 SetProtection(name, protection);
294 retval = 1;
296 } else if(IoErr() == ERROR_OBJECT_EXISTS)
297 ThrowError(Wnd, ErrMsg(ERR_WRONG_TYPE));
298 else
299 ThrowDOSError(Wnd, name);
301 WakeUp(Wnd);
302 return retval;
305 /*** Show a requester to choose a file to load ***/
306 STRPTR ask_load(struct Window *wnd, AskArgs *path, BYTE set_file, CONST_STRPTR title)
308 split_path(path, (STRPTR *)&tags[17], (STRPTR *)&tags[19]);
309 if(set_file == 0) tags[19] = 0;
310 tags[23] = (IPTR)title;
312 /* Alloc a file requester, if it hasn't been done yet */
313 if(fr==NULL && !(fr = (void *)AllocAslRequest(ASL_FileRequest,NULL)))
314 ThrowError(Wnd, ErrMsg(ERR_NOASLREQ));
315 else
316 /* Display the load requester */
317 if(AslRequest(fr, init_tags(wnd, (set_file ? FRF_DOPATTERNS : FRF_DOMULTISELECT|FRF_DOPATTERNS))))
319 STRPTR path;
321 save_asl_dim(fr);
323 /* This is actually a (StartUpArgs *) */
324 if( set_file == 0 ) return (STRPTR) fr;
326 if( ( path = CatPath(fr->fr_Drawer, fr->fr_File) ) )
328 STRPTR fullpath;
329 WORD err = get_full_path(path, &fullpath);
330 FreeVec( path );
331 if( err == 0 ) return fullpath;
332 ThrowError(Wnd, ErrMsg(err));
333 } else
334 ThrowError(Wnd, ErrMsg(ERR_NOMEM));
336 return NULL;
340 /*** Simple proc to read a file ***/
341 WORD read_file( LoadFileArgs *args, ULONG *len )
343 BPTR fh;
344 WORD err = RETURN_OK;
346 args->buffer = NULL;
347 args->lines = NULL;
348 args->protection = 0;
349 *len = 0;
351 if( ( fh = Open(args->filename, MODE_OLDFILE) ) )
353 /* First: Get file size */
354 struct FileInfoBlock *fib;
355 if( ( fib = (APTR) AllocDosObject( DOS_FIB, NULL ) ) )
357 if( ExamineFH(fh, fib) )
359 args->protection = fib->fib_Protection;
360 /* Then reads it in one large buffer */
361 if( (*len = fib->fib_Size) > 0 )
363 /* This is a critical call, with a high probability to fail ! */
364 if( ( args->buffer = (STRPTR) AllocVec(*len, MEMF_PUBLIC) ) )
366 if( Read(fh, args->buffer, *len) != *len )
367 err = ERR_LOADFILE;
369 else err = ERR_NOMEM;
371 /* This file is empty: we still need to allocate one line */
373 else err = ERR_LOADFILE;
374 FreeDosObject( DOS_FIB, fib );
376 else err = ERR_NOMEM;
378 Close( fh );
380 return err;
383 /*** load specified file from disk ***/
384 WORD load_file( LoadFileArgs *args )
386 ULONG len;
387 WORD err;
388 LINE * new;
390 BusyWindow(Wnd);
392 /* We have read the file in a buffer: create the lines */
393 if( RETURN_OK == (err = read_file( args, &len )) )
395 STRPTR p, q; char eol = '\n';
396 ULONG i;
398 args->eol = AMIGA_EOL;
399 /* Search in the very first line, the End Of Line type */
400 for(args->nblines=1, i=0, q=p=args->buffer;
401 i<len && *p!='\r' && *p!='\n'; p++, i++);
403 if( i < len && *p == '\r' )
404 args->eol = (p[1] == '\n' ? MSDOS_EOL : MACOS_EOL),
405 eol = '\r';
407 /* Build lines list */
408 if( ( args->lines = new = new_line(NULL) ) )
410 /* This loop is the most CPU consuming part */
411 for(; i<len; p++, i++)
412 if (*p == eol)
414 new->size = p-q;
415 /* *p = '\n'; Removed to preserve MS-DOS/Windows CRLF end-of-line chars */
416 new->stream = q;
417 args->nblines++;
418 if(args->eol == MSDOS_EOL && p[1]=='\n')
420 p++;
421 i++;
423 q = p+1;
424 if(NULL == (new = new_line(new))) {
425 err = ERR_NOMEM; break;
428 new->size = p-q;
429 new->stream = q;
430 } else err = ERR_NOMEM;
432 /* If there was errors: cleanup all things */
433 if( err != 0 && args->lines ) trash_file(args->lines);
435 WakeUp(Wnd);
436 return err;