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>
15 #include "ProtoTypes.h"
17 #define CATCOMP_NUMBERS /* Error msg use strings id */
20 #define MEM_CHUNK 8192 /* To save file */
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
,
39 ASLFR_SleepWindow
, TRUE
,
40 ASLFR_InitialDrawer
, (IPTR
) NULL
,
41 ASLFR_InitialFile
, (IPTR
) NULL
,
42 ASLFR_InitialPattern
, (IPTR
) NULL
,
43 ASLFR_TitleText
, (IPTR
) NULL
,
47 /*** Find the correctly spelled path ***/
48 BYTE
get_full_path( STRPTR filename
, STRPTR
*dest
)
50 STRPTR file
= NULL
, path
;
54 len
= sizeof(STR_MODIF
) + 1;
55 lock
= (BPTR
) Lock(filename
, SHARED_LOCK
);
57 /* Can't get lock, surely because file does not exist */
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 */
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 */
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
);
96 } else return ERR_NOMEM
;
97 /* Fucking name! reallocate a longer buffer! */
98 FreeVec(path
); len
+= 64;
100 if( lock
) UnLock(lock
);
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
)
112 UWORD Len
= src
->file
- src
->dir
;
114 if(Len
>= sizeof(BufTxt
)) Len
= sizeof(BufTxt
)-1;
115 CopyMem(src
->dir
, BufTxt
, Len
); BufTxt
[Len
] = '\0';
120 *file
= BufTxt
+Len
+1; Len
= strlen( src
->file
);
121 CopyMem(src
->file
, *file
, Len
); (*file
)[Len
] = '\0';
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
)
147 tags
[1] = wnd
->LeftEdge
+ (wnd
->Width
-tags
[5]) / 2;
149 tags
[3] = wnd
->TopEdge
+ wnd
->BorderTop
;
150 /* Window, Screen, Flags */
151 tags
[9] = (IPTR
) wnd
;
152 tags
[11] = (IPTR
) wnd
->WScreen
;
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
));
168 /* Display the file requester */
169 if(AslRequest(fr
,init_tags(wnd
, FRF_DOSAVEMODE
| FRF_DOPATTERNS
)))
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
) ) )
178 WORD err
= get_full_path(path
, &fullpath
);
179 /* get_full_path, allocate a new buffer since size may vary */
181 if( err
== 0 ) return fullpath
;
182 ThrowError(Wnd
, ErrMsg(err
));
184 ThrowError(Wnd
, ErrMsg(ERR_NOMEM
));
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
)))
197 if(size
+usage
> MEM_CHUNK
) {
198 if( Write(file
, buffer
, usage
) != usage
) return 0;
202 emergency
: return (char) (Write(file
, buf
, size
) == size
? 1 : 0);
204 CopyMem(buf
, buffer
+usage
, size
), usage
+=size
;
208 char myFClose( BPTR file
)
211 /* Flush buffer before closing */
213 /* Everything must be controlled */
214 if(usage
> 0 && Write(file
, buffer
, usage
) != usage
)
216 FreeVec(buffer
); buffer
=NULL
; usage
=0;
222 /** Redirect functions **/
227 #define FWrite(x,y,z,t) myFWrite(x,y,z)
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
)
240 BYTE szeol
= szEOL
[eol
];
241 LINE
*ln
; BPTR fh
=BNULL
;
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
);
261 fh
= Open(name
, MODE_NEWFILE
);
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
;
272 /* Flush preceding unmodified buffer */
274 if( i
>=0 && (FWrite(fh
, buf
, i
, 1) != 1 ||
275 FWrite(fh
, chEOL
+eol
, szeol
, 1) != 1 ) )
277 wrterr
: ThrowDOSError(Wnd
, name
);
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 ) )
289 if( i
>szeol
&& FWrite(fh
,buf
,i
-szeol
,1)!=1 ) goto wrterr
;
292 SetProtection(name
, protection
);
296 } else if(IoErr() == ERROR_OBJECT_EXISTS
)
297 ThrowError(Wnd
, ErrMsg(ERR_WRONG_TYPE
));
299 ThrowDOSError(Wnd
, name
);
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
));
316 /* Display the load requester */
317 if(AslRequest(fr
, init_tags(wnd
, (set_file
? FRF_DOPATTERNS
: FRF_DOMULTISELECT
|FRF_DOPATTERNS
))))
323 /* This is actually a (StartUpArgs *) */
324 if( set_file
== 0 ) return (STRPTR
) fr
;
326 if( ( path
= CatPath(fr
->fr_Drawer
, fr
->fr_File
) ) )
329 WORD err
= get_full_path(path
, &fullpath
);
331 if( err
== 0 ) return fullpath
;
332 ThrowError(Wnd
, ErrMsg(err
));
334 ThrowError(Wnd
, ErrMsg(ERR_NOMEM
));
340 /*** Simple proc to read a file ***/
341 WORD
read_file( LoadFileArgs
*args
, ULONG
*len
)
344 WORD err
= RETURN_OK
;
348 args
->protection
= 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
)
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
;
383 /*** load specified file from disk ***/
384 WORD
load_file( LoadFileArgs
*args
)
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';
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
),
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
++)
415 /* *p = '\n'; Removed to preserve MS-DOS/Windows CRLF end-of-line chars */
418 if(args
->eol
== MSDOS_EOL
&& p
[1]=='\n')
424 if(NULL
== (new = new_line(new))) {
425 err
= ERR_NOMEM
; break;
430 } else err
= ERR_NOMEM
;
432 /* If there was errors: cleanup all things */
433 if( err
!= 0 && args
->lines
) trash_file(args
->lines
);