• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-tools/gnulib-lib/
1/* Substitution of parameters in strings from terminal descriptions.
2   Copyright (C) 2006 Free Software Foundation, Inc.
3
4   This program is free software; you can redistribute it and/or modify it
5   under the terms of the GNU General Public License as published
6   by 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 GNU
12   Library General Public License for more details.
13
14   You should have received a copy of the GNU General Public
15   License along with this program; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17   USA.  */
18
19/* Originally by Ross Ridge, Public Domain, 92/02/01 07:30:36 */
20
21#include <config.h>
22
23#include <stdarg.h>
24#include <stdio.h>
25#include <string.h>
26
27#include "c-ctype.h"
28
29#ifdef USE_SCCS_IDS
30static const char SCCSid[] = "@(#) mytinfo tparm.c 3.2 92/02/01 public domain, By Ross Ridge";
31#endif
32
33#ifndef MAX_PUSHED
34#define MAX_PUSHED	32
35#endif
36
37#define ARG	1
38#define NUM	2
39
40#define INTEGER	1
41#define STRING	2
42
43#define MAX_LINE 640
44
45typedef struct stack_str
46{
47  int type;
48  int argnum;
49  int value;
50} stack;
51
52static stack S[MAX_PUSHED];
53static stack vars['z'-'a'+1];
54static int pos = 0;
55
56static
57struct arg_str
58{
59  int type;
60  int integer;
61  char *string;
62} arg_list[10];
63
64static int argcnt;
65
66static va_list tparm_args;
67
68static int
69pusharg (int arg)
70{
71  if (pos == MAX_PUSHED)
72    return 1;
73  S[pos].type = ARG;
74  S[pos++].argnum = arg;
75  return 0;
76}
77
78static int
79pushnum (int num)
80{
81  if (pos == MAX_PUSHED)
82    return 1;
83  S[pos].type = NUM;
84  S[pos++].value = num;
85  return 0;
86}
87
88static int
89getarg (int argnum, int type, void *p)
90{
91  while (argcnt < argnum)
92    {
93      arg_list[argcnt].type = INTEGER;
94      arg_list[argcnt++].integer = (int) va_arg (tparm_args, int);
95    }
96  if (argcnt > argnum)
97    {
98      if (arg_list[argnum].type != type)
99	return 1;
100      else if (type == STRING)
101	*(char **)p = arg_list[argnum].string;
102      else
103	*(int *)p = arg_list[argnum].integer;
104    }
105  else
106    {
107      arg_list[argcnt].type = type;
108      if (type == STRING)
109	*(char **)p = arg_list[argcnt++].string = (char *) va_arg (tparm_args, char *);
110      else
111	*(int *)p = arg_list[argcnt++].integer = (int) va_arg (tparm_args, int);
112    }
113  return 0;
114}
115
116static int
117popstring (char **str)
118{
119  if (pos-- == 0)
120    return 1;
121  if (S[pos].type != ARG)
122    return 1;
123  return getarg (S[pos].argnum, STRING, str);
124}
125
126static int
127popnum (int *num)
128{
129  if (pos-- == 0)
130    return 1;
131  switch (S[pos].type)
132    {
133    case ARG:
134      return  getarg (S[pos].argnum, INTEGER, num);
135    case NUM:
136      *num = S[pos].value;
137      return 0;
138    }
139  return 1;
140}
141
142static int
143cvtchar (const char *sp, char *c)
144{
145  switch (*sp)
146    {
147    case '\\':
148      switch (*++sp)
149	{
150	case '\'':
151	case '$':
152	case '\\':
153	case '%':
154	  *c = *sp;
155	  return 2;
156	case '\0':
157	  *c = '\\';
158	  return 1;
159	case '0':
160	  if (sp[1] == '0' && sp[2] == '0')
161	    {
162	      *c = '\0';
163	      return 4;
164	    }
165	  *c = '\200'; /* '\0' ???? */
166	  return 2;
167	default:
168	  *c = *sp;
169	  return 2;
170	}
171    default:
172      *c = *sp;
173      return 1;
174    }
175}
176
177/* sigh... this has got to be the ugliest code I've ever written.
178   Trying to handle everything has its cost, I guess.
179
180   It actually isn't to hard to figure out if a given % code is supposed
181   to be interpeted with its termcap or terminfo meaning since almost
182   all terminfo codes are invalid unless something has been pushed on
183   the stack and termcap strings will never push things on the stack
184   (%p isn't used by termcap). So where we have a choice we make the
185   decision by wether or not somthing has been pushed on the stack.
186   The static variable termcap keeps track of this; it starts out set
187   to 1 and is incremented as each argument processed by a termcap % code,
188   however if something is pushed on the stack it's set to 0 and the
189   rest of the % codes are interpeted as terminfo % codes. Another way
190   of putting it is that if termcap equals one we haven't decided either
191   way yet, if it equals zero we're looking for terminfo codes, and if
192   its greater than 1 we're looking for termcap codes.
193
194   Terminfo % codes:
195
196	%%	output a '%'
197	%[[:][-+# ][width][.precision]][doxXs]
198		output pop according to the printf format
199	%c	output pop as a char
200	%'c'	push character constant c.
201	%{n}	push decimal constant n.
202	%p[1-9] push paramter [1-9]
203	%g[a-z] push variable [a-z]
204	%P[a-z] put pop in variable [a-z]
205	%l	push the length of pop (a string)
206	%+	add pop to pop and push the result
207	%-	subtract pop from pop and push the result
208	%*	multiply pop and pop and push the result
209	%&	bitwise and pop and pop and push the result
210	%|	bitwise or pop and pop and push the result
211	%^	bitwise xor pop and pop and push the result
212	%~	push the bitwise not of pop
213	%=	compare if pop and pop are equal and push the result
214	%>	compare if pop is less than pop and push the result
215	%<	compare if pop is greater than pop and push the result
216	%A	logical and pop and pop and push the result
217	%O	logical or pop and pop and push the result
218	%!	push the logical not of pop
219	%? condition %t if_true [%e if_false] %;
220		if condtion evaulates as true then evaluate if_true,
221		else evaluate if_false. elseif's can be done:
222	%? cond %t true [%e cond2 %t true2] ... [%e condN %t trueN] [%e false] %;
223	%i	add one to parameters 1 and 2. (ANSI)
224
225  Termcap Codes:
226
227	%%	output a %
228	%.	output parameter as a character
229	%d	output parameter as a decimal number
230	%2	output parameter in printf format %02d
231	%3	output parameter in printf format %03d
232	%+x	add the character x to parameter and output it as a character
233(UW)	%-x	subtract parameter FROM the character x and output it as a char
234(UW)	%ax	add the character x to parameter
235(GNU)	%a[+*-/=][cp]x
236		GNU arithmetic.
237(UW)	%sx	subtract parameter FROM the character x
238	%>xy	if parameter > character x then add character y to parameter
239	%B	convert to BCD (parameter = (parameter/10)*16 + parameter%16)
240	%D	Delta Data encode (parameter = parameter - 2*(paramter%16))
241	%i	increment the first two parameters by one
242	%n	xor the first two parameters by 0140
243(GNU)	%m	xor the first two parameters by 0177
244	%r	swap the first two parameters
245(GNU)	%b	backup to previous parameter
246(GNU)	%f	skip this parameter
247
248  Note the two definitions of %a, the GNU defintion is used if the characters
249  after the 'a' are valid, otherwise the UW definition is used.
250
251  (GNU) used by GNU Emacs termcap libraries
252  (UW) used by the University of Waterloo (MFCF) termcap libraries
253
254*/
255
256char *
257tparm (const char *str, ...)
258{
259  static int termcap;
260  static char OOPS[] = "OOPS";
261  static char buf[MAX_LINE];
262  const char *sp;
263  char *dp;
264  char *fmt;
265  char scan_for;
266  int scan_depth;
267  int if_depth;
268  char fmt_buf[MAX_LINE];
269  char sbuf[MAX_LINE];
270
271  va_start (tparm_args, str);
272
273  sp = str;
274  dp = buf;
275  scan_for = 0;
276  scan_depth = 0;
277  if_depth = 0;
278  argcnt = 0;
279  pos = 0;
280  termcap = 1;
281  while (*sp != '\0')
282    {
283      switch (*sp)
284	{
285	case '\\':
286	  if (scan_for)
287	    {
288	      if (*++sp != '\0')
289		sp++;
290	      break;
291	    }
292	  *dp++ = *sp++;
293	  if (*sp != '\0')
294	    *dp++ = *sp++;
295	  break;
296	case '%':
297	  sp++;
298	  if (scan_for)
299	    {
300	      if (*sp == scan_for && if_depth == scan_depth)
301		{
302		  if (scan_for == ';')
303		    if_depth--;
304		  scan_for = 0;
305		}
306	      else if (*sp == '?')
307		if_depth++;
308	      else if (*sp == ';')
309		{
310		  if (if_depth == 0)
311		    return OOPS;
312		  else
313		    if_depth--;
314		}
315	      sp++;
316	      break;
317	    }
318	  fmt = NULL;
319	  switch (*sp)
320	    {
321	    case '%':
322	      *dp++ = *sp++;
323	      break;
324	    case '+':
325	      if (!termcap)
326		{
327		  int i, j;
328		  if (popnum (&j) || popnum (&i))
329		    return OOPS;
330		  i += j;
331		  if (pushnum (i))
332		    return OOPS;
333		  sp++;
334		  break;
335		}
336	      /* FALLTHROUGH */
337	    case 'C':
338	      if (*sp == 'C')
339		{
340		  int i;
341		  if (getarg (termcap - 1, INTEGER, &i))
342		    return OOPS;
343		  if (i >= 96)
344		    {
345		      i /= 96;
346		      if (i == '$')
347			*dp++ = '\\';
348		      *dp++ = i;
349		    }
350		}
351	      fmt = "%c";
352	      /* FALLTHROUGH */
353	    case 'a':
354	      if (!termcap)
355		return OOPS;
356	      {
357		int i;
358		if (getarg (termcap - 1, INTEGER, &i))
359		  return OOPS;
360		if (*++sp == '\0')
361		  return OOPS;
362		if ((sp[1] == 'p' || sp[1] == 'c')
363		    && sp[2] != '\0' && fmt == NULL)
364		  {
365		    /* GNU arithmetic parameter, what they really need is
366		       terminfo.  */
367		    int val;
368		    int lc;
369		    if (sp[1] == 'p'
370			&& getarg (termcap - 1 + sp[2] - '@', INTEGER, &val))
371		      return OOPS;
372		    if (sp[1] == 'c')
373		      {
374			char c;
375			lc = cvtchar (sp + 2, &c) + 2;
376			/* Mask out 8th bit so \200 can be used for \0 as per
377			   GNU docs.  */
378			val = c & 0177;
379		      }
380		    else
381		      lc = 2;
382		    switch (sp[0])
383		      {
384		      case '=':
385			break;
386		      case '+':
387			val = i + val;
388			break;
389		      case '-':
390			val = i - val;
391			break;
392		      case '*':
393			val = i * val;
394			break;
395		      case '/':
396			val = i / val;
397			break;
398		      default:
399			/* Not really GNU's %a after all... */
400			{
401			  char c;
402			  lc = cvtchar (sp, &c);
403			  val = c + i;
404			}
405		        break;
406		      }
407		    arg_list[termcap - 1].integer = val;
408		    sp += lc;
409		    break;
410		  }
411		{
412		  char c;
413		  sp += cvtchar (sp, &c);
414		  arg_list[termcap - 1].integer = c + i;
415		}
416	      }
417	      if (fmt == NULL)
418		break;
419	      sp--;
420	      /* FALLTHROUGH */
421	    case '-':
422	      if (!termcap)
423		{
424		  int i, j;
425		  if (popnum (&j) || popnum (&i))
426		    return OOPS;
427		  i -= j;
428		  if (pushnum (i))
429		    return OOPS;
430		  sp++;
431		  break;
432		}
433	      fmt = "%c";
434	      /* FALLTHROUGH */
435	    case 's':
436	      if (termcap && (fmt == NULL || *sp == '-'))
437		{
438		  int i;
439		  if (getarg (termcap - 1, INTEGER, &i))
440		    return OOPS;
441		  if (*++sp == '\0')
442		    return OOPS;
443		  {
444		    char c;
445		    sp += cvtchar (sp, &c);
446		    arg_list[termcap - 1].integer = c - i;
447		  }
448		  if (fmt == NULL)
449		    break;
450		  sp--;
451		}
452	      if (!termcap)
453		return OOPS;
454	      /* FALLTHROUGH */
455	    case '.':
456	      if (termcap && fmt == NULL)
457		fmt = "%c";
458	      /* FALLTHROUGH */
459	    case 'd':
460	      if (termcap && fmt == NULL)
461		fmt = "%d";
462	      /* FALLTHROUGH */
463	    case '2':
464	      if (termcap && fmt == NULL)
465		fmt = "%02d";
466	      /* FALLTHROUGH */
467	    case '3':
468	      if (termcap && fmt == NULL)
469		fmt = "%03d";
470	      /* FALLTHROUGH */
471	    case ':': case ' ': case '#': case 'u':
472	    case 'x': case 'X': case 'o': case 'c':
473	    case '0': case '1': case '4': case '5':
474	    case '6': case '7': case '8': case '9':
475	      if (fmt == NULL)
476		{
477		  if (termcap)
478		    return OOPS;
479		  if (*sp == ':')
480		    sp++;
481		  fmt = fmt_buf;
482		  *fmt++ = '%';
483		  while (*sp != 's' && *sp != 'x' && *sp != 'X' && *sp != 'd'
484			 && *sp != 'o' && *sp != 'c' && *sp != 'u')
485		    {
486		      if (*sp == '\0')
487			return OOPS;
488		      *fmt++ = *sp++;
489		    }
490		  *fmt++ = *sp;
491		  *fmt = '\0';
492		  fmt = fmt_buf;
493		}
494	      {
495		char conv_char = fmt[strlen (fmt) - 1];
496		if (conv_char == 's')
497		  {
498		    char *s;
499		    if (popstring (&s))
500		      return OOPS;
501		    sprintf (sbuf, fmt, s);
502		  }
503		else
504		  {
505		    int i;
506		    if (termcap)
507		      {
508			if (getarg (termcap++ - 1, INTEGER, &i))
509			  return OOPS;
510		      }
511		    else
512		      if (popnum (&i))
513			return OOPS;
514		    if (i == 0 && conv_char == 'c')
515		      strcpy (sbuf, "\000");
516		    else
517		      sprintf (sbuf, fmt, i);
518		  }
519	      }
520	      sp++;
521	      fmt = sbuf;
522	      while (*fmt != '\0')
523		{
524		  if (*fmt == '$')
525		    *dp++ = '\\';
526		  *dp++ = *fmt++;
527		}
528	      break;
529	    case 'r':
530	      {
531		int i;
532		if (!termcap || getarg (1, INTEGER, &i))
533		  return OOPS;
534		arg_list[1].integer = arg_list[0].integer;
535		arg_list[0].integer = i;
536	      }
537	      sp++;
538	      break;
539	    case 'i':
540	      {
541		int i;
542		if (getarg (1, INTEGER, &i) || arg_list[0].type != INTEGER)
543		  return OOPS;
544	      }
545	      arg_list[1].integer++;
546	      arg_list[0].integer++;
547	      sp++;
548	      break;
549	    case 'n':
550	      {
551		int i;
552		if (!termcap || getarg (1, INTEGER, &i))
553		  return OOPS;
554	      }
555	      arg_list[0].integer ^= 0140;
556	      arg_list[1].integer ^= 0140;
557	      sp++;
558	      break;
559	    case '>':
560	      if (!termcap)
561		{
562		  int i, j;
563		  if (popnum (&j) || popnum (&i))
564		    return OOPS;
565		  i = (i > j);
566		  if (pushnum (i))
567		    return OOPS;
568		  sp++;
569		  break;
570		}
571	      {
572		int i;
573		if (getarg (termcap-1, INTEGER, &i))
574		  return OOPS;
575		{
576		  char c;
577		  sp += cvtchar (sp, &c);
578		  if (i > c)
579		    {
580		      sp += cvtchar (sp, &c);
581		      arg_list[termcap-1].integer += c;
582		    }
583		  else
584		    sp += cvtchar (sp, &c);
585		}
586	      }
587	      sp++;
588	      break;
589	    case 'B':
590	      {
591		int i;
592		if (!termcap || getarg (termcap-1, INTEGER, &i))
593		  return OOPS;
594		arg_list[termcap-1].integer = 16 * (i / 10) + i % 10;
595	      }
596	      sp++;
597	      break;
598	    case 'D':
599	      {
600		int i;
601		if (!termcap || getarg (termcap-1, INTEGER, &i))
602		  return OOPS;
603		arg_list[termcap-1].integer = i - 2 * (i % 16);
604	      }
605	      sp++;
606	      break;
607	    case 'p':
608	      if (termcap > 1)
609		return OOPS;
610	      if (*++sp == '\0')
611		return OOPS;
612	      {
613		int i = (*sp == '0' ? 9 : *sp - '1');
614		if (i < 0 || i > 9)
615		  return OOPS;
616		if (pusharg (i))
617		  return OOPS;
618	      }
619	      termcap = 0;
620	      sp++;
621	      break;
622	    case 'P':
623	      if (termcap || *++sp == '\0')
624		return OOPS;
625	      {
626		int i = *sp++ - 'a';
627		if (i < 0 || i > 25)
628		  return OOPS;
629		if (pos-- == 0)
630		  return OOPS;
631		switch (vars[i].type = S[pos].type)
632		  {
633		  case ARG:
634		    vars[i].argnum = S[pos].argnum;
635		    break;
636		  case NUM:
637		    vars[i].value = S[pos].value;
638		    break;
639		  }
640	      }
641	      break;
642	    case 'g':
643	      if (termcap || *++sp == '\0')
644		return OOPS;
645	      {
646		int i = *sp++ - 'a';
647		if (i < 0 || i > 25)
648		  return OOPS;
649		switch (vars[i].type)
650		  {
651		  case ARG:
652		    if (pusharg (vars[i].argnum))
653		      return OOPS;
654		    break;
655		  case NUM:
656		    if (pushnum (vars[i].value))
657		      return OOPS;
658		    break;
659		  }
660	      }
661	      break;
662	    case '\'':
663	      if (termcap > 1)
664		return OOPS;
665	      if (*++sp == '\0')
666		return OOPS;
667	      {
668		char c;
669		sp += cvtchar (sp, &c);
670		if (pushnum (c) || *sp++ != '\'')
671		  return OOPS;
672	      }
673	      termcap = 0;
674	      break;
675	    case '{':
676	      if (termcap > 1)
677		return OOPS;
678	      {
679		int i;
680		i = 0;
681		sp++;
682		while (c_isdigit (*sp))
683		  i = 10 * i + *sp++ - '0';
684		if (*sp++ != '}' || pushnum (i))
685		  return OOPS;
686	      }
687	      termcap = 0;
688	      break;
689	    case 'l':
690	      {
691		int i;
692		char *s;
693		if (termcap || popstring (&s))
694		  return OOPS;
695		i = strlen (s);
696		if (pushnum (i))
697		  return OOPS;
698	      }
699	      sp++;
700	      break;
701	    case '*':
702	      {
703		int i, j;
704		if (termcap || popnum (&j) || popnum (&i))
705		  return OOPS;
706		i *= j;
707		if (pushnum (i))
708		  return OOPS;
709	      }
710	      sp++;
711	      break;
712	    case '/':
713	      {
714		int i, j;
715		if (termcap || popnum (&j) || popnum (&i))
716		  return OOPS;
717		i /= j;
718		if (pushnum (i))
719		  return OOPS;
720	      }
721	      sp++;
722	      break;
723	    case 'm':
724	      if (termcap)
725		{
726		  int i;
727		  if (getarg (1, INTEGER, &i))
728		    return OOPS;
729		  arg_list[0].integer ^= 0177;
730		  arg_list[1].integer ^= 0177;
731		  sp++;
732		  break;
733		}
734	      {
735		int i, j;
736		if (popnum (&j) || popnum (&i))
737		  return OOPS;
738		i %= j;
739		if (pushnum (i))
740		  return OOPS;
741	      }
742	      sp++;
743	      break;
744	    case '&':
745	      {
746		int i, j;
747		if (popnum (&j) || popnum (&i))
748		  return OOPS;
749		i &= j;
750		if (pushnum (i))
751		  return OOPS;
752	      }
753	      sp++;
754	      break;
755	    case '|':
756	      {
757		int i, j;
758		if (popnum (&j) || popnum (&i))
759		  return OOPS;
760		i |= j;
761		if (pushnum (i))
762		  return OOPS;
763	      }
764	      sp++;
765	      break;
766	    case '^':
767	      {
768		int i, j;
769		if (popnum (&j) || popnum (&i))
770		  return OOPS;
771		i ^= j;
772		if (pushnum (i))
773		  return OOPS;
774	      }
775	      sp++;
776	      break;
777	    case '=':
778	      {
779		int i, j;
780		if (popnum (&j) || popnum (&i))
781		  return OOPS;
782		i = (i == j);
783		if (pushnum (i))
784		  return OOPS;
785	      }
786	      sp++;
787	      break;
788	    case '<':
789	      {
790		int i, j;
791		if (popnum (&j) || popnum (&i))
792		  return OOPS;
793		i = (i < j);
794		if (pushnum (i))
795		  return OOPS;
796	      }
797	      sp++;
798	      break;
799	    case 'A':
800	      {
801		int i, j;
802		if (popnum (&j) || popnum (&i))
803		  return OOPS;
804		i = (i && j);
805		if (pushnum (i))
806		  return OOPS;
807	      }
808	      sp++;
809	      break;
810	    case 'O':
811	      {
812		int i, j;
813		if (popnum (&j) || popnum (&i))
814		  return OOPS;
815		i = (i || j);
816		if (pushnum (i))
817		  return OOPS;
818	      }
819	      sp++;
820	      break;
821	    case '!':
822	      {
823		int i;
824		if (popnum (&i))
825		  return OOPS;
826		i = !i;
827		if (pushnum (i))
828		  return OOPS;
829	      }
830	      sp++;
831	      break;
832	    case '~':
833	      {
834		int i;
835		if (popnum (&i))
836		  return OOPS;
837		i = ~i;
838		if (pushnum (i))
839		  return OOPS;
840	      }
841	      sp++;
842	      break;
843	    case '?':
844	      if (termcap > 1)
845		return OOPS;
846	      termcap = 0;
847	      if_depth++;
848	      sp++;
849	      break;
850	    case 't':
851	      {
852		int i;
853		if (popnum (&i) || if_depth == 0)
854		  return OOPS;
855		if (!i)
856		  {
857		    scan_for = 'e';
858		    scan_depth = if_depth;
859		  }
860	      }
861	      sp++;
862	      break;
863	    case 'e':
864	      if (if_depth == 0)
865		return OOPS;
866	      scan_for = ';';
867	      scan_depth = if_depth;
868	      sp++;
869	      break;
870	    case ';':
871	      if (if_depth-- == 0)
872		return OOPS;
873	      sp++;
874	      break;
875	    case 'b':
876	      if (--termcap < 1)
877		return OOPS;
878	      sp++;
879	      break;
880	    case 'f':
881	      if (!termcap++)
882		return OOPS;
883	      sp++;
884	      break;
885	    }
886	  break;
887	default:
888	  if (scan_for)
889	    sp++;
890	  else
891	    *dp++ = *sp++;
892	  break;
893	}
894    }
895  va_end (tparm_args);
896  *dp = '\0';
897  return buf;
898}
899