File: crm_expr_file_io.c

package info (click to toggle)
crm114 20100106-10
  • links: PTS
  • area: main
  • in suites: bookworm, bullseye, sid, trixie
  • size: 3,184 kB
  • sloc: ansic: 34,910; sh: 617; makefile: 578; lisp: 208
file content (367 lines) | stat: -rw-r--r-- 9,861 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
//	crm_file_io.c - file I/O routines

// Copyright 2001-2009 William S. Yerazunis.
// This file is under GPLv3, as described in COPYING.

//  include some standard files
#include "crm114_sysincludes.h"

//  include any local crm114 configuration file
#include "crm114_config.h"

//  include the crm114 data structures file
#include "crm114_structs.h"

//  and include the routine declarations file
#include "crm114.h"

//  required for READLINE - only this source file uses it
//  it may not be portable
//#include <readline/readline.h>
//#include <readline/history.h>

//    the globals used when we need a big buffer  - allocated once, used
//    wherever needed.  These are sized to the same size as the data window.
extern char *inbuf;
extern char *outbuf;

int crm_expr_input ( CSL_CELL *csl, ARGPARSE_BLOCK *apb )
{
  //           Allow input of text from stdin.
  FILE *fp;
  char temp_vars [MAX_PATTERN];
  long tvlen;
  char filename [MAX_FILE_NAME_LEN];
  long fnlen;
  char ifn [MAX_FILE_NAME_LEN];
  char fileoffset [MAX_FILE_NAME_LEN];
  long fileoffsetlen;
  char fileiolen [MAX_FILE_NAME_LEN];
  long fileiolenlen;
  long offset, iolen;
  long vstart;
  long vlen;
  long mc;
  long done;
  long till_eof;
  long use_readline;

  //         a couple of vars to bash upon
  long i, j;

  if (user_trace)
    fprintf (stderr, "executing an INPUT statement\n");

  //    set up the flags (if any)
  //
  till_eof = 1;
  if (apb->sflags & CRM_BYLINE)
    {
      till_eof = 0;
      if (user_trace)
	fprintf (stderr, " reading one line mode\n ");
    };

  use_readline = 0;
  if (apb->sflags & CRM_READLINE)
    {
      use_readline = 1;
      if (user_trace)
	fprintf (stderr, " Using READLINE input line editing\n ");
    };

  //    get the list of variable names
  //
  crm_get_pgm_arg (temp_vars, MAX_PATTERN, apb->p1start, apb->p1len);
  tvlen = crm_nexpandvar (temp_vars, apb->p1len,  MAX_PATTERN);

  //     If you think INPUT should read to the data window, uncomment this.
  //
  if (tvlen == 0)
    {
      strcpy (temp_vars, ":_dw:");
      tvlen = strlen (":_dw:");
    };

  if (internal_trace)
    fprintf (stderr, "  inputting to var: >>>%s<<<\n", temp_vars);

  //   and what file to get it from...
  //
  crm_get_pgm_arg (filename, MAX_FILE_NAME_LEN, apb->b1start,apb->b1len);
  crm_nextword (filename, apb->b1len, 0, &i, &j);
  memmove (ifn, &filename[i], j);
  fnlen = crm_nexpandvar (ifn, j, MAX_FILE_NAME_LEN);
  ifn[fnlen] = '\0';
  if (user_trace)
    fprintf (stderr, "  from filename >>>%s<<<\n", ifn);

  //   and what offset we need to do before the I/O...
  //
  offset = 0;
  crm_nextword (filename, apb->b1len, i+j, &i, &j);
  memmove (fileoffset, &filename[i], j);
  fileoffsetlen = crm_qexpandvar (fileoffset, j, MAX_FILE_NAME_LEN, NULL);
  fileoffset [fileoffsetlen] = '\0';
  sscanf (fileoffset, "%ld", &offset);
  if (user_trace)
    fprintf (stderr, "  pre-IO seek to >>>%s<<< --> %ld \n",
	     fileoffset, offset);

  //   and how many bytes to read
  //
  iolen = 0;
  crm_nextword (filename, apb->b1len, i+j, &i, &j);
  memmove (fileiolen, &filename[i], j);
  fileiolenlen = crm_qexpandvar (fileiolen, j, MAX_FILE_NAME_LEN, NULL);
  fileiolen [fileiolenlen] = '\0';
  sscanf (fileiolen, "%ld", &iolen);
  if (fileiolenlen == 0 || iolen > data_window_size) iolen = data_window_size;
  if (user_trace)
    fprintf (stderr, "  and maximum length IO of >>>%s<<< --> %ld\n",
	     fileiolen, iolen);

  if (user_trace)
    fprintf (stderr, "Opening file %s for file I/O (reading)\n", ifn);

  fp = stdin;
  if ( fnlen  > 0 && strncmp ("stdin", ifn, 6) != 0)
    {
      fp = fopen (ifn, "rb");
      if (fp == NULL)
	{
	  fatalerror5 (
	       "For some reason, I was unable to read-open the file named ",
	       filename, CRM_ENGINE_HERE );
	  goto input_no_open_bailout;
	};
    };

  done = 0;
  mc = 0;

  //   get the variable name
  crm_nextword( temp_vars, tvlen, 0,  &vstart, &vlen);

  if (vlen == 0)
    {
      done = 1;
    }
  else
    {
      //        must make a copy of the varname.
      //
      char vname[MAX_VARNAME];
      long ichar = 0;
      memmove (vname, &(temp_vars[vstart]), vlen);
      vname [vlen] = '\000';

      //        If we have a seek requested, do an fseek.
      //        (Annoying But True: fseek on stdin does NOT error, it's
      //        silently _ignored_.  Who knew?
      if (fp == stdin && offset != 0 )
	{
	  nonfatalerror5 ("Hmmm, a file offset on stdin won't do much. ",
			  "I'll ignore it for now. ",
			  CRM_ENGINE_HERE );
	}
      else
	if (offset != 0)
	  if (EBADF == fseek (fp, offset, SEEK_SET))
	    nonfatalerror5 ("Dang, seems that this file isn't fseek()able: ",
			    filename, CRM_ENGINE_HERE);

      //    are we supposed to use readline (the <readline> flag) ?
#ifdef HAVE_READLINE
      if (use_readline)
	{
	  char *chartemp;
	  chartemp = readline ("");
	  strncpy (inbuf, chartemp, data_window_size);
	  free (chartemp);
	}
      else
#endif
	//        Are we in <byline> mode?  If so, read one char at a time.
	if (! till_eof)
	  {
	    //    grab characters in a loop, terminated by EOF or newline
	    ichar = 0;
	    if (feof (fp) ) clearerr (fp);
	    while (!feof (fp)
		   && ichar < (data_window_size >> SYSCALL_WINDOW_RATIO)
		   && ( till_eof || ( ichar == 0 || inbuf [ichar-1] != '\n'))
		   && ichar <= iolen )
	      {
		inbuf[ichar] = fgetc (fp);
		ichar++;
	      };
	    if (ichar > 0) ichar-- ; //   get rid of any present newline
	    inbuf[ichar] = '\000';   // and put a null on the end of it.
	  }
	else
	  {
	    //    Nope, we are in full-block mode, read the whole block in
	    //    a single I/O if we can.
	    ichar = 0;
	    if (feof (fp)) clearerr (fp);         // reset any EOF
	    ichar = fread (inbuf, 1, iolen, fp);  // do a block I/O
	    inbuf[ichar] ='\000';                 // null at the end
	  };
      crm_set_temp_nvar (vname, inbuf, ichar);
    };

  //     and close the input file if it's not stdin.
  if (fp != stdin) fclose (fp);

 input_no_open_bailout:
  return (0);
};

//////////////////////////////////////////
//
//        And here's where we do output

int crm_expr_output ( CSL_CELL *csl, ARGPARSE_BLOCK *apb)
{
  long i, j;

  //    output a string, usually to stdout unless otherwise
  //    specified in the output statement.
  //
  //    We do variable substitutions here....
  //  char outfile[MAX_VARNAME];
  //long outfilelen;
  //char ofn[MAX_VARNAME];
  long outtextlen;
  FILE *outf;

  char filename [MAX_FILE_NAME_LEN];
  char fnam [MAX_FILE_NAME_LEN];
  long fnlen;
  char fileoffset [MAX_FILE_NAME_LEN];
  long fileoffsetlen;
  char fileiolen [MAX_FILE_NAME_LEN];
  long fileiolenlen;
  long offset, iolen;


  if (user_trace)
    fprintf (stderr," Executing an OUTPUT statement\n");

  //    get the output file name
  //
  //   What file name?
  //
  crm_get_pgm_arg (filename, MAX_FILE_NAME_LEN, apb->b1start,apb->b1len);
  crm_nextword (filename, apb->b1len, 0, &i, &j);
  memmove (fnam, &filename[i], j);
  fnlen = crm_nexpandvar (fnam, j, MAX_FILE_NAME_LEN);
  fnam[fnlen] = '\0';
  if (user_trace)
    fprintf (stderr, "  filename >>>%s<<<\n", fnam);

  //   and what offset we need to do before the I/O...
  //
  offset = 0;
  crm_nextword (filename, apb->b1len, i+j, &i, &j);
  memmove (fileoffset, &filename[i], j);
  fileoffsetlen = crm_qexpandvar (fileoffset, j, MAX_FILE_NAME_LEN, NULL);
  fileoffset [fileoffsetlen] = '\0';
  sscanf (fileoffset, "%ld", &offset);
  if (user_trace)
    fprintf (stderr, "  pre-IO seek to >>>%s<<< --> %ld \n",
	     fileoffset, offset);

  //   and how many bytes to read
  //
  iolen = 0;
  crm_nextword (filename, apb->b1len, i+j, &i, &j);
  memmove (fileiolen, &filename[i], j);
  fileiolenlen = crm_qexpandvar (fileiolen, j, MAX_FILE_NAME_LEN, NULL);
  fileiolen [fileiolenlen] = '\0';
  sscanf (fileiolen, "%ld", &iolen);
  if (fileiolenlen == 0 || iolen > data_window_size) iolen = data_window_size;
  if (user_trace)
    fprintf (stderr, "  and maximum length IO of >>>%s<<< --> %ld\n",
	     fileiolen, iolen);


  outf = stdout;
  if ( fnlen > 0)
    {
      if (user_trace)
	fprintf (stderr, "Opening file %s for I/O (writing)\n", fnam);
      if (strcmp(fnam,"stderr")==0)
	{
	  outf = stderr;
	}
      else if (strcmp(fnam,"stdout")!=0)
	{
	  if (apb->sflags & CRM_APPEND
	      || fileoffsetlen > 0 )
	    {
	      outf = fopen (fnam, "r+b");
	      //
	      //    If the file didn't exist already, that open would fail.
	      //     so we retry with "w+".
	      if (!outf) outf = fopen (fnam, "w+b");
	      //
	      //     And make sure the file pointer is at EOF.
	      if ( outf != 0 )
		fseek (outf, 0, SEEK_END);
	    }
	  else
	    {
	      outf = fopen (fnam, "wb");
	    };
	};
    };

  //
  //   could we open the file?
  //
  if ( outf == 0 )
    {
      fatalerror5
	("For some reason, I was unable to write-open the file named",
	 fnam,
	 CRM_ENGINE_HERE);
    }
  else
    {
      //   Yep, file is open, go for the writing.
      //
      crm_get_pgm_arg (outbuf, data_window_size,
			     apb->s1start, apb->s1len);
      outtextlen = apb->s1len;
      if (internal_trace)
	fprintf (stderr, "  outputting with pattern %s\n", outbuf);

      //      Do variable substitution on outbuf.
      outtextlen = crm_nexpandvar (outbuf, outtextlen, data_window_size);

      //      Do the seek if necessary
      //
      if ( fileoffsetlen > 0)
	{
	  //	  fprintf (stderr, "SEEKING to %ld\n", offset);
	  rewind (outf);
	  fseek (outf, offset, SEEK_SET);
	};

      //      Write at most iolen bytes
      //
      if (fileiolenlen > 0)
	if (iolen < outtextlen)
	  outtextlen = iolen;

      //   and send it to outf
      //
      dontcare = fwrite (outbuf, outtextlen, 1, outf);
      fflush (outf);
      if (outf != stdout && outf != stderr ) fclose (outf);
    };

  return (0);
}