[net.unix-wizards] -ltermcap

shawn@mit-eddie.MIT.EDU (Shawn F. Mckay) (08/03/86)

Greetings. I am having great problems with termcap. Has anyone out there
ever figured out how this works for simple applications?

For example, I want the 'cl' codes for a given terminal type, and don't
wan't to have to write a 500 page library like curses to get it.

On the other hand, I would rather not write my own termcap.

One would think I could say something like:

char	buff[20];

	tgetstr ("cl", buff);

And have it use the buffer it retreived from the call to tgetent() to find
my capability. But, no, this would be too easy. Is there some simple, and
fast way to get this result? I would also not mind being pointed to some
useful documentation on termcap, since I have NEVER seen anything that
documents it very clearly.

And No, the source code doesn't help, it only adds to the documentation
problem.

			Thanks for any help.
			  - Shawn

dave@rsch.wisc.edu (Dave Cohrs) (08/03/86)

In article <2773@mit-eddie.MIT.EDU>
shawn@mit-eddie.MIT.EDU (Shawn F. Mckay) writes:
>One would think I could say something like:
>
>char	buff[20];
>
>	tgetstr ("cl", buff);

Read the termcap(3) man page more carefully.  The declaration for
tgetstr is:

	char *
	tgetstr(id, area)
	char *id, **area;

Note the '**area'.  So you want to do:

{
	char buff[20];
	char *bufptr = buff;

	(void) tgetstr("cl", &bufptr);
}

The man page also says 'it advances area', which is why you must assign
buff to bufptr.

--
Dave Cohrs
(608) 262-1204
..!{harvard,ihnp4,seismo,topaz}!uwvax!dave
dave@rsch.wisc.edu

chris@umcp-cs.UUCP (Chris Torek) (08/04/86)

>In article <2773@mit-eddie.MIT.EDU> shawn@mit-eddie.MIT.EDU
>(Shawn F. Mckay) writes:
>>One would think I could say something like:
>>
>>char	buff[20];
>>	tgetstr ("cl", buff);

In article <2565@rsch.wisc.edu> dave@rsch.wisc.edu (Dave Cohrs) replies:
>Read the termcap(3) man page more carefully. ...  So you want to do:
>
>	char buff[20];
>	char *bufptr = buff;
>	(void) tgetstr("cl", &bufptr);

Closer; but it is worse than that.  Termcap's design is quite messy
and error-prone.  I once outlined a better design, but have never
bothered to implement it.

Termcap first requires that you copy the terminal capability string
into a buffer.  It then interprets the copied string into another
buffer.  Both buffers are `owned' by you but `taken over' by termcap;
the first must last through all tget* calls, and the second as long
as you wish to use the decoded strings.  The following is pretty
much the minimum code required to obtain just the clear screen
entry:

#ifdef this_works_but_is_not_a_good_idea_anyway

char	*getenv();

char *
get_clear_screen()
{
	char tbuf[1024];		/* used only during interpretation */
	static char expbuf[1024];	/* stores interpreted strings */
	char *ep;			/* pointer into expbuf */
	char *term;

	if ((term = getenv("TERM")) == NULL)
		return (NULL);		/* terminal type unavailable */

	/* -1 => no termcap file; 0 => termcap file but $TERM not found */
	if (tgetent(tbuf, term) != 1)
		return (NULL);		/* failed for some reason */
	ep = expbuf;
	return (tgetstr("cl", &ep));
}

#endif

#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>

/*
 * Before you can use `cl', you must also set `ospeed' and `PC':
 */
extern short ospeed;
extern char PC;

/*
 * ospeed should be set to the output speed of the terminal, as
 * returned by gtty() / ioctl(TIOCGETP).  PC should be set to
 * the terminal's pad character (result from tgetstr("pc")),
 * or the default, NUL ('\0').  Note that tgetstr("pc") either
 * returns NULL (in which case PC should be '\0') or a pointer
 * which must be dereferenced to get the pad character.
 *
 * For this reason, the `get_clear_screen' routine defined above
 * is pretty much useless anyway.  Instead, you need something
 * more like this:
 */

static char tbuf[1024];		/* for intermediate results */
static char expbuf[1024];	/* for expanded (decoded) strings */
static char *expp;		/* pointer into expbuf */

static int started_tc;		/* true => got termcap started */
static int no_tc;		/* true => termcap unavailable */

char	*getenv();

#define	start_tc()	if (started_tc) /*void*/; else fire_up_termcap()

/*
 * Set things up so that tgetent() et al. are OK
 */
static void
fire_up_termcap()
{
	char *term;
	struct sgttyb sg;

	started_tc++;			/* well, soon */
	if ((term = getenv("TERM")) == NULL || tgetent(tbuf, term) != 1) {
		no_tc++;		/* no termcap available */
		return;
	}
	expp = expbuf;			/* init expansion pointer *?
	if (ioctl(0, TIOCGETP, &sg))
		ospeed = B1200;		/* just a guess */
	else
		ospeed = sg.sg_ospeed;
}

/*
 * Wrapper for tgetstr().
 */
char *
get_termcap_string(name)
	char *name;
{

	start_tc();
	return (no_tc ? NULL : tgetstr(name, &expp));
}

/*
 * Get the clear screen entry, and set up the pad character so that
 * we can use it.
 */
char *
get_clear_screen()
{
	char *p;

	if ((p = get_termcap_string("pc")) != NULL)
		PC = *p;
	return (get_termcap_string("cl"));
}

/*
 * This can now be printed via
 *
 *	int outc(c) int c; { return (putchar(c)); }
 *	...
 *	p = get_clear_screen();
 *	tputs(p, 1, outc);
 *
 */

/*
 * For good measure, some interface routines for other termcap things,
 * and an `outc' routine:
 */
int
outc(c)
	int c;
{

	return (putchar(c));
}

/*
 * Wrapper for tgetnum().
 */
int
get_termcap_number(name)
	char *name;
{

	start_tc();
	return (no_tc ? -1 : tgetnum(name));
}

/*
 * Wrapper for tgetflag().
 */
int
get_termcap_flag(name)
	char *name;
{

	start_tc();
	return (no_tc ? 0 : tgetflag(name));
}
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

greg@ncr-sd.UUCP (Greg Noel) (08/05/86)

In article <2565@rsch.wisc.edu> dave@rsch.wisc.edu (Dave Cohrs), answering
an article from shawn@mit-eddie.MIT.EDU (Shawn F. Mckay), writes:
>....  The declaration for tgetstr is:
>	char * tgetstr(id, area)
>	char *id, **area;
>Note the '**area'.  So you want to do:
>{
>	char buff[20];
>	char *bufptr = buff;
>	(void) tgetstr("cl", &bufptr);
>}

Almost right.  The advance of the buffer pointer is actually a \side-effect/,
and not the value (the semantic result) of the function.  It is documented the
way it is so that programmers will be sure to allocate enough space to hold
any strings that tgetstr \might/ wish to store there, but it is the return
value from tgetstr that must be used for the string.  That is, you need to say:
	char buff[20];
	char *bufptr = buff;
	char *cl_ptr;
	cl_ptr = tgetstr("cl", &bufptr);
This will make the code compatible with the SysV terminfo emulation of termcap,
which has its own area for storing the strings, and doesn't copy them into the
buffer or update the pointer.
-- 
-- Greg Noel, NCR Rancho Bernardo    Greg@ncr-sd.UUCP or Greg@nosc.ARPA

lvs@ndm20.UUCP (08/06/86)

>In article <2773@mit-eddie.MIT.EDU>
>shawn@mit-eddie.MIT.EDU (Shawn F. Mckay) writes:
>>One would think I could say something like:
>>
>>char	buff[20];
>>
>>	tgetstr ("cl", buff);
>
>Read the termcap(3) man page more carefully.  The declaration for
>tgetstr is:
>
>	char *
>	tgetstr(id, area)
>	char *id, **area;
>
>Note the '**area'.  So you want to do:
>
>  [some more stuff]
>
>The man page also says 'it advances area', which is why you must assign
>buff to bufptr.
>--
>Dave Cohrs
>dave@rsch.wisc.edu

Note that this is not true for the AT&T SV release 2 version of termcap.
They supply termcap routines "strictly for compatibility", and they don't
work like the originals.  In specific:

    tgetent() places NO data in the buffer you supply it
    tgetstr() ignores the buffer pointer you give.

So, when using tgetstr, you MUST save and use the return value of the
function as it returns a pointer to the capability string if found, or NULL
if not found.  Fo example:

   char *tgetstr();
   char *cl_str;
   char junkbuff;
   char *bogus_ptr = &junkbuff;
   
   if( (cl_str = tgetstr( "cl", bogus_ptr )) == NULL ) {
      handle missing capability
   }
   else {
      handle success, fame, and fortune :-)
   }

I have found this to be true on the PC6300PLUS, but I think it holds true
elsewhere also.


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