viminfo
[gnucap-felix.git] / lib / io_out.cc
blobf8bf616192a2a2c7bdda96a9aae447535295b88e
1 /*$Id: io_out.cc,v 26.137 2010/04/10 02:37:33 al Exp $ -*- C++ -*-
2 * Copyright (C) 2001 Albert Davis
3 * Author: Albert Davis <aldavis@gnu.org>
5 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *------------------------------------------------------------------
22 * output text to files, devices, or whatever
23 * m???? = multiple output to a bunch of io devices.
24 * with character count (so tab will work)
25 * Will start a new line first if the entire output will not fit.
26 * so wrap will not break a word or number.
27 * Where is a bit mask of places to send the output.
28 * A possible portability problem exists with the handle numbers.
29 * It assumes they start at 0, and count up, and that there are no more than
30 * the number of bits in an integer (MAXHANDLE).
31 * but I have yet to find a system that did not meet this form.
33 //testing=script,sparse 2006.07.17
34 #include "u_opt.h"
35 /*--------------------------------------------------------------------------*/
36 const char* octal(int x);
37 // OMSTREAM & OMSTREAM::tab(int count)
38 // OMSTREAM & OMSTREAM::form(const char*,...);
39 // OMSTREAM & OMSTREAM::operator<<(const char *str)
40 // OMSTREAM & OMSTREAM::operator<<(char chr)
41 /*--------------------------------------------------------------------------*/
42 FILE* OMSTREAM::_stream[MAXHANDLE+1];
43 unsigned OMSTREAM::_cpos[MAXHANDLE+1]; /* character counter */
44 /*--------------------------------------------------------------------------*/
45 /* octal: make octal string for an int
47 const char* octal(int x)
49 static char s[sizeof(int)*3+1];
50 sprintf(s, "%o", x);
51 return s;
53 /*--------------------------------------------------------------------------*/
54 /* mtab: tab to column "count" on output devices "where"
55 * by outputting spaces.
56 * If already beyond, start new line, then tab to column.
58 OMSTREAM & OMSTREAM::tab(unsigned count)
60 for (int ii=0, mm=1; ii<=MAXHANDLE; ++ii, mm<<=1) {
61 if (_mask & mm) {
62 OMSTREAM this_file(_mask & mm);
63 if (_cpos[ii] > count) {
64 this_file << '\n';
65 }else{
67 while (_cpos[ii]<count) {
68 this_file << ' ';
70 }else{
73 return *this;
75 /*--------------------------------------------------------------------------*/
76 /* mprintf: multiple printf
77 * printf to "m" style files.
79 OMSTREAM & OMSTREAM::form(const char *fmt, ...)
81 char buffer[BIGBUFLEN];
82 va_list arg_ptr;
84 va_start(arg_ptr,fmt);
85 vsprintf(buffer,fmt,arg_ptr);
86 va_end(arg_ptr);
88 *this << buffer;
89 return *this;
91 /*--------------------------------------------------------------------------*/
92 /* mputs: multiple puts.
93 * puts to "m" style files.
94 * also....
95 * starts new line, prefixes it with + if it would exceed width
96 * width is handled separately for each file to support different widths
97 * (which are not currently handled by .options)
98 * and it is possible that current contents of lines may be different
100 OMSTREAM & OMSTREAM::operator<<(const char *str)
102 assert(str);
104 if (_mask & 1) {
105 unreachable();
106 _mask &= ~1;
107 error(bDANGER, "internal error: out to stdin\n");
108 }else{
111 bool newline = false; /* true if any destination is at beginning of line */
112 size_t sl = strlen(str);
114 /* kluge: If a string ends with certain characters,
115 * require some extra space following it, possibly forcing to next line.
116 * Why? to avoid a line break between '=' and its argument.
118 if (sl == 0) {
119 }else if (strchr("@", str[sl-1])) {
120 sl += 16;
121 }else if (strchr("=", str[sl-1])) {
122 sl += 15;
123 }else if (strchr("(", str[sl-1])) {
124 sl += 12;
125 }else{
128 /* auto line break, with a '+' to continue. */
129 for (int ii=0, mm=1; ii<=MAXHANDLE; ++ii, mm<<=1) {
130 if ((_mask & mm)
131 && (sl+_cpos[ii]) >= OPT::outwidth
132 && _cpos[ii] != 0) {
133 OMSTREAM this_file(_mask & mm);
134 this_file << '\n' << '+';
135 }else{
136 } /* see if it fits .... */
137 if (_cpos[ii]==0) { /* if not, next line */
138 newline = true;
139 }else{
143 if (cipher() && newline) {untested();
144 *this << '\t';
145 }else{
148 while (*str && (str[1] || *str != '@')) {
149 *this << *str++;
151 return *this;
153 /*--------------------------------------------------------------------------*/
154 /* mputc: multiple putc
155 * multiple putc
156 * also....
157 * crunch spaces, if selected
158 * encripts, if selected
159 * keeps track of character count
161 OMSTREAM & OMSTREAM::operator<<(char chr)
163 if (_mask & 1) {
164 unreachable();
165 _mask &= ~1;
166 error(bDANGER, "internal error: out to stdin\n");
167 }else{
170 static int old = '\0';
171 static int cchr = 'w'; /* starting encryption seed */
172 /* arbitrary printable character */
173 bool count;
174 if (chr=='\t') {itested();
175 chr = ' ';
176 count = false;
177 }else{
178 count = true;
181 bool suppress = (pack() && old==' ' && chr==' ');
182 old = chr;
183 if (cipher() && !suppress && isprint(chr)) {untested();
184 cchr += static_cast<int>(chr);
185 while (!isascii(cchr) || !isprint(cchr)) {untested();
186 cchr -= (0x7f-0x20);
188 chr = static_cast<char>(cchr);
189 }else{
192 for (int ii=0, mm=1; ii<=MAXHANDLE; ++ii, mm<<=1) {
193 if (_mask & mm) {
194 assert(_stream[ii]);
195 if (chr=='\b') {untested();
196 --_cpos[ii];
197 fflush(_stream[ii]);
198 }else if (count) {
199 ++_cpos[ii];
200 }else{itested();
203 if (chr=='\n') {
204 _cpos[ii] = 0;
205 fflush(_stream[ii]);
206 }else if (chr=='\r') {itested();
207 if (_cpos[ii] == 0) {untested();
208 suppress = true;
209 }else{itested();
210 _cpos[ii] = 0;
211 fflush(_stream[ii]);
213 }else{
215 if (!suppress) {
216 fputc(chr,_stream[ii]);
217 }else{itested();
219 }else{
222 return *this;
224 /*--------------------------------------------------------------------------*/
225 /*--------------------------------------------------------------------------*/
226 // vim:ts=8:sw=2:noet: