source: golgotha/src/i4/file/file.cc @ 80

Last change on this file since 80 was 80, checked in by Sam Hocevar, 12 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 10.5 KB
Line 
1/********************************************************************** <BR>
2  This file is part of Crack dot Com's free source code release of
3  Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
4  information about compiling & licensing issues visit this URL</a>
5  <PRE> If that doesn't help, contact Jonathan Clark at
6  golgotha_source@usa.net (Subject should have "GOLG" in it)
7***********************************************************************/
8
9//{{{ File & File Manager Classes
10//
11//$Id: file.cc,v 1.48 1998/07/15 21:16:39 jc Exp $
12
13#include "file/file.hh"
14#include "memory/malloc.hh"
15#include "error/error.hh"
16#include "time/profile.hh"
17#include "error/error.hh"
18#include "file/file_man.hh"
19#include "string/string.hh"
20
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <stdarg.h>
25
26
27static i4_profile_class pf_tell("File tell");
28static i4_profile_class pf_open("File Open");
29static i4_profile_class pf_sopen("System file Open");
30static i4_profile_class pf_close("File Close");
31static i4_profile_class pf_read("File Read");
32static i4_profile_class pf_con_buf("::buffered file");
33
34
35i4_bool i4_file_class::async_write(const void *buffer, w32 size,
36                                   async_callback call,
37                                   void *context)
38{
39  (*call)(write(buffer, size), context);
40
41  return i4_T;
42}
43
44
45i4_bool i4_file_class::async_read (void *buffer, w32 size,
46                                   async_callback call,
47                                   void *context)
48{
49  (*call)(read(buffer, size), context);
50  return i4_T;
51}
52
53
54class file_string : public i4_str
55{
56public:
57  file_string(w16 size) : i4_str(size) {}
58
59  char *buffer() { return (char *)ptr; }
60  void set_len(w16 _len) { len = _len; }
61};
62
63
64i4_str* i4_file_class::read_str(w32 len)
65{
66  file_string *str = new file_string((w16)len);   
67  len = read(str->buffer(),len);
68  str->set_len((w16)len);
69
70  return str;
71}
72
73i4_str* i4_file_class::read_counted_str()
74{
75  w16 len = read_16();
76  return read_str(len);
77}
78
79
80class file_write_string : public i4_const_str
81{
82public:
83  char *buffer() { return (char *)ptr; }
84};
85
86
87w32 i4_file_class::write_str(const i4_const_str &str)
88{
89  file_write_string *s = (file_write_string *)&str;
90
91  return write(s->buffer(), s->length());
92}
93
94w32 i4_file_class::write_counted_str(const i4_const_str &str)
95{
96  w32 count;
97
98  count = write_16((w16)str.length());
99  if (str.length())     
100    return (count + write_str(str));
101  else
102    return count;
103}
104
105
106
107static inline int fmt_char(char c)
108{
109  if ((c>='a' && c<='z') || (c>='A' && c<='Z'))
110    return 1;
111  return 0;
112}
113
114// same as fprintf, but with the addition %S is a i4_const_str *
115int i4_file_class::printf(char *fmt, ...)
116{
117  w32 start=tell();
118
119  va_list ap;
120  va_start(ap, fmt);
121
122  while (*fmt)
123  {
124    if (*fmt=='%')
125    {
126      char *fmt_end=fmt;
127      while (!fmt_char(*fmt_end) && *fmt_end) fmt_end++;
128      char f[10], out[500];
129      memcpy(f, fmt, fmt_end-fmt+1);
130      f[fmt_end-fmt+1]=0;
131      out[0]=0;
132
133      switch (*fmt_end)
134      {
135        case 's' :
136        {
137          char *str=va_arg(ap,char *);
138          write(str,strlen(str));
139        } break;         
140        case 'S' :
141        {
142          i4_const_str *s=va_arg(ap,i4_const_str *);
143          write_str(*s);
144        } break;
145        case 'd' :
146        case 'i' :
147        case 'x' :
148        case 'X' :
149        case 'c' :
150        case 'o' :
151        {
152          ::sprintf(out,f,va_arg(ap,int));
153          write(out,strlen(out));
154        } break;
155
156        case 'f' :
157        case 'g' :
158          ::sprintf(out,f,va_arg(ap,double));
159          write(out,strlen(out));
160          break;
161
162        default :
163          ::sprintf(out,f,va_arg(ap,void *));
164          write(out,strlen(out));
165          break;
166      }
167      fmt=fmt_end;
168      if (*fmt)
169        fmt++;
170    }
171    else
172    {
173      write_8(*fmt);
174      fmt++;
175    }
176  }
177  va_end(ap);
178
179  return tell()-start;
180}
181
182
183
184
185int i4_file_class::write_format(char *format, ...)
186{
187  char *f=format;
188  va_list ap;
189  va_start(ap, format);
190
191  int start=tell();
192  while (*f)
193  {
194    switch (*f)
195    {
196      case '1' : write_8(*(va_arg(ap,     w8 *))); break;
197      case '2' : write_16(*(va_arg(ap,    w16 *))); break;
198      case '4' : write_32(*(va_arg(ap,     w32 *))); break;
199      case 'f' : write_float(*(va_arg(ap,  float *))); break;
200      case 'S' : write_counted_str(  *(va_arg(ap, i4_const_str *))); break;
201    }
202    f++;
203  }
204  va_end(ap);
205
206  return tell()-start;
207}
208
209
210// format is same as write_format, returns number of fields written
211int i4_file_class::read_format(char *format, ...)
212{
213  char *f=format;
214  va_list ap;
215  va_start(ap, format);
216
217  int start=tell();
218  while (*f)
219  {
220    switch (*f)
221    {
222      case '1' : *(va_arg(ap,   w8 *))=read_8(); break;
223      case '2' : *(va_arg(ap,  w16 *))=read_16(); break;
224      case '4' : *(va_arg(ap,  w32 *))=read_32(); break;
225      case 'f' : *(va_arg(ap, float*))=read_float(); break;
226      case 'S' : *(va_arg(ap, i4_str **))=read_counted_str(); break;
227    }
228    f++;
229  }
230  va_end(ap);
231
232  return tell()-start;
233}
234
235
236// returns NULL if unable to open file
237i4_file_class *i4_open(const i4_const_str &name, w32 flags)
238{
239  for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
240  {   
241    i4_file_class *fp=m->open(name,flags);
242    if (fp)
243      return fp;
244  }
245
246  return 0;
247}
248
249// return i4_F on failure
250i4_bool i4_unlink(const i4_const_str &name)
251{
252  for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
253    if (m->unlink(name))
254      return i4_T;
255  return i4_F;
256}
257
258
259// returns i4_F if file does not exsist
260i4_bool i4_get_status(const i4_const_str &filename,
261                      i4_file_status_struct &return_stat)
262{
263  for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
264    if (m->get_status(filename, return_stat))
265      return i4_T;
266
267  return i4_F;
268}
269
270// return i4_F on failure
271i4_bool i4_mkdir(const i4_const_str &name)
272{
273  for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
274    if (m->mkdir(name))
275      return i4_T;
276
277  return i4_F;
278}
279
280// returns i4_F if path is bad (tfiles and tdirs will be 0 as well)
281// you are responsible for deleting both the array of strings and each string in the array
282// file_status is a pointer to an array of file_status's that will be created, you
283// must free these as well.  file_status may be 0 (default), in which case no array is created
284
285i4_bool i4_get_directory(const i4_const_str &path,
286                         i4_directory_struct &dir_struct,
287                         i4_bool get_status,
288                         i4_status_class *status)
289{
290  for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
291    if (m->get_directory(path, dir_struct, get_status, status))
292      return i4_T;
293
294  return i4_F;
295}
296
297// returns i4_F if path cannot be split
298i4_bool i4_split_path(const i4_const_str &name, i4_filename_struct &fname_struct)
299{
300  for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
301    if (m->split_path(name, fname_struct))
302      return i4_T;
303
304  return i4_F;
305}
306
307// return 0 if full path cannot be determined
308i4_str *i4_full_path(const i4_const_str &relative_name)
309{
310  for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
311  {
312    i4_str *s=m->full_path(relative_name);
313    if (s)
314        return s;
315  }
316
317  return 0;
318}
319
320
321i4_file_manager_class *i4_file_manager_class::first=0;
322
323void i4_add_file_manager(i4_file_manager_class *fman, i4_bool add_front)
324{
325  if (add_front)
326  {
327    fman->next=i4_file_manager_class::first;
328    i4_file_manager_class::first=fman;
329  }
330  else
331  {
332    i4_file_manager_class *last=0, *p=i4_file_manager_class::first;
333    while (p)
334    {
335      last=p;
336      p=p->next;
337    }
338
339    if (!last)
340      i4_add_file_manager(fman, i4_T);
341    else
342    {
343      last->next=fman;
344      fman->next=0;
345    }
346  }
347}
348
349void i4_remove_file_manger(i4_file_manager_class *fman)
350{
351  i4_file_manager_class *last=0, *p=i4_file_manager_class::first;
352  while (p && p!=fman)
353  {
354    last=p;
355    p=p->next;
356  }
357
358  if (p!=fman)
359    i4_error("unable to find file manager");
360  else if (last)
361    last->next=fman->next;
362  else
363    i4_file_manager_class::first=fman->next;   
364}
365
366
367
368
369i4_bool i4_file_manager_class::split_path(const i4_const_str &name, i4_filename_struct &fn)
370{
371  char buf[512];
372  i4_os_string(name, buf, 512);
373
374
375  char *p=buf, *last_slash=0, *last_dot=0, *q;
376
377  while (*p)
378  {
379    if (*p=='/' || *p=='\\')
380      last_slash=p;
381    else if (*p=='.')
382      last_dot=p;
383    p++;
384  }
385
386 
387  if (last_dot)
388  {
389    q=fn.extension;   
390    for (p=last_dot+1; *p; )
391      *(q++)=*(p++);
392    *q=0;
393  }
394  else last_dot=p;
395     
396 
397  if (last_slash)
398  {
399    q=fn.path;
400    for (p=buf; p!=last_slash; )
401      *(q++)=*(p++);
402    *q=0;
403    last_slash++;
404  }
405  else last_slash=buf;
406
407
408  q=fn.filename;
409  for (p=last_slash; p!=last_dot;)
410    *(q++)=*(p++);
411  *q=0;
412
413
414  return i4_T;
415}
416
417
418
419i4_directory_struct::~i4_directory_struct()
420{
421  int i;
422
423  for (i=0; i<tfiles; i++)
424    delete files[i];
425
426  if (files)
427    i4_free(files);
428
429  for (i=0; i<tdirs; i++)
430    delete dirs[i];
431
432  if (dirs)
433    i4_free(dirs);
434
435
436  if (file_status)
437    i4_free(file_status);
438
439}
440
441
442
443static char convert_slash(char c)
444{
445  if (c=='\\') return '/';
446  else return c;
447}
448
449i4_str *i4_relative_path(const i4_const_str &path)
450{
451  i4_str *full_path=i4_full_path(path);
452  i4_str *full_current=i4_full_path(i4_const_str("."));
453 
454  char full[512], current[512], ret[512];
455
456  i4_os_string(*full_path, full, 512);
457  i4_os_string(*full_current, current, 512);
458
459  delete full_path;
460  delete full_current;
461
462
463  // files are on different drives 
464  if (full[1]==':' && current[1]==':' && full[0]!=current[0])
465    return new i4_str(full);
466
467  // one files is on a network drive and one is local
468  if ((full[1]==':' && current[1]!=':') ||
469      (full[1]!=':' && current[1]==':'))
470    return new i4_str(full);
471
472
473  int start=0;
474  while (convert_slash(full[start])==convert_slash(current[start]))
475    start++;
476
477
478  char *c=current+start;
479  if (*c==0)
480    return new i4_str(full+start+1);
481
482  strcpy(ret,"../");
483  while (*c)
484  {
485    if (convert_slash(*c)=='/')
486      strcpy(ret+strlen(ret),"../");
487
488    c++;
489  }
490
491  strcpy(ret+strlen(ret), full+start);
492  return new i4_str(ret);
493}
Note: See TracBrowser for help on using the repository browser.