[net.unix] tgetstr on system V R2

lav@mtsbb.UUCP (L.A.VALLONE) (07/18/86)

    I am trying to get a recently posted reminder program (rs)
to run on my machine (VAX 11/780 running Sys V R2).  The program
seems to run okay, except that all calls to tgetstr() do not
return the correct escape sequence (they return null).

    The sequence being used is:
	tgetent(bp, terminal name)  /* works fine - return of 1 */
	tgetnum("co")		    /* works fine - returns 80 */
	tgetstr("so",&some_buffer) or
	tgetstr("bl",&some_buffer) or anything else
				    /* returns 0's in buffer */

    The program is compiled loading the terminfo/curses library
(-lcurses the /usr/lib/libtermcap file on my machine bombs).  All the
documentation seems to indicate, that at least for the present,
the above should work.

    Does anyone know why it doesn't?  Am I doing something wrong?
Please respond via email.
-- 

Lee Vallone		AT&T Information Systems	Merlin
{... ihnp4, mtuxo}!mtsbb!lav

guy@sun.UUCP (07/18/86)

>     I am trying to get a recently posted reminder program (rs)
> to run on my machine (VAX 11/780 running Sys V R2).  The program
> seems to run okay, except that all calls to tgetstr() do not
> return the correct escape sequence (they return null).
> 
>     The sequence being used is:
> 	tgetent(bp, terminal name)  /* works fine - return of 1 */
> 	tgetnum("co")		    /* works fine - returns 80 */
> 	tgetstr("so",&some_buffer) or
> 	tgetstr("bl",&some_buffer) or anything else
> 				    /* returns 0's in buffer */
> 
>     The program is compiled loading the terminfo/curses library
> (-lcurses the /usr/lib/libtermcap file on my machine bombs).

As it should.  The "curses" that was first publicly released in S5R2
uses the "terminfo" stuff, and contains routines to emulate "termcap"
routines.  Linking it with "termcap" is unnecessary and erroneous.

> All the documentation seems to indicate, that at least for the present,
> the above should work.
> 
>     Does anyone know why it doesn't?  Am I doing something wrong?

The documentation I have for S5R2 says precious little about "tgetstr",
except that it's a "termcap compatibility routine".  The 4BSD documentation,
unfortunately, indicates that it stuffs the string value into the area
pointed to by the pointer pointed to by its second argument (note - that
argument isn't a "pointer to 'char'", it's a "pointer to pointer to
'char'"), and does *not* indicate that it also returns a pointer to the
string value in question.  The trouble with this is that it causes people to
write non-portable code that only works with the "termcap" package, and not
with "terminfo", because they think of "tgetstr" as a routine that fills in
a buffer, not one that returns the item gotten (as do "tgetnum" and
"tgetflag".

The only reason why "tgetstr" takes that second argument is so it has some
place to stuff the string value.  The intent was that the programmer'd
allocate a big buffer to hold all the strings, declare a "char *" variable
and initialize it to point to the first character in that buffer, and pass a
pointer to that "char *" to "tgetstr".  "tgetstr" would stuff a string at
that location, and step that pointer to point to the next available location
in the buffer, so that the next call to "tgetstr" would stick the string
after it.

"terminfo" works differently from "termcap".  It reads in a huge block of
compiled data that includes all the strings, and includes a structure
containing all the values from the "terminfo" entry.  The structure members
are "int"s (for entries gotten with "tgetnum"), some representation of a
Boolean type (for entries gotten with "tgetflag"), and pointers into the
string area (for entries gotten with "tgetstr").  The "tgetstr" routine just
maps the code given to it into one of those character pointers, and returns
it; it *ignores* its second argument.  (The S5R2 version of "tgetstr", in
fact, improperly declares the second argument as "char *" rather than "char
**".)

As such:

	1) The code given above for "tgetstr" looks wrong; it should pass
	   a pointer to a pointer to the buffer, not (as it seems to)
	   a pointer to the buffer.  The latter wouldn't work with the
	   old "termcap" version.

	2) The code should grab the return value of "tgetstr" and use
	   that, rather than assuming that "tgetstr" will fill in
	   the buffer with the string.

	3) Programs writtern for "termcap" should use the "tget" routines
	   in the manner described, so that they will be more likely to
	   work with "terminfo".

	4) The "terminfo" "tgetstr" routine should, perhaps, copy the
	   string to the buffer pointed to by the pointer pointed to
	   by its second argument, and bump that pointer, so that
	   programs written in the other fashion will still work.
	   The S5R2 one isn't written in that fashion, though, so
	   you'll probably never be able to count on that.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com (or guy@sun.arpa)

lvs@ndm20.UUCP (07/21/86)

>    I am trying to get a recently posted reminder program (rs)
>to run on my machine (VAX 11/780 running Sys V R2).  The program
>seems to run okay, except that all calls to tgetstr() do not
>return the correct escape sequence (they return null).
>
>    The sequence being used is:
>	tgetent(bp, terminal name)  /* works fine - return of 1 */
>	tgetnum("co")		    /* works fine - returns 80 */
>	tgetstr("so",&some_buffer) or
>	tgetstr("bl",&some_buffer) or anything else
>				    /* returns 0's in buffer */
>
>    Does anyone know why it doesn't?  Am I doing something wrong?
>Please respond via email.
>
>Lee Vallone		AT&T Information Systems	Merlin
>{... ihnp4, mtuxo}!mtsbb!lav

No, you are not doing anything wrong, AT&T is!  They  have broken the
way  tgetent  and  tgetstr  work.   The only  help you  get from AT&T
software support is "Sorry,  we don't  support termcap  anymore".  Oh
well, so it goes.

The original definition for tgetstr was

   char *tgetstr( char *code, char **bufptr )

tgetstr would  get the  string you  desired (if  it can  find it) and
place it in your buffer, supplied  by bufptr.   It  would then update
bufptr  to point  just beyond  the string  just added  and return the
original value  of the  buffer pointer  (unless the  code couldn't be
found in which case it returns NULL).

Well, so much for the way it  SHOULD work.   The  version supplied by
AT&T in SVR2 is just plain broken.  It  does nothing  with the buffer
you supply  it, nor  does it  update the  pointer.   The only usefull
information is the return value.  If it is not NULL it  will point to
the string you requested.  Therefore, you must save  the return value
from the call, that is you can't use bufptr because  it doesn't point
to the string.  If you want the strings in a buffer you  will have to
copy them into it yourself.

Alas, it seems AT&T has broken termcap and instead of fixing it, they
decided not to support it.

BTW, the machine I have checked this  on is  an AT&T  PC6300PLUS.  It
exibited the same problems you described.  It  now works  by doing it
the way I described above.

Hope this helps,
Larry V. Streepy Jr.                        "Waiting is"
Nathan D. Maier Consulting Engineers

VOICE:  (214)739-4741
Usenet: {seismo!c1east | cbosgd!sun | ihnp4}!convex!infoswx!ndm20!lvs
CSNET:  ndm20!lvs@smu
ARPA:   ndm20!lvs%smu@csnet-relay.ARPA