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 */
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
,
36 ASLFR_SleepWindow
, TRUE
,
37 ASLFR_InitialDrawer
, (IPTR
) NULL
,
38 ASLFR_InitialFile
, (IPTR
) NULL
,
39 ASLFR_InitialPattern
, (IPTR
) NULL
,
40 ASLFR_TitleText
, (IPTR
) NULL
,
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
;
55 len
= sizeof(STR_MODIF
) + 1;
56 lock
= (BPTR
) Lock(filename
, SHARED_LOCK
);
58 /* Can't get lock, surely because file does not exist */
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 */
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 */
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
);
97 } else return ERR_NOMEM
;
98 /* Fucking name! reallocate a longer buffer! */
99 FreeVec(path
); len
+= 64;
101 if( lock
) UnLock(lock
);
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
)
113 UWORD Len
= src
->file
- src
->dir
;
115 if(Len
>= sizeof(BufTxt
)) Len
= sizeof(BufTxt
)-1;
116 CopyMem(src
->dir
, BufTxt
, Len
); BufTxt
[Len
] = '\0';
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';
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
)
149 tags
[1] = wnd
->LeftEdge
+ (wnd
->Width
-tags
[5]) / 2;
151 tags
[3] = wnd
->TopEdge
+ wnd
->BorderTop
;
152 /* Window, Screen, Flags */
153 tags
[9] = (ULONG
) wnd
;
154 tags
[11] = (ULONG
) wnd
->WScreen
;
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
));
170 /* Display the file requester */
171 if(AslRequest(fr
,init_tags(wnd
, FRF_DOSAVEMODE
| FRF_DOPATTERNS
)))
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
) ) )
180 WORD err
= get_full_path(path
, &fullpath
);
181 /* get_full_path, allocate a new buffer since size may varry */
183 if( err
== 0 ) return fullpath
;
184 ThrowError(Wnd
, ErrMsg(err
));
186 ThrowError(Wnd
, ErrMsg(ERR_NOMEM
));
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
)))
199 if(size
+usage
> MEM_CHUNK
) {
200 if( Write(file
, buffer
, usage
) != usage
) return 0;
204 emergency
: return (char) (Write(file
, buf
, size
) == size
? 1 : 0);
206 CopyMem(buf
, buffer
+usage
, size
), usage
+=size
;
210 char myFClose( BPTR file
)
213 /* Flush buffer before closing */
215 /* Everything must be controlled */
216 if(usage
> 0 && Write(file
, buffer
, usage
) != usage
)
218 FreeVec(buffer
); buffer
=NULL
; usage
=0;
224 /** Redirect functions **/
229 #define FWrite(x,y,z,t) myFWrite(x,y,z)
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
)
242 BYTE szeol
= szEOL
[eol
];
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
;
256 /* Flush preceding unmodified buffer */
258 if( i
>=0 && (FWrite(fh
, buf
, i
, 1) != 1 ||
259 FWrite(fh
, chEOL
+eol
, szeol
, 1) != 1 ) )
261 wrterr
: ThrowDOSError(Wnd
, name
);
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 ) )
273 if( i
>szeol
&& FWrite(fh
,buf
,i
-szeol
,1)!=1 ) goto wrterr
;
276 } else if(IoErr() == ERROR_OBJECT_EXISTS
)
277 ThrowError(Wnd
, ErrMsg(ERR_WRONG_TYPE
));
279 ThrowDOSError(Wnd
, name
);
281 SetProtection(name
, protection
);
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
));
297 /* Display the load requester */
298 if(AslRequest(fr
, init_tags(wnd
, (set_file
? FRF_DOPATTERNS
: FRF_DOMULTISELECT
|FRF_DOPATTERNS
))))
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
) ) )
308 WORD err
= get_full_path(path
, &fullpath
);
310 if( err
== 0 ) return fullpath
;
311 ThrowError(Wnd
, ErrMsg(err
));
313 ThrowError(Wnd
, ErrMsg(ERR_NOMEM
));
319 /*** Simple proc to read a file ***/
320 WORD
read_file( LoadFileArgs
*args
, ULONG
*len
)
323 WORD err
= RETURN_OK
;
327 args
->protection
= 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
)
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
;
362 /*** load specified file from disk ***/
363 WORD
load_file( LoadFileArgs
*args
)
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';
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
),
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
++)
393 new->size
= p
-q
; *p
= '\n';
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;
403 } else err
= ERR_NOMEM
;
405 /* If there was errors: cleanup all things */
406 if( err
!= 0 && args
->lines
) trash_file(args
->lines
);