1/*****
2 * runfile.in
3 *
4 * Runtime functions for file operations.
5 *
6 *****/
7
8file*    => primFile()
9
10#include "fileio.h"
11#include "callable.h"
12#include "triple.h"
13#include "array.h"
14
15#ifdef __CYGWIN__
16extern "C" int mkstemp(char *c);
17#endif
18
19using namespace camp;
20using namespace settings;
21using namespace vm;
22
23string commentchar="#";
24
25// Autogenerated routines:
26
27
28bool ==(file *a, file *b)
29{
30  return a == b;
31}
32
33bool !=(file *a, file *b)
34{
35  return a != b;
36}
37
38file* :nullFile()
39{
40  return &camp::nullfile;
41}
42
43file* input(string name=emptystring, bool check=true,
44            string comment=commentchar, string mode=emptystring)
45{
46  file *f=NULL;
47  if(mode == "binary") {
48    f=new ibfile(name,check);
49  } else if(mode == "xdr") {
50#ifdef HAVE_RPC_RPC_H
51    f=new ixfile(name,check);
52#else
53  ostringstream buf;
54  buf << name << ": XDR read support not enabled";
55  error(buf);
56#endif
57  } else if(mode == "") {
58    char c=comment.empty() ? (char) 0 : comment[0];
59    f=new ifile(name,c,check);
60  } else {
61    f=NULL;
62    ostringstream buf;
63    buf << name << ": invalid file mode '" << mode << "'";
64    error(buf);
65  }
66
67  f->open();
68  return f;
69}
70
71file* output(string name=emptystring, bool update=false,
72             string comment=commentchar, string mode=emptystring)
73{
74  file *f=NULL;
75  if(mode == "pipe") {
76    f=new opipe(name);
77  } else if(mode == "binary") {
78    if(update) f=new iobfile(name);
79    else f=new obfile(name);
80  } else if(mode == "xdr") {
81#ifdef HAVE_RPC_RPC_H
82    if(update)
83      f=new ioxfile(name);
84    else f=new oxfile(name);
85#else
86    ostringstream buf;
87    buf << name << ": XDR write support not enabled";
88    error(buf);
89#endif
90  } else if(mode == "") {
91    if(update) {
92      char c=comment.empty() ? (char) 0 : comment[0];
93      f=new iofile(name,c);
94    } else f=new ofile(name);
95  } else {
96    f=NULL;
97    ostringstream buf;
98    buf << name << ": invalid file mode '" << mode << "'";
99    error(buf);
100  }
101
102  f->open();
103  if(update) f->seek(0,false);
104
105  return f;
106}
107
108bool eof(file *f)
109{
110  return f->eof();
111}
112
113bool eol(file *f)
114{
115  return f->eol();
116}
117
118bool error(file *f)
119{
120  return f->error();
121}
122
123void clear(file *f)
124{
125  f->clear();
126}
127
128void close(file *f)
129{
130  f->close();
131}
132
133Int precision(file *f=NULL, Int digits=0)
134{
135  if(f == 0) f=&camp::Stdout;
136  return f->precision(digits);
137}
138
139void flush(file *f)
140{
141  f->flush();
142}
143
144string getc(file *f)
145{
146  char c=0;
147  if(f->isOpen()) f->read(c);
148  static char str[1];
149  str[0]=c;
150  return string(str);
151}
152
153Int tell(file *f)
154{
155  return f->tell();
156}
157
158void seek(file *f, Int pos)
159{
160  f->seek(pos,pos >= 0);
161}
162
163void seekeof(file *f)
164{
165  f->seek(0,false);
166}
167
168string :namePart(file f)
169{
170  return f.filename();
171}
172
173string :modePart(file f)
174{
175  return f.FileMode();
176}
177
178// Set file dimensions
179file* :dimensionSetHelper(Int nx=-1, Int ny=-1, Int nz=-1, file *f)
180{
181  f->dimension(nx,ny,nz);
182  return f;
183}
184
185callable* :dimensionSet(file *f)
186{
187  return new thunk(new bfunc(dimensionSetHelper),f);
188}
189
190array * :dimensionPart(file f)
191{
192  array *a=new array(3);
193  (*a)[0]=f.Nx();
194  (*a)[1]=f.Ny();
195  (*a)[2]=f.Nz();
196  return a;
197}
198
199// Set file f to read arrays in line-at-a-time mode
200file* :lineSetHelper(bool b=true, file *f)
201{
202  f->LineMode(b);
203  return f;
204}
205
206callable* :lineSet(file *f)
207{
208  return new thunk(new bfunc(lineSetHelper),f);
209}
210
211bool :linePart(file f)
212{
213  return f.LineMode();
214}
215
216// Set file to read comma-separated values
217file* :csvSetHelper(bool b=true, file *f)
218{
219  f->CSVMode(b);
220  return f;
221}
222
223callable* :csvSet(file *f)
224{
225  return new thunk(new bfunc(csvSetHelper),f);
226}
227
228bool :csvPart(file f)
229{
230  return f.CSVMode();
231}
232
233// Set file to read whitespace-separated values
234file* :wordSetHelper(bool b=true, file *f)
235{
236  f->WordMode(b);
237  return f;
238}
239
240callable* :wordSet(file *f)
241{
242  return new thunk(new bfunc(wordSetHelper),f);
243}
244
245bool :wordPart(file f)
246{
247  return f.WordMode();
248}
249
250// Set file to read/write single precision real XDR values.
251file* :singlerealSetHelper(bool b=true, file *f)
252{
253  f->SingleReal(b);
254  return f;
255}
256
257callable* :singlerealSet(file *f)
258{
259  return new thunk(new bfunc(singlerealSetHelper),f);
260}
261
262bool :singlerealPart(file f)
263{
264  return f.SingleReal();
265}
266
267// Set file to read/write single precision int XDR values.
268file* :singleintSetHelper(bool b=true, file *f)
269{
270  f->SingleInt(b);
271  return f;
272}
273
274callable* :singleintSet(file *f)
275{
276  return new thunk(new bfunc(singleintSetHelper),f);
277}
278
279bool :singleintPart(file f)
280{
281  return f.SingleInt();
282}
283
284// Set file to read/write signed int XDR values.
285file* :signedintSetHelper(bool b=true, file *f)
286{
287  f->SignedInt(b);
288  return f;
289}
290
291callable* :signedintSet(file *f)
292{
293  return new thunk(new bfunc(signedintSetHelper),f);
294}
295
296bool :signedintPart(file f)
297{
298  return f.SignedInt();
299}
300
301// Set file to read an arrayi (i int sizes followed by an i-dimensional array)
302file* :readSetHelper(Int i, file *f)
303{
304  switch(i) {
305    case 1:
306      f->dimension(-2);
307      break;
308
309    case 2:
310      f->dimension(-2,-2);
311      break;
312
313    case 3:
314      f->dimension(-2,-2,-2);
315      break;
316
317    default:
318      f->dimension();
319  }
320
321  return f;
322}
323
324callable* :readSet(file *f)
325{
326  return new thunk(new bfunc(readSetHelper),f);
327}
328
329// Delete file named s.
330Int delete(string s)
331{
332  s=outpath(s);
333  Int rc=unlink(s.c_str());
334  if(rc == 0 && verbose > 0)
335    cout << "Deleted " << s << endl;
336  return rc;
337}
338
339// Rename file "from" to file "to".
340Int rename(string from, string to)
341{
342  from=outpath(from);
343  to=outpath(to);
344  Int rc=rename(from.c_str(),to.c_str());
345  if(rc == 0 && verbose > 0)
346    cout << "Renamed " << from << " to " << to << endl;
347  return rc;
348}
349
350// Create a unique temporary file name.
351string mktemp(string s)
352{
353  char *S=Strdup(s+"XXXXXX");
354  int fd=mkstemp(S);
355  if(fd < 0) {
356    ostringstream buf;
357    buf << "Could not create unique temporary filename based on " << s;
358    error(buf);
359  }
360  return S;
361}
362