source: vendor/gawk/3.1.5/vms/vms_fwrite.c

Last change on this file was 3076, checked in by bird, 18 years ago

gawk 3.1.5

File size: 7.8 KB
Line 
1/* vms_fwrite.c - augmentation for the fwrite() function.
2
3 Copyright (C) 1991-1996 the Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18
19#include "awk.h" /* really "../awk.h" */
20
21#ifndef NO_TTY_FWRITE
22#include "vms.h"
23#include <stdio.h>
24#include <errno.h>
25
26#ifdef VAXC_BUILTINS
27#pragma builtins /* VAXC V3.0 & up */
28# define find_c(s,n,c) ((n) - _LOCC((c),(n),(s)))
29#else /*VAXC_BUILTINS*/
30static int find_c( const char *s, int n, char c ) {
31 register const char *t = (const char *)memchr(s, c, n);
32 return (t == 0 ? n : t - s); /* 0..n-1, or n if not found */
33}
34#endif /*VAXC_BUILTINS*/
35#define is_stdout(file_no) ((file_no) == 1) /* fileno(stdout) */
36#define is_stderr(file_no) ((file_no) == 2) /* fileno(stderr) */
37
38#define PREFIX_CR 0x008D0000 /* leading carriage return */
39#define POSTFIX_CR 0x8D000000 /* trailing carriage return (=> lf/cr) */
40
41static short channel[_NFILE] = {0};
42static FILE *prev_file = 0;
43static int prev_file_num;
44
45 /*
46 * VAXCRTL's fwrite() seems to flush after every character when
47 * writing to a terminal. This routine is a limited functionality
48 * substitute that is *much* faster. However, calls to fwrite()
49 * should not be mixed with other stdio calls to the same file
50 * unless fflush() is always called first. Also, this routine
51 * will not detect that a freopen() call has finished with the
52 * original terminal; tty_fclose() should be used to close a file.
53 */
54#ifdef fwrite
55# undef fwrite
56#endif
57/* tty_fwrite() - performance hack for fwrite() to a terminal */
58size_t
59tty_fwrite( const void *buf, size_t size, size_t number, FILE *file )
60{
61 static long evfn = -1;
62 short chan;
63 int file_num, result;
64
65 if (!size || !number)
66 return 0;
67 else if (!file || !*file)
68 return 0 * (errno = EBADF); /* kludge alert! */
69 else if (file == prev_file)
70 file_num = prev_file_num;
71 else /* note: VAXCRTL's fileno() is a function, not just a macro */
72 prev_file_num = file_num = fileno(file), prev_file = file;
73
74 chan = file_num < _NFILE ? channel[file_num] : -1;
75 if (chan == 0) { /* if not initialized, need to assign a channel */
76 if (isatty(file_num) > 0) { /* isatty: 1=yes, 0=no, -1=problem */
77 Dsc device;
78 char devnam[255+1];
79 fgetname(file, devnam); /* get 'file's name */
80 device.len = strlen(device.adr = devnam); /* create descriptor */
81 if (vmswork(sys$assign(&device, &chan, 0, (Dsc *)0))) {
82 /* get an event flag; use #0 if problem */
83 if (evfn == -1 && vmsfail(lib$get_ef(&evfn))) evfn = 0;
84 } else chan = 0; /* $ASSIGN failed */
85 }
86 /* store channel for later use; -1 => don't repeat failed init attempt */
87 channel[file_num] = (chan > 0 ? chan : -1);
88 }
89 if (chan > 0) { /* chan > 0 iff 'file' is a terminal */
90 struct _iosbw { U_Short status, count; U_Long rt_kludge; } iosb;
91 register U_Long sts = 1;
92 register char *pt = (char *)buf;
93 register int offset, pos, count = size * number;
94 U_Long cc_fmt, io_func = IO$_WRITEVBLK;
95 int extra = 0;
96 result = 0;
97 if (is_stderr(file_num)) /* if it's SYS$ERROR (stderr)... */
98 io_func |= IO$M_CANCTRLO; /* cancel ^O (resume tty output) */
99 while (count > 0) {
100 /* special handling for line-feeds to make them be 'newlines' */
101 offset = 0;
102 if (*pt == '\n') { /* got at least one leading line-feed */
103 cc_fmt = PREFIX_CR, extra++; /* precede 1st LF with a CR */
104 do offset++;
105 while (offset < count && *(pt + offset) == '\n');
106 } else
107 cc_fmt = 0;
108 /* look for another line-feed; if found, break line there */
109 pos = offset + find_c(pt + offset, count - offset, '\n');
110 if (pos >= BUFSIZ) pos = BUFSIZ - 1; /* throttle quota usage */
111 else if (pos < count) pos++, cc_fmt |= POSTFIX_CR, extra++;
112 /* wait for previous write, if any, to complete */
113 if (pt > (char *)buf) {
114 sts = sys$synch(evfn, &iosb);
115 if (vmswork(sts)) sts = iosb.status, result += iosb.count;
116 if (vmsfail(sts)) break;
117 }
118 /* queue an asynchronous write */
119 sts = sys$qio(evfn, chan, io_func, &iosb, (void (*)(U_Long))0, 0L,
120 pt, pos, 0, cc_fmt, 0, 0);
121 if (vmsfail(sts)) break; /*(should never happen)*/
122 pt += pos, count -= pos;
123 }
124 /* wait for last write to complete */
125 if (pt > (char *)buf && vmswork(sts)) {
126 sts = sys$synch(evfn, &iosb);
127 if (vmswork(sts)) sts = iosb.status, result += iosb.count;
128 }
129 if (vmsfail(sts)) errno = EVMSERR, vaxc$errno = sts;
130 else if (iosb.rt_kludge == 0) result = number + extra;
131 result -= extra; /* subtract the additional carriage-returns */
132 } else { /* use stdio */
133 /* Note: we assume that we're writing text, not binary data.
134 For stream format files, 'size' and 'number' are effectively
135 interchangable, and fwrite works fine. However, for record
136 format files, 'size' governs the maximum record length, so
137 fwrite(string, size(char), strlen(string), file)
138 will produce a sequence of 1-byte records, which is hardly
139 what we want in this (assumed) situation. Line-feeds ('\n')
140 are converted into newlines (ie, record separators) by the
141 run-time library, but strings that don't end with a newline
142 still become separate records. The simplest work around
143 is just to use fputs() instead of fwrite(); unfortunately,
144 we have to provide special treatment for NULs ('\0's).
145 At present, only stdout might be in record format (via
146 >$'filename' redirection on the command line).
147 */
148 if (size > 1) { /* not used by GAWK */
149 result = fwrite((void *)buf, size, number, file);
150 } else if (*((char *)buf + number - 1) == '\n' || !is_stdout(file_num)) {
151 result = fwrite((void *)buf, number, size, file);
152 result = result * number / size; /*(same as 'result = number')*/
153 } else {
154#ifdef NO_ALLOCA
155# define alloca(n) ((n) <= abuf_siz ? abuf : \
156 ((abuf_siz > 0 ? (free(abuf),0) : 0), \
157 (abuf = malloc(abuf_siz = (n)+20))))
158 static void *abuf = 0;
159 static size_t abuf_siz = 0;
160#endif /*NO_ALLOCA*/
161 register char *pt = (char *)buf;
162 register int pos, count = number;
163 if (pt[count] != '\0') { /*(out of bounds, but relatively safe)*/
164 pt = (char *)alloca(count + 1);
165 memcpy(pt, buf, count), pt[count] = '\0';
166 /* if exiting this block undoes the alloca(), we're hosed :-( */
167 }
168 result = 0;
169 while (count > 0) {
170 pos = find_c(pt, count, '\0');
171 if (fputs(pt, file) < 0) break;
172 if (pos < count) {
173 if (fputc('\0', file) < 0) break;
174 pos++; /* 0..n-1 -> 1..n */
175 }
176 result += pos, pt += pos, count -= pos;
177 }
178 }
179 }
180 return result;
181}
182#define fwrite(b,s,n,f) tty_fwrite((b),(s),(n),(f))
183
184#ifdef fclose
185# undef fclose
186#endif
187/* tty_fclose() - keep tty_fwrite() up to date when closing a file */
188int
189tty_fclose( FILE *file )
190{
191 if (file && *file) { /* note: VAXCRTL stdio has extra level of indirection */
192 int file_num = fileno(file);
193 short chan = file_num < _NFILE ? channel[file_num] : -1;
194 if (chan > 0)
195 (void)sys$dassgn(chan); /* deassign the channel (ie, close) */
196 if (file_num < _NFILE)
197 channel[file_num] = 0; /* clear stale info */
198 }
199 prev_file = 0; /* force tty_fwrite() to reset */
200 return fclose(file);
201}
202#define fclose(f) tty_fclose(f)
203
204#endif /*!NO_TTY_FWRITE*/
Note: See TracBrowser for help on using the repository browser.