/* TERMLIB: Terminal independant database.
 *
 * Module: tgoto
 *
 * Purpose: decode cm cursor motion string.
 *
 * Calling conventions: cm is cursor motion string.
 *			line, col, are the desired destination.
 *
 * Returned values: a string pointing to the decoded string, or
 *		    "OOPS" if it cannot be decoded.
 *
 * Notes
 *		The accepted escapes are:
 *			%d	 as in printf, 0 origin.
 *			%2, %3	 like %02d, %03d in printf.
 *			%.	 like %c
 *			%+x	 adds <x> to value, then %.
 *			%>xy	 if value>x, adds y. No output.
 *			%i	 increments line& col, no output.
 *			%r	 reverses order of line&col. No output.
 *			%%	 prints as a single %.
 *			%n	 exclusive or row & col with 0140.
 *			%B	 BCD, no output.
 *			%D	 reverse coding (x-2*(x%16)), no output.
 */
#include <stdio.h>
#include <ctype.h>
#include "termlib.h"

/* tgoto.c (libtermlib.a)
 *
 */

char *
tgoto(cm, col, line)
char	*cm;                                      /* cm string, from termcap */
int	col,                                           /* column, x position */
	line;                                            /* line, y position */
{
	char	*_addfmt(),
		gx, gy,                                           /*    x, y */
		*ptr,                                     /* pointer in 'cm' */
		reverse = 0,                                 /* reverse flag */
		*bufp,                         /* pointer in returned string */
		addup = 0,                                     /* add upline */
		addbak = 0,                                    /* add backup */
		c;
	static char buffer[32];

	if(!cm)
		return "OOPS";                       /* Kludge, but standard */

	bufp = buffer;
	ptr = cm;

	while(*ptr) {
		if((c = *ptr++) != '%') {                     /* normal char */
			*bufp++ = c;
		} else {                                         /* % escape */
			switch(c = *ptr++) {
			case 'd':                                 /* decimal */
				bufp = _addfmt(bufp, "%d", line);
				line = col;
				break;
			case '2':                         /* 2 digit decimal */
				bufp = _addfmt(bufp, "%02d", line);
				line = col;
				break;
			case '3':                         /* 3 digit decimal */
				bufp = _addfmt(bufp, "%03d", line);
				line = col;
				break;
			case '>':                      /* %>xy: if >x, add y */
				gx = *ptr++;
				gy = *ptr++;
				if(col>gx) col += gy;
				if(line>gx) line += gy;
				break;
			case '+':                              /* %+c: add c */
				line += *ptr++;
			case '.':                               /* print x/y */
				if(line=='\t' ||                /* these are */
				   line == '\n' ||             /* chars that */
				   line=='\004' ||             /* UNIX hates */
				   line=='\0') {
					line++;         /* so go to next pos */
					if(reverse==(line==col))
						addup=1;      /* and mark UP */
					else
						addbak=1;           /* or BC */
				}
				*bufp++=line;
				line = col;
				break;
			case 'r':                              /* r: reverse */
				gx = line; 
				line = col; 
				col = gx;
				reverse = 1;
				break;
			case 'i':             /* increment (1-origin screen) */
				col++;
				line++;
				break;
			case '%':                          /* %%=% literally */
				*bufp++='%';
				break;
			case 'n':                       /* magic DM2500 code */
				line ^= 0140;
				col ^= 0140;
				break;
			case 'B':                            /* bcd encoding */
				line = line/10<<4+line%10;
				col = col/10<<4+col%10;
				break;
			case 'D':                   /* magic Delta Data code */
				line = line-2*(line&15);
				col = col-2*(col&15);
				break;
			default:                           /* Unknown escape */
				return "OOPS";
			}
		}
	}

	if(addup)                                              /* add upline */
		if(UP) {
			ptr=UP;
			while(isdigit(*ptr) || *ptr=='.')
				ptr++;
			if(*ptr=='*')
				ptr++;
			while(*ptr)
				*bufp++ = *ptr++;
		}

	if(addbak)                                          /* add backspace */
		if(BC) {
			ptr=BC;
			while(isdigit(*ptr) || *ptr=='.')
				ptr++;
			if(*ptr=='*')
				ptr++;
			while(*ptr)
				*bufp++ = *ptr++;
		} 
		else
			*bufp++='\b';

	*bufp = 0;

	return(buffer);
}
