DNA.
wyrm-io
Version.
1.0.9
Namespace.
::wyrm ::wyrm::wif
Command.
::wyrm::io
Language.
c
Manpage.
wyrm-io (4WY)
Manpage.
cread (3WY)
Manpage.
cwrite (3WY)
Manpage.
cprintf (3WY)
Manpage.
rprintf (3WY)
Manpage.
dprintf (3WY)
Manpage.
io (1WY)
Manpage.
mc (1WY)
Manpage.
qio (1WY)
Testbase.
Test Script
Test Report
Import.
Interface.
wyrmwif
Export.
Implementation.
wyrm-io.c
Interface.
wyrm-io.h
Object.
wyrm-io.o
System.
wyrm-io.sys
wyrm-io.sys

<stdio>-ish Version of Tcl I/O.

Sections.
Introduction
I/O Constants and Variables
Character and String Reading
Character and String Writing
Format Values into an Object or Channel
format string
formatter
subst
va-args replacement
msgcat
Format Values into the Interpretter
Message Catalog Interface
I/O interpretter
Debugging
Command Interface
Testing interface
Make.
Object.
compile -c -o [
  export object
] [
  export implementation
] -- -list [import interface] [export interface]
   

Introduction

   
top

1 :: A simple interface to Tcl I/O in the style of stdio.h. However, the channel always comes first in calls, unlike stdio, where the FILE comes randomly as the first or last parameter.

Copyright (C) 2002 SM Ryan

Wyrmwif Tcl extensions. For non-profit uses only, provided this copyright is preserved on all copies, this work may be freely copied, modified, redistributed, compiled, and incorporated in other works. This work is distributed with no warranty of any kind; no author or distributor accepts any responsibility for the consequences of using it, or for whether it serves any particular purpose or works at all, unless he or she says so in writing.

 
section    top

#ifndef WYRM_IO_H
#define WYRM_IO_H


	//	wyrm-io.dna - Copyright (C) 2002 SM Ryan. All rights reserved.


	#include "wyrmwif.h"
	#include <stdio.h>
	#include <stdarg.h>

	<Character and string read interface>
	<Character and string write interface>
	<Formatted output interface>
	<Format into interpretter interface>
	
		
 
section    top
 
section    top

#include <ctype.h>
#include "wyrm-io.h"
#include "wyrm-io.sys"

		
   
   

I/O Constants and Variables

   
top
5. wyrm-io (4WY) ::

NAME

wyrm-io.h — wyrm-io globals.

description

<wyrm-io (4WY) Description>

This is just a <stdio.h> like interface to Tcl. This permits character or string at a time calls cgetc(channel) and cputc(channell,ch), as well formatted output cprintf.

<Thread safe>
 
section    top
 
section    top
#define chstdin—standard input channel.
#define chstdin (Tcl_GetStdChannel(TCL_STDIN))
		
 
section    top
#define chstdout—standard output channel.
#define chstdout (Tcl_GetStdChannel(TCL_STDOUT))
		
 
section    top
#define chstderr—standard error channel.
#define chstderr (Tcl_GetStdChannel(TCL_STDERR))
		
 
section    top
 
section    top
 
section    top
type ioResult—Additional I/O results.
BLK—Input is blocked; no data was returned.
EOF—Input is ended; no data was returned.
ERR—An error occurred.

#if EOF==-1
	enum ioResult {BLK=-2,ERR=-3};
#elif EOF<-3
	enum ioResult {BLK=-1,ERR=-2};
#else
	enum ioResult {BLK=-3,ERR=-4};
#endif

		
   
   

Character and String Reading

   
top
 
section    top

14 :: Character and string I/O just call Tcl_Write, Tcl_WriteObj, Tcl_Read, and Tcl_GetsObj with error returns refined (slightly).

 
section    top
proc cgetc—Read one char and return the actual byte as nonnegative value or ERR, EOF, or BLK.
input channel—Channel to read from.
io (channel)—Contents of channel read and advanced passed the read chars.
int cgetc(Tcl_Channel channel);
		
 
section    top

int cgetc(Tcl_Channel channel) {
	unsigned char b[1]; int N = cread(channel,b,1);
	return N>0 ? *b : N;
}

		
 
section    top
 
section    top
proc cgeto—Returns a new object containing read characters or NULL if end-of-file or error.
Memory. Reference count set to 1; decrement to reclaim storage.
input channel—Channel to read from.
io (channel)—Contents of channel read and advanced passed the read chars.
Obj cgeto(Tcl_Channel channel);
		
 
section    top

Obj cgeto(Tcl_Channel channel) {
	Obj obj = incr(Tcl_NewObj());
	int N = cgets(channel,obj);
	if (N==EOF || N==ERR) {
		decr(obj); obj = 0;
	}
	return obj;
}

		
 
section    top
 
section    top
proc cgets—Read into an object and return the number of bytes read or ERR, EOF, or BLK.
input channel—Channel to read from.
io (channel)—Contents of channel read and advanced passed the read chars.
output obj—Object to append the input to. A partial line may have been read if BLK is returned.
Memory. Must already be allocated and initialised.
int cgets(Tcl_Channel channel,Obj obj);
		
 
section    top

int cgets(Tcl_Channel channel,Obj obj) {
	int N = Tcl_GetsObj(channel,obj);
	return	N>=0 ? N
		:	Tcl_Eof(channel) ? EOF
		:	Tcl_InputBlocked(channel) ? BLK
		:	ERR;
}


		
 
section    top
 
section    top
proc cread—Read into the buffer and return the number of chars actual read, ERR, EOF, or BLK.
input channel—Channel to read from.
io (channel)—Contents of channel read and advanced passed the read chars.
input n—Maximum number of chars to read.
output p—Receives read bytes.
int cread(Tcl_Channel channel,ptr p,int n);
		
 
section    top

int cread(Tcl_Channel channel,ptr p,int n) {
	int N = Tcl_Read(channel,(chars)p,n);
	return	N>0 ? N
		:	Tcl_Eof(channel) ? EOF
		:	Tcl_InputBlocked(channel) ? BLK
		:	ERR;
}

		
 
section    top
 
section    top
    Read.
      cread
        Read data.
          SIO100
        Read error.
          SIO101
        Read blocking.
          SIO102
        Read end of file.
          SIO103
          SIO104
      cgetc
        Read ASCII character.
          SIO110
        Read non-ASCII character.
          SIO111
        Read error.
          SIO112
        Read blocking.
          SIO113
        Read end of file.
          SIO114
          SIO115
      cgets
        Read string onto empty string.
          SIO120
        Read string onto partial string.
          SIO121
        Read last line which has <nl%gt;.
          SIO122
        Read last line which does not have <nl%gt;.
          SIO123
        Read error.
          SIO124
        Read blocking.
          SIO125
        Read end of file.
          SIO126
          SIO127
      cgeto
        Read string.
          SIO130
        Read last line which has <nl%gt;.
          SIO131
        Read last line which does not have <nl%gt;.
          SIO132
        Read error.
          SIO133
        Read blocking.
          SIO134
        Read end of file.
          SIO135
          SIO136
   
   

Character and String Writing

   
top
 
section    top
proc cputc—Write one character and return the number of chars actually written (1) or ERR.
input channel—Channel to write to.
output (channel)—Contents of channel written and advanced.
input ch—Character to write.
int cputc(Tcl_Channel channel,int ch);
		
 
section    top

int cputc(Tcl_Channel channel,int ch) {
	char b[1]; *b = ch; return cwrite(channel,b,1);
}

		
 
section    top
 
section    top
proc cputo—Write one object and return the number of chars actually written or ERR.
input channel—Channel to write to.
output (channel)—Contents of channel written and advanced.
input obj—Object whose string representation is written.
int cputo(Tcl_Channel channel,Obj obj);
		
 
section    top

int cputo(Tcl_Channel channel,Obj obj) {
	if (obj) {
		int N = Tcl_WriteObj(channel,obj);
		return	N>0 ? N
			:	ERR;
	}else
		return 0;
}

		
 
section    top
 
section    top
#define cputs—Write string and return the number of chars actually written or ERR.
input channel—Channel to write to.
output (channel)—Contents of channel written and advanced.
input string—String to write.
#define cputs(channel,string) (cwrite(channel,(chars)(string),-1))
		
 
section    top
 
section    top
 
section    top
proc cwrite—Write buffer and return the number of chars actually written or ERR.
input channel—Channel to write to.
output (channel)—Contents of channel written and advanced.
input p—Sends written bytes.
input n—Maximum number of chars to write.
int cwrite(Tcl_Channel channel,ptr p,int n);
		
 
section    top

int cwrite(Tcl_Channel channel,ptr p,int n) {
	int N = Tcl_Write(channel,(chars)p,n);
	return	N>0 ? N
		:	ERR;
}

		
 
section    top
 
section    top
    Write.
      cwrite
        Write data.
          SIO200
        Write data with zero-byte.
          SIO201
        Write error.
          SIO202
        Write blocking.
          SIO203
        Write end of file.
          SIO204
          SIO205
      cputc
        Write ASCII data.
          SIO210
        Write error.
          SIO212
        Write blocking.
          SIO213
        Write end of file.
          SIO214
          SIO215
      cputs
        Write data.
          SIO220
        Write error.
          SIO221
        Write blocking.
          SIO222
        Write end of file.
          SIO223
          SIO224
      cputo
        Write data.
          SIO230
        Write error.
          SIO231
        Write blocking.
          SIO232
        Write end of file.
          SIO233
          SIO234
   
   

Format Values into an Object or Channel

   
top
 
section    top

43. Formatted output implementation :: This is much the same as the Tcl format command with a few features added. The input var-args list is read according to the format string %-formatters, but an alternate input type can be added. For example,

"%s" expects the next argument to be a string.

"%d" expects the next argument to be an integer.

"%{i}s" expects the next argument to be an integer packed with multiple characters. The characters are extracted and presented to format as a string.

"%{y}d" expects the next argument to be an object and presents it as an integer.

While formatters are examined for input and output types, the argument position is ignored. Arguments must be in the same order as their format specifier. To handle positional formats, transfer arguments in order for their first uses, and then use the empty input type "{}" for reoccurences. If the width or precision of a formatter includes an "*", the next argument is assumed to be an integer and packed unmodified.

input type c, d, i, o, x, X:
output type c, d, i, o, x, X
No conversion needed.
output type u
Signedness ignored.
output type f, e, E, g, G
Floated.
output type s
The integer value is regarded as a packed sequence of characters, which are unpacked and formatted as a string. Leading zero bytes are skipped. Sign extension is disabled so leading 0xFF characters are not created unless they actually occur.
input type u:
output type c, d, i, o, x, X
Unsignedness ignored.
output type u
No conversion needed.
output type f, e, E, g, G
Floated.
output type s
The unsigned value is regarded as a packed sequence of characters, which are unpacked and formatted as a string. Leading zero bytes are skipped. Sign extension is disabled so leading 0xFF characters are not created unless they actually occur.
input type f, e, E, g, G:
output type c, d, i, o, x, X
Truncated to integer.
output type u
Truncated to unsigned.
output type f, e, E, g, G
No conversion needed.
output type s
Not allowed.
input type s:
output type c, d, i, o, x, X
Not allowed.
output type u
Not allowed.
output type f, e, E, g, G
Not allowed.
output type s
No conversion needed.
input type n:
output type c, d, i, o, x, X
Not allowed.
output type u
Not allowed.
output type f, e, E, g, G
Not allowed.
output type s
The first n characters are formatted, including any null characters.
input type y:
Object formatted without conversion.
input type r:
Result formatted without conversion.
empty input:
Nothing is added to the argument list.

Format String Syntax

<format string syntax>

format-item ::= %% | subst-trigger | var-args-replacement | msgcat-load | formatter | any-character-except-%

<subst formatter syntax> <var-args replacement formatter syntax> <msgcat formatter syntax> <formatter syntax>
<subst Description><var-args Description><msgcat Description>
 
section    top
proc cprintf—Formatted print to a channel and return number of chars actually written or ERR.
input channel—Channel to write to.
output (channel)—Contents of channel written and advanced.
input format—The format string, augmented with %$ and input types.
input ...—List of formatted values.
io o—An internal Tcl interpretter. It is not directly available, but commands can be evaluated in it with decr(oprintf("%$tcl command"))
int cprintf(Tcl_Channel channel,chars format,...);
		
 
section    top

int cprintf(Tcl_Channel channel,chars format,...) {
	va_list args; Obj obj; int n;
	va_start(args,format); obj = voprintf(format,args); va_end(args);
	n = cputo(channel,obj); decr(obj);
	return n;
}

		
 
section    top
proc coprintf—Return a formatted string on an object.
Memory. New object with reference count 1.
input args—List of formatted values.
input format—The format string, augmented with %$ and input types.
io iointr—An internal Tcl interpretter. It is not directly available, but commands can be evaluated in it with decr(oprintf("%$tcl command"))
Obj oprintf(chars format,...);
		
 
section    top

Obj oprintf(chars format,...) {
	va_list args; Obj obj;
	va_start(args,format); obj = voprintf(format,args); va_end(args);
	return obj;
}

		
 
section    top
proc vcprintf
input channel—Channel to write to.
output (channel)—Contents of channel written and advanced.
input format—The format string, augmented with %$ and input types.
input args—List of formatted values.
io iointr—An internal Tcl interpretter. It is not directly available, but commands can be evaluated in it with decr(oprintf("%$tcl command"))
int vcprintf(Tcl_Channel channel,chars format,va_list args);
		
 
section    top

int vcprintf(Tcl_Channel channel,chars format,va_list args) {
	Obj obj; int n;
	obj = voprintf(format,args);
	n = cputo(channel,obj); decr(obj);
	return n;
}

		
 
section    top
proc voprintf—Return a formatted string on an object.
Memory. New object with reference count 1.
input format—The format string, augmented with %$ and input types.
input args—List of formatted values.
io iointr—An internal Tcl interpretter. It is not directly available, but commands can be evaluated in it with decr(oprintf("%$tcl command"))
Obj voprintf(chars format,va_list args);
		
 
section    top

Obj voprintf(chars format,va_list args) {
	ThreadData *thread = Tcl_GetThreadData(&ioKey,sizeof(ThreadData));
	Obj result = 0;
	<Declare msgcat variables>
	<Format string traversal loop variables>
	<Parse the entire format string and varargs list>
	<Format the list>
	<Subst the list>
	<Collect loop variables>
	<Release msgcat variables>
	return result;
}

		
 
section    top

Tcl_CmdInfo formatCmd; bool gotFormatCmd;

		
 
section    top
			
<Get I/O interpretter>
if (!thread->gotFormatCmd) {
	thread->gotFormatCmd = Tcl_GetCommandInfo(thread->iointr,"format",&thread->formatCmd);
}
if (thread->gotFormatCmd) {
	thread->formatCmd.objProc(thread->formatCmd.objClientData,thread->iointr,N,P1);
	result = incr(Tcl_GetObjResult(thread->iointr));
	Tcl_ResetResult(thread->iointr);
} else {
	result = incr(Tcl_NewStringObj("<couldn't find format command>",-1));
}

		
   
   

format string

   
top
 
section    top
chars f—Cursor to traverse the input format string.
chars f;
		
 
section    top
Obj format1—The translated format string.
Obj format1 = incr(Tcl_NewObj());
		
 
section    top

if (f[0]=='%' && f[1]=='%') {
	Tcl_AppendToObj(format1,f,2); f+=2;
}else if (f[0]=='%' && f[1]=='$') {
	<Trigger call of subst command>
}else if (f[0]=='%' && f[1]=='P') {
	<Var-args replacement by an array of objects>
}else if (f[0]=='%' && f[1]=='#') {
	<Substitute a message catalog string>
}else if (*f!='%') {
	Tcl_AppendToObj(format1,f,1); f+=1;
}else {
	<Formatter variables>
	Tcl_AppendToObj(format1,f,1); f+=1;
	<Parse and translate the formatter>
	if (!varargsReplaced) {
		<Move formatter varargs to argument list>
	}
}

		
 
section    top

Obj *P,*P1; int N;

		
 
section    top

decr(P1[0]);
decr(P1[1]);
dispose(P1);

		
 
section    top

for (f=format; *f; ) {
	<Parse and translate step the format string>
}
Tcl_ListObjGetElements(0,list,&N,&P);
P1 = nheap(N+2,Obj);
P1[0] = incr(Tcl_NewStringObj("format",-1));
P1[1] = format1;
memcpy(P1+2,P,N*sizeof(Obj));
N += 2;

		
   
   

formatter

   
top
 
section    top

int numberAsterisks = 0;
int intype=0,intype1=0,inmod=0,outtype=0,outtype1=0,outmod=0;
int suffix=0;
chars input;

		
 
section    top

while (*f!=0 && *f!='{' && !isalpha(*f)) {
	numberAsterisks += *f=='*';
	Tcl_AppendToObj(format1,f,1); f+=1;
}
if (f[0]=='{' && f[1]=='}') {
	f += 2;
	while (*f && (!isalpha(*f) || tolower(*f)=='h' || tolower(*f)=='l')) {
		Tcl_AppendToObj(format1,f,1); f+=1;
	}
	continue;
}
if (*f=='{') {
	chars F = strchr(f+1,'}');
	input = f+1;
	f = F ? F+1 : f+1;
}else {
	input = "";
}
if (tolower(*f)=='h') {
	outmod = 1; Tcl_AppendToObj(format1,f,1); f+=1;
}else if (tolower(*f)=='l') {
	outmod = 2; Tcl_AppendToObj(format1,f,1); f+=1;
}
if (isalpha(*f)) {
	outtype = *f; Tcl_AppendToObj(format1,f,1); f+=1;
}
if (isalpha(*input)) {
	if (tolower(*input)=='h') {
		inmod = 1; input+=1;
	}else if (tolower(*input)=='l') {
		inmod = 2; input+=1;
	}
	if (isalpha(*input)) {
		intype = *input; input+=1;
	}
}else {
	intype = outtype; inmod = inmod;
}
if (*input=='+' || *input=='-') {
	suffix = *input++;
}

		
 
section    top

while (numberAsterisks-->0) {
	Obj count = Tcl_NewIntObj(va_arg(args,int));
	Tcl_ListObjAppendList(0,list,count);
}

		
 
section    top
 
section    top

enum {i=1,u=2,r=3,s=4,n=5,y=6,z=7,i0=10,u0=20,r0=30,s0=40,n0=50,y0=60,z0=70};
enum {ii=i0+i,iu=i0+u,ir=i0+r,is=i0+s};
enum {ui=u0+i,uu=u0+u,ur=u0+r,us=u0+s};
enum {ri=r0+i,ru=r0+u,rr=r0+r};
enum {ss=s0+s};
enum {ns=n0+s};
enum {yi=y0+i,yu=y0+u,yr=y0+r,ys=y0+s};
enum {zi=z0+i,zu=z0+u,zr=z0+r,zs=z0+s};
#if defined(ASCII)
	static unsigned char baseType[] = {
		//a b c d e f g h i j k l m n o p q r s t u v w x y z
		0,0,0,0,0,r,0,r,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,i,0,0,0,0,0,0,0,
		0,0,0,i,i,r,r,r,0,i,0,0,0,0,n,i,0,0,z,s,0,u,0,0,i,y,0,0,0,0,0
	};
	enum {zerochar = '@',limitchar = 0x7f};
	#define printable(ch) (' '<=(ch) && (ch)<0x7F)
#else
	#error Unknown character set.
#endif
Obj arg; bool decrement;

		
 
section    top
Obj list—The list of values to given to the Tcl format.

Obj list = incr(Tcl_NewObj());

		
 
section    top

decr(list);

		
 
section    top
			
<Move asterisks varargs>
if (zerochar<=intype && intype<limitchar)
	intype1 = baseType[intype-zerochar];
if (zerochar<=outtype && outtype<limitchar)
	outtype1 = baseType[outtype-zerochar];
switch (10*intype1+outtype1) {
	case ii:	case iu:	case ir:
		<Move integer vararg to numeric>
		break;
	case ui:	case uu:	case ur:
		<Move unsigned vararg to numeric>
		break;
	case ri:	case ru:	case rr:
		<Move real vararg to numeric>
		break;
	case is:	case us:
		<Convert integer vararg to string>
		break;
	case ss:
		<Move string vararg to string>
		break;
	case ns:
		<Move counted string vararg to string>
		break;
	case yi:	case yu:	case yr:	case ys:
		<Move object vararg to list>
		break;
	case zi:	case zu:	case zr:	case zs:
		<Move result vararg to list>
		break;
	default: {
		char B[30];
		sprintf(B,"<invalid conversion: %c->%c>",intype,outtype);
		arg = Tcl_NewStringObj(B,-1); decrement = false;
	}	break;
}
Tcl_ListObjAppendElement(0,list,arg);
if (decrement) decr(arg);


		
 
section    top

switch (inmod) {
	case 0:
		arg = incr(Tcl_NewIntObj(va_arg(args,int)));
		decrement = true;
		break;
	case 1:
		arg = incr(Tcl_NewIntObj((short)va_arg(args,int)));
		decrement = true;
		break;
	case 2:
		arg = incr(Tcl_NewLongObj(va_arg(args,long)));
		decrement = true;
		break;
}

		
 
section    top

switch (inmod) {
	case 0:
		arg = incr(Tcl_NewIntObj((int)va_arg(args,unsigned)));
		decrement = true;
		break;
	case 1:
		arg = incr(Tcl_NewIntObj((int)(unsigned short)va_arg(args,unsigned)));
		decrement = true;
		break;
	case 2:
		arg = incr(Tcl_NewLongObj((long)va_arg(args,unsigned long)));
		decrement = true;
		break;
}

		
 
section    top

arg = incr(Tcl_NewDoubleObj(va_arg(args,double)));
decrement = true;

		
 
section    top

char conv[sizeof( unsigned long)+1],*pconv;
unsigned long ival;
int lival;

		
 
section    top

switch (intype1) {
	case i:
		switch (inmod) {
			case 0: ival = (unsigned long)va_arg(args,int); lival = sizeof(int); break;
			case 1: ival = (unsigned long)va_arg(args,int); lival = sizeof(int); break;
			case 2: ival = (unsigned long)va_arg(args,long); lival = sizeof(long); break;
		}
		break;
	case u:
		switch (inmod) {
			case 0: ival = (unsigned long)va_arg(args,unsigned); lival = sizeof(unsigned); break;
			case 1: ival = (unsigned long)va_arg(args,unsigned int); lival = sizeof(unsigned int); break;
			case 2: ival = (unsigned long)va_arg(args,unsigned long); lival = sizeof(unsigned long); break;
		}
		break;
}
pconv = conv+sizeof( unsigned long);
*pconv = 0; stringlen = 0;
while (pconv>conv && lival>0 && ival!=0) {
	*--pconv = ival; ival >>= 8; lival++; stringlen++;
}
string = pconv;
goto string;

		
 
section    top

chars string; int stringlen;

		
 
section    top

	string = va_arg(args,chars); stringlen = -1;
string:
	if (suffix=='+') {
		chars copy; int xstring;
		if (stringlen<0) stringlen = strlen(string);
		copy = nheap(stringlen,char);
		for (xstring=0; xstring<stringlen; xstring++) {
			copy[xstring] = printable(string[xstring]) ? string[xstring] : '.';
		}
		arg = incr(Tcl_NewStringObj(copy,stringlen));
		dispose(copy);
	} else {
		arg = incr(Tcl_NewStringObj(string,stringlen));
	}
	decrement = true;

		
 
section    top
 {
	stringlen = va_arg(args,int);
	stri