aboutsummaryrefslogtreecommitdiffstats
path: root/vms/vms_fwrite.c
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2010-07-16 11:58:26 +0300
committerArnold D. Robbins <arnold@skeeve.com>2010-07-16 11:58:26 +0300
commit765c7494b3dac62207e6cd57fb839997e237f292 (patch)
treef7da12ffdb85d9f82671cb3122775b2ce73f7ad9 /vms/vms_fwrite.c
parentcce5115e21db1702e0617afdca36633e7e2c9eae (diff)
downloadegawk-765c7494b3dac62207e6cd57fb839997e237f292.tar.gz
egawk-765c7494b3dac62207e6cd57fb839997e237f292.tar.bz2
egawk-765c7494b3dac62207e6cd57fb839997e237f292.zip
Moving to 2.13.2.
Diffstat (limited to 'vms/vms_fwrite.c')
-rw-r--r--vms/vms_fwrite.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/vms/vms_fwrite.c b/vms/vms_fwrite.c
new file mode 100644
index 00000000..c0282c14
--- /dev/null
+++ b/vms/vms_fwrite.c
@@ -0,0 +1,209 @@
+/*
+ * vms_fwrite.c - augmentation for the fwrite() function.
+ */
+
+/*
+ * Copyright (C) 1991 the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Progamming Language.
+ *
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GAWK; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "awk.h" /* really "../awk.h" */
+
+#ifndef NO_TTY_FWRITE
+#include "vms.h"
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef VAXC_BUILTINS
+#pragma builtins /* VAXC V3.0 & up */
+# define find_c(s,n,c) ((n) - _LOCC((c),(n),(s)))
+#else /*VAXC_BUILTINS*/
+static int find_c( const char *s, int n, char c ) {
+ register const char *t = (const char *)memchr(s, c, n);
+ return (t == 0 ? n : t - s); /* 0..n-1, or n if not found */
+}
+#endif /*VAXC_BUILTINS*/
+#define is_stdout(file_no) ((file_no) == 1) /* fileno(stdout) */
+#define is_stderr(file_no) ((file_no) == 2) /* fileno(stderr) */
+
+#define PREFIX_CR (0x8D << 16) /* leading carriage return */
+#define POSTFIX_CR (0x8D << 24) /* trailing carriage return (=> lf/cr) */
+
+static short channel[_NFILE] = {0};
+static FILE *prev_file = 0;
+static int prev_file_num;
+
+ /*
+ * VAXCRTL's fwrite() seems to flush after every character when
+ * writing to a terminal. This routine is a limited functionality
+ * substitute that is *much* faster. However, calls to fwrite()
+ * should not be mixed with other stdio calls to the same file
+ * unless fflush() is always called first. Also, this routine
+ * will not detect that a freopen() call has finished with the
+ * original terminal; tty_fclose() should be used to close a file.
+ */
+#ifdef fwrite
+# undef fwrite
+#endif
+/* tty_fwrite() - performance hack for fwrite() to a terminal */
+size_t
+tty_fwrite( const void *buf, size_t size, size_t number, FILE *file )
+{
+ static long evfn = -1;
+ short chan;
+ int file_num, result;
+
+ if (!file || !*file)
+ return 0 * (errno = EBADF); /* kludge alert! */
+ else if (file == prev_file)
+ file_num = prev_file_num;
+ else /* note: VAXCRTL's fileno() is a function, not just a macro */
+ prev_file_num = file_num = fileno(file), prev_file = file;
+
+ chan = file_num < _NFILE ? channel[file_num] : -1;
+ if (chan == 0) { /* if not initialized, need to assign a channel */
+ if (isatty(file_num) > 0) { /* isatty: 1=yes, 0=no, -1=problem */
+ Dsc device;
+ char devnam[255+1];
+ fgetname(file, devnam); /* get 'file's name */
+ device.len = strlen(device.adr = devnam); /* create descriptor */
+ if (vmswork(SYS$ASSIGN(&device, &chan, 0, (Dsc *)0))) {
+ /* get an event flag; use #0 if problem */
+ if (evfn == -1 && vmsfail(LIB$GET_EF(&evfn))) evfn = 0;
+ } else chan = 0; /* $ASSIGN failed */
+ }
+ /* store channel for later use; -1 => don't repeat failed init attempt */
+ channel[file_num] = (chan > 0 ? chan : -1);
+ }
+ if (chan > 0) { /* chan > 0 iff 'file' is a terminal */
+ struct _iosbw { u_short status, count; u_long rt_kludge; } iosb;
+ register u_long sts = 1;
+ register char *pt = (char *)buf;
+ register int offset, pos, count = size * number;
+ u_long cc_fmt, io_func = IO$_WRITEVBLK;
+ int extra = 0;
+ result = 0;
+ if (is_stderr(file_num)) /* if it's SYS$ERROR (stderr)... */
+ io_func |= IO$M_CANCTRLO; /* cancel ^O (resume tty output) */
+ while (count > 0) {
+ /* special handling for line-feeds to make them be 'newlines' */
+ offset = 0;
+ if (*pt == '\n') { /* got at least one leading line-feed */
+ cc_fmt = PREFIX_CR, extra++; /* precede 1st LF with a CR */
+ do offset++;
+ while (offset < count && *(pt + offset) == '\n');
+ } else
+ cc_fmt = 0;
+ /* look for another line-feed; if found, break line there */
+ pos = offset + find_c(pt + offset, count - offset, '\n');
+ if (pos >= BUFSIZ) pos = BUFSIZ - 1; /* throttle quota usage */
+ else if (pos < count) pos++, cc_fmt |= POSTFIX_CR, extra++;
+ /* wait for previous write, if any, to complete */
+ if (pt > (char *)buf) {
+ sts = SYS$SYNCH(evfn, &iosb);
+ if (vmswork(sts)) sts = iosb.status, result += iosb.count;
+ if (vmsfail(sts)) break;
+ }
+ /* queue an asynchronous write */
+ sts = SYS$QIO(evfn, chan, io_func, &iosb, (u_long (*)())0, 0,
+ pt, pos, 0, cc_fmt, 0, 0);
+ if (vmsfail(sts)) break; /*(should never happen)*/
+ pt += pos, count -= pos;
+ }
+ /* wait for last write to complete */
+ if (pt > (char *)buf && vmswork(sts)) {
+ sts = SYS$SYNCH(evfn, &iosb);
+ if (vmswork(sts)) sts = iosb.status, result += iosb.count;
+ }
+ if (vmsfail(sts)) errno = EVMSERR, vaxc$errno = sts;
+ else if (iosb.rt_kludge == 0) result = number + extra;
+ result -= extra; /* subtract the additional carriage-returns */
+ } else { /* use stdio */
+ /* Note: we assume that we're writing text, not binary data.
+ For stream format files, 'size' and 'number' are effectively
+ interchangable, and fwrite works fine. However, for record
+ format files, 'size' governs the maximum record length, so
+ fwrite(string, size(char), strlen(string), file)
+ will produce a sequence of 1-byte records, which is hardly
+ what we want in this (assumed) situation. Line-feeds ('\n')
+ are converted into newlines (ie, record separators) by the
+ run-time library, but strings that don't end with a newline
+ still become separate records. The simplest work around
+ is just to use fputs() instead of fwrite(); unfortunately,
+ we have to provide special treatment for NULs ('\0's).
+ At present, only stdout might be in record format (via
+ >$'filename' redirection on the command line).
+ */
+ if (size > 1) { /* not used by GAWK */
+ result = fwrite((void *)buf, size, number, file);
+ } else if (*((char *)buf + number - 1) == '\n' || !is_stdout(file_num)) {
+ result = fwrite((void *)buf, number, size, file);
+ result = result * number / size; /*(same as 'result = number')*/
+ } else {
+#ifdef NO_ALLOCA
+# define alloca(n) ((n) <= abuf_siz ? abuf : \
+ (abuf_siz > 0 ? (void *)free(abuf) : (void *)0), \
+ (abuf = malloc(abuf_siz = (n)+20)))
+ static void *abuf = 0;
+ static size_t abuf_siz = 0;
+#endif /*NO_ALLOCA*/
+ register char *pt = (char *)buf;
+ register int pos, count = number;
+ if (pt[count] != '\0') { /*(out of bounds, but relatively safe)*/
+ pt = (char *)alloca(count + 1);
+ memcpy(pt, buf, count), pt[count] = '\0';
+ /* if exiting this block undoes the alloca(), we're hosed :-( */
+ }
+ result = 0;
+ while (count > 0) {
+ pos = find_c(pt, count, '\0');
+ if (fputs(pt, file) < 0) break;
+ if (pos < count) {
+ if (fputc('\0', file) < 0) break;
+ pos++; /* 0..n-1 -> 1..n */
+ }
+ result += pos, pt += pos, count -= pos;
+ }
+ }
+ }
+ return result;
+}
+#define fwrite(b,s,n,f) tty_fwrite((b),(s),(n),(f))
+
+#ifdef fclose
+# undef fclose
+#endif
+/* tty_fclose() - keep tty_fwrite() up to date when closing a file */
+int
+tty_fclose( FILE *file )
+{
+ if (file && *file) { /* note: VAXCRTL stdio has extra level of indirection */
+ int file_num = fileno(file);
+ short chan = file_num < _NFILE ? channel[file_num] : -1;
+ if (chan > 0)
+ (void)SYS$DASSGN(chan); /* deassign the channel (ie, close) */
+ if (file_num < _NFILE)
+ channel[file_num] = 0; /* clear stale info */
+ }
+ prev_file = 0; /* force tty_fwrite() to reset */
+ return fclose(file);
+}
+#define fclose(f) tty_fclose(f)
+
+#endif /*!NO_TTY_FWRITE*/