1/* Merge parameters into a termcap entry string.
2   Copyright (C) 1985, 87, 93, 95, 2000 Free Software Foundation, Inc.
3
4This program is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation; either version 2, or (at your option)
7any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; see the file COPYING.  If not, write to
16the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17Boston, MA 02111-1307, USA.  */
18
19/* Emacs config.h may rename various library functions such as malloc.  */
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#ifdef emacs
25#include "lisp.h"		/* for xmalloc */
26#else
27
28#ifdef STDC_HEADERS
29#include <stdlib.h>
30#include <string.h>
31#else
32char *malloc ();
33char *realloc ();
34#endif
35
36/* Do this after the include, in case string.h prototypes bcopy.  */
37#if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
38#define bcopy(s, d, n) memcpy ((d), (s), (n))
39#endif
40
41#endif /* not emacs */
42
43#ifndef NULL
44#define NULL (char *) 0
45#endif
46
47#ifndef emacs
48static void
49memory_out ()
50{
51  write (2, "virtual memory exhausted\n", 25);
52  exit (1);
53}
54
55static char *
56xmalloc (size)
57     unsigned size;
58{
59  register char *tem = malloc (size);
60
61  if (!tem)
62    memory_out ();
63  return tem;
64}
65
66static char *
67xrealloc (ptr, size)
68     char *ptr;
69     unsigned size;
70{
71  register char *tem = realloc (ptr, size);
72
73  if (!tem)
74    memory_out ();
75  return tem;
76}
77#endif /* not emacs */
78
79/* Assuming STRING is the value of a termcap string entry
80   containing `%' constructs to expand parameters,
81   merge in parameter values and store result in block OUTSTRING points to.
82   LEN is the length of OUTSTRING.  If more space is needed,
83   a block is allocated with `malloc'.
84
85   The value returned is the address of the resulting string.
86   This may be OUTSTRING or may be the address of a block got with `malloc'.
87   In the latter case, the caller must free the block.
88
89   The fourth and following args to tparam serve as the parameter values.  */
90
91static char *tparam1 ();
92
93/* VARARGS 2 */
94char *
95tparam (string, outstring, len, arg0, arg1, arg2, arg3)
96     char *string;
97     char *outstring;
98     int len;
99     int arg0, arg1, arg2, arg3;
100{
101  int arg[4];
102
103  arg[0] = arg0;
104  arg[1] = arg1;
105  arg[2] = arg2;
106  arg[3] = arg3;
107  return tparam1 (string, outstring, len, NULL, NULL, arg);
108}
109
110char *BC;
111char *UP;
112
113static char tgoto_buf[50];
114
115char *
116tgoto (cm, hpos, vpos)
117     char *cm;
118     int hpos, vpos;
119{
120  int args[2];
121  if (!cm)
122    return NULL;
123  args[0] = vpos;
124  args[1] = hpos;
125  return tparam1 (cm, tgoto_buf, 50, UP, BC, args);
126}
127
128static char *
129tparam1 (string, outstring, len, up, left, argp)
130     char *string;
131     char *outstring;
132     int len;
133     char *up, *left;
134     register int *argp;
135{
136  register int c;
137  register char *p = string;
138  register char *op = outstring;
139  char *outend;
140  int outlen = 0;
141
142  register int tem;
143  int *old_argp = argp;
144  int doleft = 0;
145  int doup = 0;
146
147  outend = outstring + len;
148
149  while (1)
150    {
151      /* If the buffer might be too short, make it bigger.  */
152      if (op + 5 >= outend)
153	{
154	  register char *new;
155	  int offset = op - outstring;
156
157	  if (outlen == 0)
158	    {
159	      outlen = len + 40;
160	      new = (char *) xmalloc (outlen);
161	      bcopy (outstring, new, offset);
162	    }
163	  else
164	    {
165	      outlen *= 2;
166	      new = (char *) xrealloc (outstring, outlen);
167	    }
168
169	  op = new + offset;
170	  outend = new + outlen;
171	  outstring = new;
172	}
173      c = *p++;
174      if (!c)
175	break;
176      if (c == '%')
177	{
178	  c = *p++;
179	  tem = *argp;
180	  switch (c)
181	    {
182	    case 'd':		/* %d means output in decimal.  */
183	      if (tem < 10)
184		goto onedigit;
185	      if (tem < 100)
186		goto twodigit;
187	    case '3':		/* %3 means output in decimal, 3 digits.  */
188	      if (tem > 999)
189		{
190		  *op++ = tem / 1000 + '0';
191		  tem %= 1000;
192		}
193	      *op++ = tem / 100 + '0';
194	    case '2':		/* %2 means output in decimal, 2 digits.  */
195	    twodigit:
196	      tem %= 100;
197	      *op++ = tem / 10 + '0';
198	    onedigit:
199	      *op++ = tem % 10 + '0';
200	      argp++;
201	      break;
202
203	    case 'C':
204	      /* For c-100: print quotient of value by 96, if nonzero,
205		 then do like %+.  */
206	      if (tem >= 96)
207		{
208		  *op++ = tem / 96;
209		  tem %= 96;
210		}
211	    case '+':		/* %+x means add character code of char x.  */
212	      tem += *p++;
213	    case '.':		/* %. means output as character.  */
214	      if (left)
215		{
216		  /* If want to forbid output of 0 and \n and \t,
217		     and this is one of them, increment it.  */
218		  while (tem == 0 || tem == '\n' || tem == '\t')
219		    {
220		      tem++;
221		      if (argp == old_argp)
222			doup++, outend -= strlen (up);
223		      else
224			doleft++, outend -= strlen (left);
225		    }
226		}
227	      *op++ = tem ? tem : 0200;
228	    case 'f':		/* %f means discard next arg.  */
229	      argp++;
230	      break;
231
232	    case 'b':		/* %b means back up one arg (and re-use it).  */
233	      argp--;
234	      break;
235
236	    case 'r':		/* %r means interchange following two args.  */
237	      argp[0] = argp[1];
238	      argp[1] = tem;
239	      old_argp++;
240	      break;
241
242	    case '>':		/* %>xy means if arg is > char code of x, */
243	      if (argp[0] > *p++) /* then add char code of y to the arg, */
244		argp[0] += *p;	/* and in any case don't output.  */
245	      p++;		/* Leave the arg to be output later.  */
246	      break;
247
248	    case 'a':		/* %a means arithmetic.  */
249	      /* Next character says what operation.
250		 Add or subtract either a constant or some other arg.  */
251	      /* First following character is + to add or - to subtract
252		 or = to assign.  */
253	      /* Next following char is 'p' and an arg spec
254		 (0100 plus position of that arg relative to this one)
255		 or 'c' and a constant stored in a character.  */
256	      tem = p[2] & 0177;
257	      if (p[1] == 'p')
258		tem = argp[tem - 0100];
259	      if (p[0] == '-')
260		argp[0] -= tem;
261	      else if (p[0] == '+')
262		argp[0] += tem;
263	      else if (p[0] == '*')
264		argp[0] *= tem;
265	      else if (p[0] == '/')
266		argp[0] /= tem;
267	      else
268		argp[0] = tem;
269
270	      p += 3;
271	      break;
272
273	    case 'i':		/* %i means add one to arg, */
274	      argp[0] ++;	/* and leave it to be output later.  */
275	      argp[1] ++;	/* Increment the following arg, too!  */
276	      break;
277
278	    case '%':		/* %% means output %; no arg.  */
279	      goto ordinary;
280
281	    case 'n':		/* %n means xor each of next two args with 140.  */
282	      argp[0] ^= 0140;
283	      argp[1] ^= 0140;
284	      break;
285
286	    case 'm':		/* %m means xor each of next two args with 177.  */
287	      argp[0] ^= 0177;
288	      argp[1] ^= 0177;
289	      break;
290
291	    case 'B':		/* %B means express arg as BCD char code.  */
292	      argp[0] += 6 * (tem / 10);
293	      break;
294
295	    case 'D':		/* %D means weird Delta Data transformation.  */
296	      argp[0] -= 2 * (tem % 16);
297	      break;
298
299	    default:
300	      abort ();
301	    }
302	}
303      else
304	/* Ordinary character in the argument string.  */
305      ordinary:
306	*op++ = c;
307    }
308  *op = 0;
309  while (doup-- > 0)
310    strcat (op, up);
311  while (doleft-- > 0)
312    strcat (op, left);
313  return outstring;
314}
315
316#if 0
317
318main (argc, argv)
319     int argc;
320     char **argv;
321{
322  char buf[50];
323  int args[3];
324  args[0] = atoi (argv[2]);
325  args[1] = atoi (argv[3]);
326  args[2] = atoi (argv[4]);
327  tparam1 (argv[1], buf, "LEFT", "UP", args);
328  printf ("%s\n", buf);
329  return 0;
330}
331
332#endif
333