Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / tools / Edit / DiskIO.c
bloba82096a14ff33fc1e633fd7d1e51055eb0b97503
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 CopyMem(src->file, *file, Len); (*file)[Len] = '\0';
124 else
126 *file = src->file;
127 if ( dir != NULL ) *dir = NULL;
131 /*** Encapsulated cleaning procedure of allocated things ***/
132 void free_diskio_alloc(void)
134 if(fr) FreeFileRequest(fr);
137 /*** Save width and height of an ASL requester ***/
138 void save_asl_dim(struct FileRequester *fr)
140 tags[5] = fr->fr_Width;
141 tags[7] = fr->fr_Height;
144 /*** Init the ASL tags table ***/
145 struct TagItem *init_tags(struct Window *wnd, ULONG flags)
147 /* Init LeftEdge */
148 tags[1] = wnd->LeftEdge + (wnd->Width-tags[5]) / 2;
149 /* TopEdge */
150 tags[3] = wnd->TopEdge + wnd->BorderTop;
151 /* Window, Screen, Flags */
152 tags[9] = (ULONG) wnd;
153 tags[11] = (ULONG) wnd->WScreen;
154 tags[13] = flags;
155 tags[21] = (IPTR) "#?";
156 return (struct TagItem *)tags;
159 /*** Popup a file requester to choose a save file ***/
160 STRPTR ask_save(struct Window *wnd, AskArgs *path, CONST_STRPTR title)
162 split_path(path, (STRPTR *)&tags[17], (STRPTR *)&tags[19]);
163 tags[23] = (ULONG)title;
165 /* If requester hasn't been allocated yet */
166 if(fr==NULL && !(fr = (void *)AllocAslRequest(ASL_FileRequest,NULL)))
167 ThrowError(Wnd, ErrMsg(ERR_NOASLREQ));
168 else
169 /* Display the file requester */
170 if(AslRequest(fr,init_tags(wnd, FRF_DOSAVEMODE | FRF_DOPATTERNS)))
172 STRPTR path;
173 save_asl_dim(fr);
174 /* User may choose strange path like "CPROG://docs/prog.c" **
175 ** get_full_path will search for the correct pathname */
176 if( ( path = CatPath(fr->fr_Drawer, fr->fr_File) ) )
178 STRPTR fullpath;
179 WORD err = get_full_path(path, &fullpath);
180 /* get_full_path, allocate a new buffer since size may vary */
181 FreeVec( path );
182 if( err == 0 ) return fullpath;
183 ThrowError(Wnd, ErrMsg(err));
184 } else
185 ThrowError(Wnd, ErrMsg(ERR_NOMEM));
187 return NULL;
190 /** Original FWrite has a too small buffer **/
191 static STRPTR buffer = NULL;
192 static ULONG usage = 0;
193 char myFWrite(BPTR file, STRPTR buf, ULONG size)
195 if(buffer == NULL && NULL == (buffer = (STRPTR) AllocVec(MEM_CHUNK, MEMF_PUBLIC)))
196 goto emergency;
198 if(size+usage > MEM_CHUNK) {
199 if( Write(file, buffer, usage) != usage ) return 0;
200 else usage = 0;
202 if(size > MEM_CHUNK)
203 emergency: return (char) (Write(file, buf, size) == size ? 1 : 0);
204 else
205 CopyMem(buf, buffer+usage, size), usage+=size;
206 return 1;
209 char myFClose( BPTR file )
211 char retcode = 1;
212 /* Flush buffer before closing */
213 if(buffer) {
214 /* Everything must be controlled */
215 if(usage > 0 && Write(file, buffer, usage) != usage)
216 retcode = 0;
217 FreeVec(buffer); buffer=NULL; usage=0;
219 Close(file);
220 return retcode;
223 /** Redirect functions **/
224 #ifdef FWrite
225 #undef FWrite
226 #endif
228 #define FWrite(x,y,z,t) myFWrite(x,y,z)
230 #ifdef FClose
231 #undef FClose
232 #endif
234 #define FClose(x) myFClose(x)
236 /*** Write the lines svg in the file `name', returns 1 if all's OK ***/
237 BYTE save_file(STRPTR name, LINE *svg, unsigned char eol, LONG protection)
239 STRPTR buf;
240 LONG i;
241 BYTE szeol = szEOL[eol];
242 LINE *ln; BPTR fh;
243 BYTE retval = 0;
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 );
275 retval = 1;
277 } else if(IoErr() == ERROR_OBJECT_EXISTS)
278 ThrowError(Wnd, ErrMsg(ERR_WRONG_TYPE));
279 else
280 ThrowDOSError(Wnd, name);
282 SetProtection(name, protection);
283 WakeUp(Wnd);
284 return retval;
287 /*** Show a requester to choose a file to load ***/
288 STRPTR ask_load(struct Window *wnd, AskArgs *path, BYTE set_file, CONST_STRPTR title)
290 split_path(path, (STRPTR *)&tags[17], (STRPTR *)&tags[19]);
291 if(set_file == 0) tags[19] = 0;
292 tags[23] = (ULONG)title;
294 /* Alloc a file requester, if it hasn't been done yet */
295 if(fr==NULL && !(fr = (void *)AllocAslRequest(ASL_FileRequest,NULL)))
296 ThrowError(Wnd, ErrMsg(ERR_NOASLREQ));
297 else
298 /* Display the load requester */
299 if(AslRequest(fr, init_tags(wnd, (set_file ? FRF_DOPATTERNS : FRF_DOMULTISELECT|FRF_DOPATTERNS))))
301 STRPTR path;
302 save_asl_dim(fr);
303 /* This is actually a (StartUpArgs *) */
304 if( set_file == 0 ) return (STRPTR) &fr->fr_NumArgs;
306 if( ( path = CatPath(fr->fr_Drawer, fr->fr_File) ) )
308 STRPTR fullpath;
309 WORD err = get_full_path(path, &fullpath);
310 FreeVec( path );
311 if( err == 0 ) return fullpath;
312 ThrowError(Wnd, ErrMsg(err));
313 } else
314 ThrowError(Wnd, ErrMsg(ERR_NOMEM));
316 return NULL;
320 /*** Simple proc to read a file ***/
321 WORD read_file( LoadFileArgs *args, ULONG *len )
323 BPTR fh;
324 WORD err = RETURN_OK;
326 args->buffer = NULL;
327 args->lines = NULL;
328 args->protection = 0;
329 *len = 0;
331 if( ( fh = Open(args->filename, MODE_OLDFILE) ) )
333 /* First: Get file size */
334 struct FileInfoBlock *fib;
335 if( ( fib = (APTR) AllocDosObject( DOS_FIB, NULL ) ) )
337 if( ExamineFH(fh, fib) )
339 args->protection = fib->fib_Protection;
340 /* Then reads it in one large buffer */
341 if( (*len = fib->fib_Size) > 0 )
343 /* This is a critical call, with a high probability to fail ! */
344 if( ( args->buffer = (STRPTR) AllocVec(*len, MEMF_PUBLIC) ) )
346 if( Read(fh, args->buffer, *len) != *len )
347 err = ERR_LOADFILE;
349 else err = ERR_NOMEM;
351 /* This file is empty: we still need to allocate one line */
353 else err = ERR_LOADFILE;
354 FreeDosObject( DOS_FIB, fib );
356 else err = ERR_NOMEM;
358 Close( fh );
360 return err;
363 /*** load specified file from disk ***/
364 WORD load_file( LoadFileArgs *args )
366 ULONG len;
367 WORD err;
368 LINE * new;
370 BusyWindow(Wnd);
372 /* We have read the file in a buffer: create the lines */
373 if( RETURN_OK == (err = read_file( args, &len )) )
375 STRPTR p, q; char eol = '\n';
376 ULONG i;
378 args->eol = AMIGA_EOL;
379 /* Search in the very first line, the End Of Line type */
380 for(args->nblines=1, i=0, q=p=args->buffer;
381 i<len && *p!='\r' && *p!='\n'; p++, i++);
383 if( i < len && *p == '\r' )
384 args->eol = (p[1] == '\n' ? MSDOS_EOL : MACOS_EOL),
385 eol = '\r';
387 /* Build lines list */
388 if( ( args->lines = new = new_line(NULL) ) )
390 /* This loop is the most CPU consuming part */
391 for(; i<len; p++, i++)
392 if (*p == eol)
394 new->size = p-q; *p = '\n';
395 new->stream = q;
396 args->nblines++;
397 if(args->eol == MSDOS_EOL && p[1]=='\n') p++,i++; q = p+1;
398 if(NULL == (new = new_line(new))) {
399 err = ERR_NOMEM; break;
402 new->size = p-q;
403 new->stream = q;
404 } else err = ERR_NOMEM;
406 /* If there was errors: cleanup all things */
407 if( err != 0 && args->lines ) trash_file(args->lines);
409 WakeUp(Wnd);
410 return err;