Unnamed Fossil Project

Check-in [224e0af1b9]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Thread safe output buffers.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 224e0af1b980e155700b43d68c3f1daf517c6b95
User & Date: dgp 2013-05-06 16:45:58
Context
2013-05-07
16:59
Increase robustness of ThreadData replacements when no threading support. check-in: 55490ebb9d user: dgp tags: trunk
2013-05-06
16:45
Thread safe output buffers. check-in: 224e0af1b9 user: dgp tags: trunk
14:27
Thread safety for *printf scale value cache. check-in: 141a5b9278 user: dgp tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/qio.c.

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
	r = atoqnum(etoabuf);
	if (ziszero(r->den)) {
		qfree(r);
		r = NULL;
	}
	return r;
}
#endif


#if 0
/*
 * Print a number in the specified output mode.
 * If MODE_DEFAULT is given, then the default output mode is used.
 * Any approximate output is flagged with a leading tilde.
 * Integers are always printed as themselves.
 */
void






<


<







208
209
210
211
212
213
214

215
216

217
218
219
220
221
222
223
	r = atoqnum(etoabuf);
	if (ziszero(r->den)) {
		qfree(r);
		r = NULL;
	}
	return r;
}




/*
 * Print a number in the specified output mode.
 * If MODE_DEFAULT is given, then the default output mode is used.
 * Any approximate output is flagged with a leading tilde.
 * Integers are always printed as themselves.
 */
void

Changes to generic/zio.c.

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
..
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
...
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
 * Copyright (c) 1994 David I. Bell
 * Permission is granted to use, distribute, or modify this source,
 * provided that this copyright notice remains intact.
 *
 * Scanf and printf routines for arbitrary precision integers.
 */

#include <tcl.h>
#include "zmath.h"


#define	OUTBUFSIZE	200		/* realloc size for output buffers */

#define	PUTCHAR(ch)		math_chr(ch)
#define	PUTSTR(str)		math_str(str)
#define	PRINTF1(fmt, a1)	math_fmt(fmt, a1)
#define	PRINTF2(fmt, a1, a2)	math_fmt(fmt, a1, a2)

/*
 * Output state that has been saved when diversions are done.
 */


typedef struct iostate IOSTATE;
struct iostate {
	IOSTATE *oldiostates;		/* previous saved state */
	long outdigits;			/* digits for output */
	FILE *outfp;			/* file unit for output (if any) */
	char *outbuf;			/* output string buffer (if any) */
	long outbufsize;		/* current size of string buffer */
	long outbufused;		/* space used in string buffer */
	BOOL outputisstring;		/* TRUE if output is to string buffer */
};



static IOSTATE	*oldiostates = NULL;	/* list of saved output states */
static FILE	*outfp = NULL;		/* file unit for output */
static char	*outbuf = NULL;		/* current diverted buffer */
static BOOL	outputisstring = FALSE;
static long	outbufsize;
static long	outbufused;



/*
 * zio_init - perform needed initilization work
 *
 * On some systems, one cannot initialize a pointer to a FILE *.
 * This routine, called once at startup is a work-a-round for
 * systems with such bogons.
 */
................................................................................
    static int done = 0;	/* 1 => routine already called */

    if (!done) {
	outfp = stdout;
	done = 1;
    }
}















/*
 * Routine to output a character either to a FILE
 * handle or into a string.
 */
void
math_chr(ch)
	int ch;
{
	char	*cp;


	if (!outputisstring) {
		fputc(ch, outfp);
		return;
	}
	if (outbufused >= outbufsize) {
		cp = (char *)ckrealloc(outbuf, outbufsize + OUTBUFSIZE + 1);
		if (cp == NULL)
			math_error("Cannot realloc output string");
		outbuf = cp;
		outbufsize += OUTBUFSIZE;
	}
	outbuf[outbufused++] = (char)ch;
}


/*
 * Routine to output a null-terminated string either
 * to a FILE handle or into a string.
 */
void
math_str(str)
	CONST char	*str;
{

	char	*cp;
	int	len;

	if (!outputisstring) {
		fputs(str, outfp);
		return;
	}
	len = strlen(str);
	if ((outbufused + len) > outbufsize) {
		cp = (char *)ckrealloc(outbuf, outbufsize + len + OUTBUFSIZE + 1);
		if (cp == NULL)
			math_error("Cannot realloc output string");
		outbuf = cp;
		outbufsize += (len + OUTBUFSIZE);
	}
	memcpy(&outbuf[outbufused], str, len);

	outbufused += len;
}


/*
 * Output a null-terminated string either to a FILE handle or into a string,
 * padded with spaces as needed so as to fit within the specified width.
 * If width is positive, the spaces are added at the front of the string.
................................................................................
 * returned later when the diversion is completed.  The current state of
 * output is remembered for later restoration.  Diversions can be nested.
 * Output diversion is only intended for saving output to "stdout".
 */
void
math_divertio()
{
	register IOSTATE *sp;


	sp = (IOSTATE *) ckalloc(sizeof(IOSTATE));
	if (sp == NULL)
		math_error("No memory for diverting output");
	sp->oldiostates = oldiostates;
	sp->outfp = outfp;
	sp->outbuf = outbuf;
	sp->outbufsize = outbufsize;
	sp->outbufused = outbufused;
	sp->outputisstring = outputisstring;

	outbufused = 0;
	outbufsize = 0;
	outbuf = (char *) ckalloc(OUTBUFSIZE + 1);
	if (outbuf == NULL)
		math_error("Cannot allocate divert string");
	outbufsize = OUTBUFSIZE;
	outputisstring = TRUE;
	oldiostates = sp;


}


/*
 * Undivert output and return the saved output as a string.  This also
 * restores the output state to what it was before the diversion began.
 * The string needs freeing by the caller when it is no longer needed.
 */
char *
math_getdivertedio()
{
	register IOSTATE *sp;

	char *cp;

	sp = oldiostates;
	if (sp == NULL)
		math_error("No diverted state to restore");
	cp = outbuf;
	cp[outbufused] = '\0';
	oldiostates = sp->oldiostates;
	outfp = sp->outfp;
	outbuf = sp->outbuf;
	outbufsize = sp->outbufsize;
	outbufused = sp->outbufused;
	outbuf = sp->outbuf;
	outputisstring = sp->outputisstring;
	ckfree((char *)sp);		/* TP: fix memory leak */
	return cp;
}


/*
 * Clear all diversions and set output back to the original destination.
 * This is called when resetting the global state of the program.
 */
void
math_cleardiversions()
{


	while (oldiostates)
		ckfree(math_getdivertedio());
}


#if 0
/*
 * Set the output routines to output to the specified FILE stream.






<
|
<











>
>
|
<
<
|
<
|
|
|
<
<
>


<
<
<
<
<
<
<
<
>







 







>

>
>
>
>
>
>
>
>
>
>
>
>










>

<
|
<
<
<
|


|
|

|











>



<
<
<
<

|
|


|
|

<
>
|







 







|
>

<
|

|
<
<
<
<
<
<
<
<
|
|

|
<
<
>
>











|
>


<
|

|
|
|
<
<
<
<
<
<
|











>
>
|







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
..
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
...
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
 * Copyright (c) 1994 David I. Bell
 * Permission is granted to use, distribute, or modify this source,
 * provided that this copyright notice remains intact.
 *
 * Scanf and printf routines for arbitrary precision integers.
 */


#include "mpexpr.h"


#define	OUTBUFSIZE	200		/* realloc size for output buffers */

#define	PUTCHAR(ch)		math_chr(ch)
#define	PUTSTR(str)		math_str(str)
#define	PRINTF1(fmt, a1)	math_fmt(fmt, a1)
#define	PRINTF2(fmt, a1, a2)	math_fmt(fmt, a1, a2)

/*
 * Output state that has been saved when diversions are done.
 */

static Tcl_ThreadDataKey outKey;
typedef struct Out {


    struct Out *next;	/* List of pending nested buffers */

    char *buf;		/* output string buffer */
    long size;		/* current size of buffer */
    long used;		/* space used in buffer */


} Out;










#if 0
/*
 * zio_init - perform needed initilization work
 *
 * On some systems, one cannot initialize a pointer to a FILE *.
 * This routine, called once at startup is a work-a-round for
 * systems with such bogons.
 */
................................................................................
    static int done = 0;	/* 1 => routine already called */

    if (!done) {
	outfp = stdout;
	done = 1;
    }
}
#endif

static Out *
GetOut()
{
	Out **outListPtr = Tcl_GetThreadData(&outKey, sizeof(Out *));
	Out *out = *outListPtr;

	if (out == NULL) {
		math_divertio();
		out = *outListPtr;
	}
	return out;
}

/*
 * Routine to output a character either to a FILE
 * handle or into a string.
 */
void
math_chr(ch)
	int ch;
{
	char	*cp;
	Out *out = GetOut();


	if (out->used >= out->size) {



		cp = (char *)ckrealloc(out->buf, out->size + OUTBUFSIZE + 1);
		if (cp == NULL)
			math_error("Cannot realloc output string");
		out->buf = cp;
		out->size += OUTBUFSIZE;
	}
	out->buf[out->used++] = (char)ch;
}


/*
 * Routine to output a null-terminated string either
 * to a FILE handle or into a string.
 */
void
math_str(str)
	CONST char	*str;
{
	Out *out = GetOut();
	char	*cp;
	int	len;





	len = strlen(str);
	if ((out->used + len) > out->size) {
		cp = (char *)ckrealloc(out->buf, out->size + len + OUTBUFSIZE + 1);
		if (cp == NULL)
			math_error("Cannot realloc output string");
		out->buf = cp;
		out->size += (len + OUTBUFSIZE);
	}

	memcpy(out->buf + out->used, str, len);
	out->used += len;
}


/*
 * Output a null-terminated string either to a FILE handle or into a string,
 * padded with spaces as needed so as to fit within the specified width.
 * If width is positive, the spaces are added at the front of the string.
................................................................................
 * returned later when the diversion is completed.  The current state of
 * output is remembered for later restoration.  Diversions can be nested.
 * Output diversion is only intended for saving output to "stdout".
 */
void
math_divertio()
{
	Out **outListPtr = Tcl_GetThreadData(&outKey, sizeof(Out *));
	Out *new = (Out *) ckalloc(sizeof(Out));


	if (new == NULL)
		math_error("No memory for diverting output");
	new->next = *outListPtr;








	new->buf = (char *) ckalloc(OUTBUFSIZE + 1);
	if (new->buf == NULL)
		math_error("Cannot allocate divert string");
	new->size = OUTBUFSIZE;


	new->used = 0;
	*outListPtr = new;
}


/*
 * Undivert output and return the saved output as a string.  This also
 * restores the output state to what it was before the diversion began.
 * The string needs freeing by the caller when it is no longer needed.
 */
char *
math_getdivertedio()
{
	Out **outListPtr = Tcl_GetThreadData(&outKey, sizeof(Out *));
	Out *out = *outListPtr;
	char *cp;


	if (out == NULL)
		math_error("No diverted state to restore");
	cp = out->buf;
	cp[out->used] = '\0';
	*outListPtr = out->next;






	ckfree((char *)out);
	return cp;
}


/*
 * Clear all diversions and set output back to the original destination.
 * This is called when resetting the global state of the program.
 */
void
math_cleardiversions()
{
	Out **outListPtr = Tcl_GetThreadData(&outKey, sizeof(Out *));

	while (*outListPtr) 
		ckfree(math_getdivertedio());
}


#if 0
/*
 * Set the output routines to output to the specified FILE stream.