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