Don't use fstat for readable pipe chars in dtexec.
[oweals/cde.git] / cde / programs / dtdspmsg / dtdspmsg.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: dtdspmsg.c /main/4 1996/04/21 19:28:47 drk $ */
24 /*
25  * COMPONENT_NAME: (CMDMSG) Message Catalogue Facilities
26  *
27  * FUNCTIONS: main, pars_args
28  *
29  * ORIGINS: 27
30  *
31  * IBM CONFIDENTIAL -- (IBM Confidential Restricted when
32  * combined with the aggregated modules for this product)
33  * OBJECT CODE ONLY SOURCE MATERIALS
34  * (C) COPYRIGHT International Business Machines Corp. 1988, 1989, 1991
35  * All Rights Reserved
36  *
37  * US Government Users Restricted Rights - Use, duplication or
38  * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
39  */
40 /*
41  * @OSF_COPYRIGHT@
42  */
43 /*static char rcsid[] = "RCSfile: dspmsg.c,v Revision: 1.4  (OSF) Date: 90/10/07 16:45:19 ";*/
44
45 /*
46  * (c) Copyright 1993, 1994 Hewlett-Packard Company
47  * (c) Copyright 1993, 1994 International Business Machines Corp. 
48  * (c) Copyright 1993, 1994 Sun Microsystems, Inc. 
49  * (c) Copyright 1993, 1994 Novell, Inc.   
50  */
51
52 /*                                                                   
53  * EXTERNAL PROCEDURES CALLED: standard library functions
54  */
55
56
57 #include <stdlib.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <locale.h>
61 #include "msgfac_msg.h"
62
63 #define die(s)                  puts(s), exit(1)
64 #define isanumber(c) (c >= '0' && c <= '9') ? 1 : 0
65 #define isaoctal(c) (c >= '0' && c <= '7') ? 1 : 0
66 #define toanumber(c) (c - '0')
67 #define NOT_SET -1
68 #define TRUE    1
69 #define FALSE   0
70
71 struct arguments {
72         int     set,
73                 msg,
74                 argmax;
75         char    *catname,
76                 *def,
77                 **args;
78 };
79
80         /*-- subroutine used to parse the input arguments ---*/
81 void parse_args(int argc, char *argv[], struct arguments *args);
82
83 nl_catd catderr;        /* error message catalog descriptor */
84
85
86
87 /*
88  * NAME: main
89  *                                                                    
90  * FUNCTION:    Extract a message string from a catalog. Perform printf
91  *              style substitutions and print it out.
92  * 
93  * EXECUTION ENVIRONMENT:
94  *      User mode.
95  *                                                                          
96  * RETURNS:     Exit with 0, except when: the format string 
97  *              is invalid.
98  */  
99
100 int main(int argc,char *argv[]) 
101
102         /* argc: Number of arguments */
103         /* argv: argument vector */
104
105 {
106         struct arguments   args;   /* place to store the parsed arguments*/
107         nl_catd catdmsg;           /* catalog descriptor for message catalog */
108         char    *message;          /* place to store message */
109         char    *p;                /* pointer to current pos within message */
110         int     idx,               /* current argument to be printed */
111                 reorder = NOT_SET; /* Reordering  (TRUE, FALSE, NOT_SET) */
112         int     n;                 /* # bytes in a character */
113
114         setlocale (LC_ALL,"");
115         catderr = catopen(MF_MSGFAC, 0);
116         if (argc < 3) {
117                 die(catgets(catderr,MS_DSPMSG,M_DSPMSG, "Usage: dtdspmsg [-s setno] <catname> <msgno> ['default' arg ... ]"));
118         }
119
120 /*______________________________________________________________________
121         Parse the input arguments int the args structure.
122   ______________________________________________________________________*/
123
124         parse_args(argc,argv,&args);
125
126 /*______________________________________________________________________
127         get the message out of the catalog.
128   ______________________________________________________________________*/
129
130         catdmsg = catopen(args.catname, 0);
131         message = catgets(catdmsg,args.set,args.msg,args.def);
132
133 /*______________________________________________________________________
134
135         print out the message making the appropriate sub's for
136         the parameters.  Reorder the parameters if necessary.
137         Do not use mixed reordering!!!
138   ______________________________________________________________________*/
139
140         for (p = message , idx = 0 ; *p ; p++ )  {
141
142                 /* quoted escape characters */
143                 if (*p == '\\' && message == args.def) {
144                         switch (*++p) {
145                                 case 'n':
146                                         putc('\n',stdout);
147                                         break;
148
149                                 case 't':
150                                         putc('\t',stdout);
151                                         break;
152
153                                 case 'b':
154                                         putc('\b',stdout);
155                                         break;
156
157                                 case 'r':
158                                         putc('\r',stdout);
159                                         break;
160
161                                 case 'v':
162                                         putc('\v',stdout);
163                                         break;
164
165                                 case 'f':
166                                         putc('\f',stdout);
167                                         break;
168
169                                 case 'x':
170                                         {
171                                         char *pesc = p;
172                                         unsigned int hex, hexlen = 0;
173
174                                         while (isxdigit(*++pesc))
175                                                 hexlen++;
176                                         if (hexlen == 2)
177                                                 sscanf (p+1, "%2x", &hex);
178                                         else if (hexlen == 4)
179                                                 sscanf (p+1, "%4x", &hex);
180                                         else {
181                                                 putc('x',stdout);
182                                                 break;
183                                         }
184                                         putc(hex,stdout);
185                                         p += hexlen;
186                                         break;
187                                         }
188
189                                 case '0':
190                                 case '1':
191                                 case '2':
192                                 case '3':
193                                 case '4':
194                                 case '5':
195                                 case '6':
196                                 case '7':
197                                         {
198                                         int c = 0;
199                                         char *pesc = p;
200
201                                         do
202                                                 c = c * 8 + *pesc++ - '0';
203                                         while (isaoctal(*pesc) && pesc < p+3);
204                                         if (c <= 0377) {
205                                                 putc(c,stdout);
206                                                 p = pesc - 1;
207                                         } else
208                                                 putc(*p,stdout);
209                                         break;
210                                         }
211
212                                 default: 
213                                         putc(*p,stdout);
214                                         break;
215                         }
216                 }
217
218                 /* printf % style substitution */
219                 else if (*p == '%') {
220
221                         /* %% prints one % */
222                         if (*++p == '%')  {
223                                 putc(*p,stdout);
224                                 continue;
225                         }
226
227                         /* %n$ reorders the argument list and uses variable n next */
228                         /* once this is used, all arguments must use it */
229                         if (isanumber(*p)) {
230
231                                 /* do not allow mixing of reorder types */
232                                 if (reorder == FALSE) {
233                                         die(catgets(catderr,MS_DSPMSG,M_REORDER,"\nNone or all arguments must use %n$ format"));
234                                 }
235                                 for (idx = 0 ; isanumber(*p) ; p++)
236                                         idx += idx * 10 + toanumber(*p);
237                                 idx--;
238                                 if (*p++ != '$') {
239                                         die(catgets(catderr,MS_DSPMSG,M_INVRE,"\n% missing from %n$ format"));
240                                 }
241                                 reorder = TRUE;
242                         }
243                         else {
244                                 /* do not allow mixing of reorder types */
245                                 if (reorder == TRUE) {
246                                         die(catgets(catderr,MS_DSPMSG,M_REORDER,"\nNone or all arguments must use %n$ format"));
247                                 }
248                                 reorder = FALSE;        
249                         }
250                         /* report invalid printf argument number */
251                         if (idx < 0 || idx >= args.argmax) {
252                                 die(catgets(catderr,MS_DSPMSG,M_REINDEX,"\nInvalid argument index"));
253                         }
254                         /* report unsupported % type */
255                         if (*p == 's')
256                                 ;
257                         else if (*p == 'l' && p[1] == 'd')
258                                 p++;
259                         else {
260                                 exit(1);
261                         }
262                         fwrite(args.args[idx],strlen(args.args[idx]),1,stdout);
263                         idx++;                          
264                 }
265
266                 /* just print the next character */
267                 else {
268                         n = mblen(p, MB_CUR_MAX);
269                         if (n < 0)
270                                 n = 1;
271                         do
272                                 putc(*p++,stdout);
273                         while (--n > 0);
274                         p--;
275                 }
276         }
277         exit(0);
278 }
279
280
281
282 /*
283  * NAME: parse_args
284  *
285  * FUNCTION: Sets up the args-> data structure for main().
286  *
287  * EXECUTION ENVIRONMENT:
288  *      User mode.
289  * 
290  * RETURNS: void
291  */
292
293 void parse_args(int argc, char *argv[], struct arguments *args) 
294
295         /* argc: The number or arguments */
296         /* argv: The input argument vector */
297         /* args: The output argument structure */
298
299 {
300
301         args->args = NULL;
302         args->def = "";
303         args->argmax = 0;
304         args->set = 1;
305         argv++ ; 
306         argc--;                         /* Skip the program name */
307         if (!strcmp(*argv,"-s")) {      /* check for a set number */
308                 if (argc < 4)           /* check for sufficient arguements */
309                 die(catgets(catderr,MS_DSPMSG,M_DSPMSG, "Usage: dtdspmsg [-s setno] <catname> <msgno> ['default' arg ... ]"));
310                 argv++; 
311                 argc--;                         /* skip past the '-s' */
312                 sscanf(*argv,"%d",&args->set);  /* get the real set number */
313                 argv++; 
314                 argc--;                         /* skip past the set number */
315         }
316         args->catname = *argv++;                /* get the cat name */
317         argc--;
318         if (!strcmp(*argv,"-s")) {              /* check for a set number */
319                 if (argc < 3)           /* check for sufficient arguements */
320                 die(catgets(catderr,MS_DSPMSG,M_DSPMSG, "Usage: dtdspmsg [-s setno] <catname> <msgno> ['default' arg ... ]"));
321
322                 argv++; 
323                 argc--;                         /* skip past the '-s' */
324                 sscanf(*argv,"%d",&args->set);  /* get the real set number */
325                 argv++; 
326                 argc--;                         /* skip past the set number */
327         }
328         sscanf(*argv++,"%d",&args->msg);        /* scan the message number */
329         argc--;
330         if (argc) {                             /* check for the arg count 
331                                                    for a default string */
332                 args->def= *argv++;
333                 argc--;
334         }
335         if (argc)  {
336                 args->args = argv;
337                 args->argmax = argc;
338         }
339 }