Page 1 of 2

Use of DOS Write command for writing to the console

Posted: Tue Sep 10, 2013 2:17 pm
by JosDuchIt
In Gui4Cli the "say" command originally allowed to write in colors to the console, to flash the screen etc
say '\#7' // flash screen
Say "\#155\1;33;40;>0mText is now color 3" // text was written in blue,

This is stll the case under OS4 when the script is interpreted with the 68k Gui4Cli interpreter.

I recently observed that this is not working anymore when the modified (PPC) source is compiled for OS4.
I have the impression that this was not the case earlier (with the same OS4 source, or earlier versions) and suspect something happened to the DOS Write function

The interpreter does simply this, taking as arguments the console pointer, the string to write and its length

case SAY : if (gf->cp) conout = gf->cp;
else conout = DEFcp;
Write (conout, marg[0].str, strlen(marg[0].str));
conout = ZERO; //OS4W was NULL
break;


It seems to me that the Write function previously detected the cases when writing was done to the console, and maybe used the CMD_WRITE console.h function
Am i right?
If yes is there a reason to this ?

Re: Use of DOS Write command for writing to the console

Posted: Tue Sep 10, 2013 3:28 pm
by tonyw
It's just a different path to the same destination.

If you printf() or IDOS->Printf() or IDOS->Write(), DOS creates a DOS Packet with the details and sends it to the con-handler, which in turn calls the console.device by using CMD_WRITE.
You can get the same effect by calling the console.device directly. You miss out on the context swaps that are a natural overhead of DOS operations, so dealing directly with the console.device is a bit faster than going through DOS.
On the other hand, by skipping the con-handler stage, you don't get any of the input editing functions, name or command expansion, etc.

I'm pretty sure that nothing has changed in the area you are talking about. You are talking about con-handler V53.1 and console.device V53.1, right? All the ANSI escape sequences are still there and work exactly the same from either DOS packets or direct device CMD_WRITE calls.

You can test these sequences by making up simple scripts and "Type-ing" them to the console. Use either the CSI code or the "ESC [" pair.

Re: Use of DOS Write command for writing to the console

Posted: Tue Sep 10, 2013 5:29 pm
by thomasrapp
tonyw wrote:Use either the ESC code or the "CSI [" pair.
This should read

Use either the CSI code or the "ESC [" pair".

CSI = 0x9b
ESC = 0x1b

Re: Use of DOS Write command for writing to the console

Posted: Tue Sep 10, 2013 8:30 pm
by JosDuchIt
I don't get it.

The source for 68k or PPC Gui4Cli "say" command" is unchanged
say '\#7' // flash screen works with 68k code, not with PPC code
Say "\#155\1;33;40;>0mText is now color 3" // text "Text is now color 3" was written in blue with 68k code, nothing appears with PPC code
Normal strings e.g:
say "hello\n hello again\n" // are printed correctly


Why should the same source code produce different results if nothing changed in the way Write is handling things?
Would the Write command recognise the strings \#7 and #155\1;33;40;>0m ?

Re: Use of DOS Write command for writing to the console

Posted: Tue Sep 10, 2013 10:18 pm
by thomasrapp
This page shows which character sequences are recognised by the console: http://wiki.amigaos.net/index.php/Conso ... dow_Output

I am quite sure that things like \# are not among it. You have to parse the string and replace \#155 by a single character with ASCII code 155 (that's the CSI) before you send it to Write(). I am also sure that this was necessary on OS 3, too. I never heard of \# before.

Re: Use of DOS Write command for writing to the console

Posted: Wed Sep 11, 2013 1:57 am
by tonyw
@Thomas: Thanks, edited the error.

@JosDuchIt:
Would the Write command recognise the strings \#7 and #155\1;33;40;>0m ?
No, it would simply print it verbatim on the screen. The replacement of escaped characters and embedded constant characters is all done by high-level functions like your interpreter.

As Thomas said, the use of the "#" as an escape character is new to me also. Is it possible that you are confusing it with the asterisk "*" character? The way DOS handles "*" characters has changed - you now need two (not just one) in commands, since a single "*" is absorbed as an escape character and to pass an actual "*", you need two of them. But to the console, an asterisk still is not going to mean anything special. It has to mean something special to your interpreter, which will modify it and translate it into something else for the console.

Re: Use of DOS Write command for writing to the console

Posted: Wed Sep 11, 2013 3:27 pm
by salass00
JosDuchIt wrote: The source for 68k or PPC Gui4Cli "say" command" is unchanged
say '\#7' // flash screen works with 68k code, not with PPC code
Say "\#155\1;33;40;>0mText is now color 3" // text "Text is now color 3" was written in blue with 68k code, nothing appears with
The following ruby code works just fine:
print 7.chr # Cause DisplayBeep()
puts 155.chr+"33;40;>0mText is now color 3" # Change color and print some text
print 155.chr+"0m" # Reset color

I would change it to ARexx but I don't know what the ARexx equivalent of chr() is.

As others have mentioned the \#number stuff means nothing to IDOS->Write() or con-handler/console.device for that matter. If the code you mention worked before then it's something in the say ARexx command that has changed or is broken.

Re: Use of DOS Write command for writing to the console

Posted: Wed Sep 11, 2013 3:45 pm
by thomasrapp
I don't know what the ARexx equivalent of chr() is.
d2c() (decimal to character)

There are c2d, c2x, x2c, x2d, d2x, too.
If the code you mention worked before then it's something in the say ARexx command that has changed or is broken.
The SAY above is not from ARexx. If ARexx did recognise \# I would expect this to return 9B instead:

Code: Select all

1> rx "say c2x('\#155')"
5C23313535
1>
BTW, in Rexx you don't need a function to convert from hexadecimal to character. You can just specify the hexadecimal number in quotes followed by an x.

Code: Select all

1> rx "say c2d('9b'x)"
155
1> rx "say '41'x"
A
1>

Re: Use of DOS Write command for writing to the console

Posted: Wed Sep 11, 2013 7:51 pm
by JosDuchIt
@ Tony & Thomas

Thanks for reactions




To make things clear: the following lines are Gui4Cl command lines not arexx or DOS
say '\#7' // no flash screen or beep
Say "\#155\1;33;40;>0mText is now color 3" // nothing is written with OS4 compile





Gui4Cli indeed translates an argument string for any command.

A Gui4Cli argument string may contain variables such as $myvar or $myvar[0][6] and \n \t escape sequences with standard effect;

A typical argument string to the Gui4Cli command "say" (not the arexx "say") is seen below

say "my age is $age\nMy name is $name"

for \# the doc of the translate() function (joined) states:
"if there is a number following it, read in decimal value, otherwise disregard it, allowing concatenation of variables., such as $var1\#$var2 "

This is which makes possible command lines and argument strings such as
say '\#7' // flash screen & beep
Say "\#155\1;33;40;>0mText is now color 3" // text "Text is now color 3" is written in blue (or whatever colo 3 is on the screen)


This is the function Gui4Cli uses

Code: Select all

translate (char *buff, int length)
{
	register UBYTE *p, *ba;
	UBYTE *bufa, *bufb, *baend, *pend;
	BOOL transflag, havetrans=0;
	BOOL havebrak=0, hashflag;
	LONG transloop = 0;		// check against gd->maxtransloop
	LONG lng;
	int num, adv;
	struct varparts *vp;

	vp = &gd->vparts;			// point to global varparts
	lng = (LONG)length;
	bufa = gd->membuff[1];	// gen buffers
	bufb = gd->membuff[2];	

	do
	{	transflag  = 0;
		havetrans  = 0;
		++transloop;
		pend  = &buff[length];   // end of src buff
		baend = &bufa[length-1]; // end of dest buff

		for (p=buff, ba=bufa; *p && (ba < baend); )
		{ 
		   switch (*p)
		   {
				case '$' :										// VARIABLES
		  			// keep bracketed expressions for the end - after the 1st
		  			// pass and after all variables have been translated
		  			if (p[1] == '(')
		  			{	havebrak = 1;
		  				*ba = *p; ++ba; ++p;
		  				*ba = *p; ++ba; ++p;
		  			}
		  			else											// Read in var name
		  			{	havetrans = 1;

						// Printf ("==========\nHave variable : %s\n\tSending : %s\n\ttransloop=%ld\n",
						//		p, &p[1], transloop);

						if (!(p = transvar (&p[1], ba, baend-ba)))
							return (0);

						// Printf ("====>> After Transvar: %s\n", ba);

						while (*ba)								// go after var contents..
		  				{	if (*ba=='$') transflag = 1;	// checking for varINvar
							++ba;
		  			}	}
		  			break;

				case '\\':
		  			++p;
		  			havetrans = 1;
		  			hashflag  = 0; 
		  			switch (*p)
		  			{	case '\'': *ba='\''; break;
						case 'n'	: *ba='\n'; break;
						case 't'	: *ba='\t'; break;
						case 'r'	: *ba='\r'; break;
						case '$'	: *ba='$' ; break;
						case '"'	: *ba='"' ; break;
						case '\\': *ba='\\'; break;
						case '#'	: // if there is a number following it, read
						  			  // in decimal value, otherwise disregard it
						  			  // allowing concatenation of variables.
						  			  if (!(adv = stcd_i(&p[1], &num)))
						  			  {  hashflag = 1; // to stop ++ba..
						  			  }
						  			  else
						  			  {  *ba=num;
						  				  p += adv; // skip number
						  			  }
						  			  break;
						default	: *ba = *p; break;
		  			};
		  			++p;
		  			if (!hashflag) ++ba;
		  			break;

				default	 :
		  			*ba = *p;
		  			++ba; ++p;
		  			break;
		   };
		}

		if (ba >= baend) 
		{	myerror (NULL, ERR_BUFF, 0, "\nTranslated string too long");
			*buff = 0;  // null the buffer & return it
			return(0);
		}

		*ba = 0;

		if (havebrak)
		{	// if there are no more $ in string - goto eval.h & return
			if (!transflag) return (dobrak (bufa, bufb, buff));
		}
		else // if no translation was done, return old buff as is..
			if (!havetrans) return (1);

		// continue with parsing..
		strcpy (buff, bufa);

		// return if deeptrans is off
		if (gd->flags & gd_nodeeptrans)
		  	return (1);
		if (transloop > gd->maxtransloop)		 // trans is in wild loop..
		{	Printf ("**ERROR: Can not translate %s\nSet MaxTransLoop higher.\n", buff);
		  	*buff = 0;
		  	return (0);
		}

	} while (transflag);

	return (1);
}

This code is essentially the same for 68k & PPC (i did not modify it). The original 68k Gui4Cli sill reacts correctly under OS4
but with OS4 compile



say '\#7' // no flash screen or beep
Say "\#155\1;33;40;>0mText is now color 3" // nothing is written with OS4 compile

Given my understanding of the translate() function the '\#7' gui4cli string is translated to the unprintable character decimal 7 and thus presented to the Write() function.
The translated gui4cli string "\#155\1;33;40;>0mText is now color 3" presented to the Writ() function will be the unprintable decimal character 155 followed by the sequence "\1;33;40;>0mText is now color 3"
It should change the color and print the line "Text is now color 3"

I still don't see what is going wrong


I also looked into
file:///Datas:Manual/dos/book-main114.html
Esc[33m => switches on to blue , works OK
comparable to
Say "\#155\1;33;40;>0mText is now color 3" as with original 68k source
I also don't see where the 33 value in Esc[33m comes from

Bell or beep is not mentioned here, anybody ?

Re: Use of DOS Write command for writing to the console

Posted: Wed Sep 11, 2013 9:51 pm
by thomasrapp
The relevant part begins after case '#':. The stcd_i function (which you did not quote) is probably the culprit.

Check the link I gave above, it explains how ANSI sequences are built up. The 33 in Esc[33m is the same as the 33 in your SAY command.