Imported from ../bash-2.0.tar.gz.
[platform/upstream/bash.git] / lib / termcap / tparam.c
1 /* Merge parameters into a termcap entry string.
2    Copyright (C) 1985, 87, 93, 95 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   int arg[4];
96
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 }
103
104 char *BC;
105 char *UP;
106
107 static char tgoto_buf[50];
108
109 char *
110 tgoto (cm, hpos, vpos)
111      char *cm;
112      int hpos, vpos;
113 {
114   int args[2];
115   if (!cm)
116     return NULL;
117   args[0] = vpos;
118   args[1] = hpos;
119   return tparam1 (cm, tgoto_buf, 50, UP, BC, args);
120 }
121
122 static char *
123 tparam1 (string, outstring, len, up, left, argp)
124      char *string;
125      char *outstring;
126      int len;
127      char *up, *left;
128      register int *argp;
129 {
130   register int c;
131   register char *p = string;
132   register char *op = outstring;
133   char *outend;
134   int outlen = 0;
135
136   register int tem;
137   int *old_argp = argp;
138   int doleft = 0;
139   int doup = 0;
140
141   outend = outstring + len;
142
143   while (1)
144     {
145       /* If the buffer might be too short, make it bigger.  */
146       if (op + 5 >= outend)
147         {
148           register char *new;
149           if (outlen == 0)
150             {
151               outlen = len + 40;
152               new = (char *) xmalloc (outlen);
153               outend += 40;
154               bcopy (outstring, new, op - outstring);
155             }
156           else
157             {
158               outend += outlen;
159               outlen *= 2;
160               new = (char *) xrealloc (outstring, outlen);
161             }
162           op += new - outstring;
163           outend += new - outstring;
164           outstring = new;
165         }
166       c = *p++;
167       if (!c)
168         break;
169       if (c == '%')
170         {
171           c = *p++;
172           tem = *argp;
173           switch (c)
174             {
175             case 'd':           /* %d means output in decimal.  */
176               if (tem < 10)
177                 goto onedigit;
178               if (tem < 100)
179                 goto twodigit;
180             case '3':           /* %3 means output in decimal, 3 digits.  */
181               if (tem > 999)
182                 {
183                   *op++ = tem / 1000 + '0';
184                   tem %= 1000;
185                 }
186               *op++ = tem / 100 + '0';
187             case '2':           /* %2 means output in decimal, 2 digits.  */
188             twodigit:
189               tem %= 100;
190               *op++ = tem / 10 + '0';
191             onedigit:
192               *op++ = tem % 10 + '0';
193               argp++;
194               break;
195
196             case 'C':
197               /* For c-100: print quotient of value by 96, if nonzero,
198                  then do like %+.  */
199               if (tem >= 96)
200                 {
201                   *op++ = tem / 96;
202                   tem %= 96;
203                 }
204             case '+':           /* %+x means add character code of char x.  */
205               tem += *p++;
206             case '.':           /* %. means output as character.  */
207               if (left)
208                 {
209                   /* If want to forbid output of 0 and \n and \t,
210                      and this is one of them, increment it.  */
211                   while (tem == 0 || tem == '\n' || tem == '\t')
212                     {
213                       tem++;
214                       if (argp == old_argp)
215                         doup++, outend -= strlen (up);
216                       else
217                         doleft++, outend -= strlen (left);
218                     }
219                 }
220               *op++ = tem ? tem : 0200;
221             case 'f':           /* %f means discard next arg.  */
222               argp++;
223               break;
224
225             case 'b':           /* %b means back up one arg (and re-use it).  */
226               argp--;
227               break;
228
229             case 'r':           /* %r means interchange following two args.  */
230               argp[0] = argp[1];
231               argp[1] = tem;
232               old_argp++;
233               break;
234
235             case '>':           /* %>xy means if arg is > char code of x, */
236               if (argp[0] > *p++) /* then add char code of y to the arg, */
237                 argp[0] += *p;  /* and in any case don't output.  */
238               p++;              /* Leave the arg to be output later.  */
239               break;
240
241             case 'a':           /* %a means arithmetic.  */
242               /* Next character says what operation.
243                  Add or subtract either a constant or some other arg.  */
244               /* First following character is + to add or - to subtract
245                  or = to assign.  */
246               /* Next following char is 'p' and an arg spec
247                  (0100 plus position of that arg relative to this one)
248                  or 'c' and a constant stored in a character.  */
249               tem = p[2] & 0177;
250               if (p[1] == 'p')
251                 tem = argp[tem - 0100];
252               if (p[0] == '-')
253                 argp[0] -= tem;
254               else if (p[0] == '+')
255                 argp[0] += tem;
256               else if (p[0] == '*')
257                 argp[0] *= tem;
258               else if (p[0] == '/')
259                 argp[0] /= tem;
260               else
261                 argp[0] = tem;
262
263               p += 3;
264               break;
265
266             case 'i':           /* %i means add one to arg, */
267               argp[0] ++;       /* and leave it to be output later.  */
268               argp[1] ++;       /* Increment the following arg, too!  */
269               break;
270
271             case '%':           /* %% means output %; no arg.  */
272               goto ordinary;
273
274             case 'n':           /* %n means xor each of next two args with 140.  */
275               argp[0] ^= 0140;
276               argp[1] ^= 0140;
277               break;
278
279             case 'm':           /* %m means xor each of next two args with 177.  */
280               argp[0] ^= 0177;
281               argp[1] ^= 0177;
282               break;
283
284             case 'B':           /* %B means express arg as BCD char code.  */
285               argp[0] += 6 * (tem / 10);
286               break;
287
288             case 'D':           /* %D means weird Delta Data transformation.  */
289               argp[0] -= 2 * (tem % 16);
290               break;
291             }
292         }
293       else
294         /* Ordinary character in the argument string.  */
295       ordinary:
296         *op++ = c;
297     }
298   *op = 0;
299   while (doup-- > 0)
300     strcat (op, up);
301   while (doleft-- > 0)
302     strcat (op, left);
303   return outstring;
304 }
305 \f
306 #ifdef DEBUG
307
308 main (argc, argv)
309      int argc;
310      char **argv;
311 {
312   char buf[50];
313   int args[3];
314   args[0] = atoi (argv[2]);
315   args[1] = atoi (argv[3]);
316   args[2] = atoi (argv[4]);
317   tparam1 (argv[1], buf, "LEFT", "UP", args);
318   printf ("%s\n", buf);
319   return 0;
320 }
321
322 #endif /* DEBUG */