Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / lib / DtSvc / DtEncap / spc-termio.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 libraries 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 /*
24  * File:         spc-termio.c $TOG: spc-termio.c /main/5 1998/04/03 17:08:32 mgreess $
25  * Language:     C
26  *
27  * (c) Copyright 1990, Hewlett-Packard Company, all rights reserved.
28  *
29  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
30  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
31  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
32  * (c) Copyright 1993, 1994 Novell, Inc.                                *
33  */
34
35 #include <bms/sbport.h>
36 #include <bms/stringbuf.h>
37
38 #include <termios.h>
39 #if !defined(__linux__) && !defined(CSRG_BASED)
40 #include <sys/termio.h>
41 #endif
42 #include <codelibs/stringx.h>
43
44 #include <SPC/spcP.h>
45
46 #ifdef __cplusplus
47 #define STRTOKX(b,f) strtokx((b), (f))
48 #else
49 #define STRTOKX(b,f) strtokx((char **)(&b), (f))
50 #endif
51
52 /***************************************************************************************
53
54 The routines in this file decode and encode a termios struct back and forth between the
55 actual binary representation of the structure and an ASCII string representation which
56 may be portably sent across the network.  
57
58  <version>!<i-flags>!<o-flags>!<c-flags>!<l-flags>!<i-speed>!<o-speed>!<cc-array>
59
60   Where:
61
62      <version> == the termios struct protocal version (currently XPG3)
63
64      <i-flags> == comma separated list of input mode flags as defined in
65                   the termios.h header file.
66
67      <o-flags> == comma separated list of output mode flags as defined in
68                   the termios.h header file.
69
70      <c-flags> == comma separated list of control mode flags as defined in
71                   the termios.h header file.  The terminal speed info is
72                   not part of this list.
73
74      <i-speed> == The input speed as defined in the termios.h header file.  
75
76      <o-speed> == The output speed as defined in the termios.h header file.  
77
78      <cc-array> == comma separated list of control control character names and 
79                    values formatted as (<name>=<value),<name>=<value>...)
80
81 ******************************************************************************************/
82
83 #define SPC_TERMIO_VER_FIELD    1       /* Define field indicies for above string */
84 #define SPC_TERMIO_IMODE_FIELD  2
85 #define SPC_TERMIO_OMODE_FIELD  3
86 #define SPC_TERMIO_CMODE_FIELD  4
87 #define SPC_TERMIO_LMODE_FIELD  5
88 #define SPC_TERMIO_ISPEED_FIELD 6
89 #define SPC_TERMIO_OSPEED_FIELD 7
90 #define SPC_TERMIO_CC_FIELD     8
91 #define SPC_TERMIO_LAST_FIELD   SPC_TERMIO_CC_FIELD
92
93 #define SPC_TERMIO_SEP "!"              /* These three MUST be only 1 char */
94 #define SPC_TCFLAG_SEP ","
95 #define SPC_CC_SEP     "="              
96
97 #define SPC_CC_FORMAT  "%u"             /* CC values are printed with this format */
98
99 struct modes_s
100 {
101     XeString    name;
102     tcflag_t    value;
103 };
104
105 struct baud_s
106 {
107     XeString    name;
108     speed_t     speed;
109 };
110
111 struct cc_s
112 {
113     XeString    name;
114     cc_t        value;
115 };
116
117 /* The following lists are the valid componants of a "struct termios"   */
118 /* as defined in XPG3.  These MUST be kept up to date with the X/Open   */
119 /* standard.  No platform specific items can exist here as we pass this */
120 /* data to other systems on the network and they be from any vendor.    */
121 /* -------------------------------------------------------------------- */
122
123 #define SPC_TERMIO_VERSION "XPG3"
124
125 #define END_OF_LIST "End_Of_List"
126     
127 static struct modes_s Input_modes[] = {
128   { "BRKINT",   BRKINT, },
129   { "ICRNL",    ICRNL, },
130   { "IGNBRK",   IGNBRK, },
131   { "IGNCR",    IGNCR, },
132   { "IGNPAR",   IGNPAR, },
133   { "INLCR",    INLCR, },
134   { "INPCK",    INPCK, },
135   { "ISTRIP",   ISTRIP, },
136   { "IXOFF",    IXOFF, },
137   { "IXON",     IXON, },
138   { "PARMRK",   PARMRK, },
139   { END_OF_LIST, 0 },
140 };
141
142 static struct modes_s Output_modes[] = {    
143   { "OPOST",    OPOST, },
144   { "ONLCR",    ONLCR, },
145   { "OCRNL",    OCRNL, },
146   { "ONOCR",    ONOCR, },
147   { "ONLRET",   ONLRET, },
148 #if !defined(CSRG_BASED)
149   { "OFILL",    OFILL, },
150   { "OFDEL",    OFDEL, },
151   { "NLDLY",    NLDLY, },
152   { "NL0",      NL0, },
153   { "NL1",      NL1, },
154   { "CRDLY",    CRDLY, },
155   { "CR0",      CR0, },
156   { "CR1",      CR1, },
157   { "CR2",      CR2, },
158   { "CR3",      CR3, },
159   { "TABDLY",   TABDLY, },
160   { "TAB0",     TAB0, },
161   { "TAB1",     TAB1, },
162   { "TAB2",     TAB2, },
163   { "TAB3",     TAB3, },
164   { "BSDLY",    BSDLY, },
165   { "BS0",      BS0, },
166   { "BS1",      BS1, },
167   { "VTDLY",    VTDLY, },
168   { "VT0",      VT0, },
169   { "VT1",      VT1, },
170   { "FFDLY",    FFDLY, },
171   { "FF0",      FF0, },
172   { "FF1",      FF1, },
173 #endif
174   { END_OF_LIST, 0 },
175 };
176
177
178 static struct baud_s Baud_rates[] = {    
179   { "B0",       B0, },
180   { "B50",      B50, },
181   { "B75",      B75, },
182   { "B110",     B110, },
183   { "B134",     B134, },
184   { "B150",     B150, },
185   { "B200",     B200, },
186   { "B300",     B300, },
187   { "B600",     B600, },
188   { "B1200",    B1200, },
189   { "B1800",    B1800, },
190   { "B2400",    B2400, },
191   { "B4800",    B4800, },
192   { "B9600",    B9600, },
193   { "B19200",   B19200, },
194   { "B38400",   B38400, },
195   { END_OF_LIST, 0 },
196 };
197
198
199 static struct modes_s Control_modes[] = {    
200   { "CSIZE",    CSIZE, },
201   { "CS5",      CS5, },
202   { "CS6",      CS6, },
203   { "CS7",      CS7, },
204   { "CS8",      CS8, },
205   { "CSTOPB",   CSTOPB, },
206   { "CREAD",    CREAD, },
207   { "PARENB",   PARENB, },
208   { "PARODD",   PARODD, },
209   { "HUPCL",    HUPCL, },
210   { "CLOCAL",   CLOCAL, },
211   { END_OF_LIST, 0 },
212 };
213
214
215 static struct modes_s Local_modes[] = {    
216   { "ECHO",     ECHO, },
217   { "ECHOE",    ECHOE, },
218   { "ECHOK",    ECHOK, },
219   { "ECHONL",   ECHONL, },
220   { "ICANON",   ICANON, },
221   { "IEXTEN",   IEXTEN, },
222   { "ISIG",     ISIG, },
223   { "NOFLSH",   NOFLSH, },
224   { "TOSTOP",   TOSTOP, },
225   { END_OF_LIST, 0 },
226 };
227
228
229 static struct cc_s CC_Array[] = {    
230   { "VEOF",     VEOF, },
231   { "VEOL",     VEOL, },
232   { "VERASE",   VERASE, },
233   { "VINTR",    VINTR, },
234   { "VKILL",    VKILL, },
235   { "VMIN",     VMIN, },
236   { "VQUIT",    VQUIT, },
237   { "VSTART",   VSTART, },
238   { "VSTOP",    VSTOP, },
239   { "VSUSP",    VSUSP, },
240   { "VTIME",    VTIME, },
241   { END_OF_LIST, 0 },
242 };
243
244     
245 /*----------------------------------------------------------------------+*/
246 static void 
247     SPC_Decode_TCflag(tcflag_t       flag, 
248                       struct modes_s modes[], 
249                       XeStringBuffer buff)
250 /*----------------------------------------------------------------------+*/
251 {
252     Boolean first_time = TRUE;
253     
254     /* Given a binary representation of flag (tcflag_t), convert */
255     /* it into a comma separated list of ASCII flag names.            */
256
257     while (strcmp(modes->name, END_OF_LIST) != 0)
258     {
259         if ( (modes->value & flag) == modes->value)
260         {
261             if (first_time) 
262                 first_time = FALSE;
263             else
264                 XeAppendToStringBuffer(buff, SPC_TCFLAG_SEP);
265
266             XeAppendToStringBuffer(buff, modes->name);
267         }
268         modes++;
269     }
270     
271     /* We need at least one blank for strtokx to work when */
272     /* we take this string apart on the other side.        */
273     /* --------------------------------------------------- */
274     if (first_time)
275         XeAppendToStringBuffer(buff, (XeString)" ");
276 }
277
278 /*----------------------------------------------------------------------+*/
279 static tcflag_t 
280     SPC_Encode_TCflag(XeString       buff,  
281                       struct modes_s modes[])
282 /*----------------------------------------------------------------------+*/
283 {
284     /* Given a comma separated list of flag names, convert the list */
285     /* into a "tcflag_t" (binary) representation of that list.      */
286
287     XeString item;
288     tcflag_t flag = (tcflag_t)0;
289     struct modes_s *orig_modes = modes;
290     
291     if (!*buff) 
292         return flag;
293     
294     while ((item = (XeString)STRTOKX(buff, SPC_TCFLAG_SEP)))
295     {
296         Boolean found = FALSE;
297         
298         modes = orig_modes;
299         while (strcmp(modes->name, END_OF_LIST) != 0)
300         {
301             if (strcmp(modes->name, item) == 0)
302             {
303                 flag |= modes->value;
304                 found = TRUE;
305                 break;
306             }
307             modes++;
308         }
309
310         if (!found)
311             SPC_Error(SPC_Bad_Termios_Mode, item);
312     }
313
314     return flag;
315 }
316
317 /*----------------------------------------------------------------------+*/
318 static void 
319     SPC_Decode_Speed(speed_t        speed, 
320                      struct baud_s  bauds[], 
321                      XeStringBuffer buff)
322 /*----------------------------------------------------------------------+*/
323 {
324     /* Given a binary "speed_t" speed specification, convert it into */
325     /* a single ASCII string.                                        */
326
327     while (strcmp(bauds->name, END_OF_LIST) != 0)
328     {
329         if (bauds->speed == speed)
330         {
331             XeAppendToStringBuffer(buff, bauds->name);
332             return;
333         }
334         bauds++;
335     }
336
337     /* We need at least one blank for strtokx to work when */
338     /* we take this string apart on the other side.        */
339     /* --------------------------------------------------- */
340     XeAppendToStringBuffer(buff, (XeString)" ");
341 }
342
343 /*----------------------------------------------------------------------+*/
344 static speed_t 
345     SPC_Encode_Speed(XeString      buff,  
346                      struct baud_s bauds[])
347 /*----------------------------------------------------------------------+*/
348 {
349 #define DEFAULT_SPEED B9600
350     
351     /* Given a single ASCII name of a termio speed item, convert it into */
352     /* a binary (speed_t) representation.                                */
353     
354     if (!*buff) 
355         return DEFAULT_SPEED;
356     
357     while (strcmp(bauds->name, END_OF_LIST) != 0)
358     {
359         if (strcmp(bauds->name, buff) == 0)
360             return bauds->speed;
361         bauds++;
362     }
363     
364     SPC_Error(SPC_Bad_Termios_Speed, buff);
365     return DEFAULT_SPEED;
366 }
367
368 /*----------------------------------------------------------------------+*/
369 static void 
370     SPC_Decode_CC(cc_t           ccs[], 
371                   struct cc_s    cc_array[], 
372                   XeStringBuffer buff)
373 /*----------------------------------------------------------------------+*/
374 {
375     Boolean first_time = TRUE;
376
377     /* Given an array of cc_s from a termios struct (binary        */
378     /* representation), convert it into a comma sepearted list of  */
379     /* CC names and values of the form <name>=<value>              */
380     
381     while (strcmp(cc_array->name, END_OF_LIST) != 0)
382     {
383         int index = ccs[cc_array->value];
384         if ( index != 0 )
385         {
386             XeChar num[30];
387
388             if (first_time) 
389                 first_time = FALSE;
390             else
391                 XeAppendToStringBuffer(buff, SPC_TCFLAG_SEP);
392
393             XeAppendToStringBuffer(buff, cc_array->name);
394             XeAppendToStringBuffer(buff, SPC_CC_SEP);
395             sprintf(num, SPC_CC_FORMAT, index);
396             XeAppendToStringBuffer(buff, num);
397         }
398         cc_array++;
399     }
400
401     /* We need at least one blank for strtokx to work when */
402     /* we take this string apart on the other side.        */
403     /* --------------------------------------------------- */
404     if (first_time)
405         XeAppendToStringBuffer(buff, (XeString)" ");
406 }
407
408 /*----------------------------------------------------------------------+*/
409 static void 
410     SPC_Encode_CC(XeString    buff,  
411                   cc_t        ccs[], 
412                   struct cc_s cc_array[])
413 /*----------------------------------------------------------------------+*/
414 {
415     /* we should have gotten a string that looks like this:               */
416     /*                                                                    */
417     /* <V-Name>=<value>,<V-Name>=<value>...                               */
418     /*                                                                    */
419     /* For example:   VEOF=4,VKILL=8                                      */
420     /*                                                                    */
421     /* Parse this array and store the values in the "ccs" array passed in */
422     /* to us.  It is assumed that the <V-name> strings are all defined in */
423     /* the "cc_array" list passed to us.                                  */
424     /* ------------------------------------------------------------------ */
425
426     XeString cc_name, cc_value;
427     int i;
428     unsigned int a_cc;
429     struct cc_s *orig_cc_array = cc_array;
430
431     for(i=0; i<NCCS; i++) 
432         ccs[i] = 0;
433     
434     if (!*buff) return;
435     
436     while ((cc_name = (XeString)STRTOKX(buff, SPC_TCFLAG_SEP)))
437     {
438         Boolean found = FALSE;
439
440         cc_value = strchr(cc_name, SPC_CC_SEP[0]);      /* Go find the "=" */
441         if (!cc_value)
442         {
443             SPC_Error(SPC_Bad_Termios_CC, cc_name);
444             continue;
445         }
446         *cc_value++ = XeChar_NULL;                      /* Replace "=" with null */
447         
448
449         /* Look for "V-Name" in table ... */
450         /* ------------------------------ */
451         cc_array = orig_cc_array;
452         while (strcmp(cc_array->name, END_OF_LIST) != 0)
453         {
454             if (strcmp(cc_array->name, cc_name) == 0)
455             {
456                 if (sscanf(cc_value, SPC_CC_FORMAT, &a_cc) != 1)
457                 {
458                     *(cc_value-1) = SPC_CC_SEP[0];
459                     SPC_Error(SPC_Bad_Termios_CC, cc_name);
460                 }
461                 else
462                     ccs[cc_array->value] = a_cc;
463
464                 found = TRUE;
465                 break;
466             }
467             cc_array++;
468         }
469
470         if (!found)
471         {
472             *(cc_value-1) = SPC_CC_SEP[0];
473             SPC_Error(SPC_Bad_Termios_CC, cc_name);
474         }
475     }
476 }
477
478 /*----------------------------------------------------------------------+*/
479 XeString SPC_Decode_Termios(struct termios *tio)
480 /*----------------------------------------------------------------------+*/
481 {
482     /* Given a termios struct, return an ascii string representation of */
483     /* it as defined at the front of this file.                         */
484
485 #define RESULT_BUFF_SIZE 32
486
487     XeString all;
488     speed_t speed;
489     XeStringBuffer result = XeMakeStringBuffer(RESULT_BUFF_SIZE);
490
491     XeAppendToStringBuffer(result, SPC_TERMIO_VERSION);
492     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
493     
494     SPC_Decode_TCflag(tio->c_iflag, Input_modes, result);
495     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
496     
497     SPC_Decode_TCflag(tio->c_oflag, Output_modes, result);
498     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
499
500     SPC_Decode_TCflag(tio->c_cflag, Control_modes, result);
501     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
502
503     SPC_Decode_TCflag(tio->c_lflag, Local_modes, result);
504     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
505     
506     speed = cfgetispeed(tio);
507     SPC_Decode_Speed(speed, Baud_rates, result);
508     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
509
510     speed = cfgetospeed(tio);
511     SPC_Decode_Speed(speed, Baud_rates, result);
512     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
513
514     SPC_Decode_CC(tio->c_cc, CC_Array, result);
515     
516     all = strdup(result->buffer);
517
518     XeFree(result->buffer);
519     XeFree(result);
520
521     return all;
522 }
523
524 /*----------------------------------------------------------------------+*/
525 void SPC_Encode_Termios(XeString buff, struct termios *tio)
526 /*----------------------------------------------------------------------+*/
527 {
528     /* Decodes the ascii representation of the termios struct.  The format */
529     /* of the string is defined at the front of this file.                 */
530
531     XeString    item;
532     XeString    protocol_version;
533     int         item_cnt = 0;
534     speed_t     speed;    
535     
536     while ((item = (XeString)STRTOKX(buff, SPC_TERMIO_SEP)))
537     {
538         /* We can possibly have an all blank field.  Walk past them  */
539         /* because the routines we will be calling don't expect any  */
540         /* blanks in the string (but they do check for empty stings).*/
541         while (*item == (XeChar)' ') item++;
542         
543         switch(++item_cnt) 
544         {
545         case SPC_TERMIO_VER_FIELD : 
546             protocol_version = item; 
547             /* Check this some day ??? */
548             break;
549
550         case SPC_TERMIO_IMODE_FIELD : 
551             tio->c_iflag = SPC_Encode_TCflag(item, Input_modes); 
552             break;
553             
554         case SPC_TERMIO_OMODE_FIELD : 
555             tio->c_oflag = SPC_Encode_TCflag(item, Output_modes); 
556             break;
557             
558         case SPC_TERMIO_CMODE_FIELD : 
559             tio->c_cflag = SPC_Encode_TCflag(item, Control_modes); 
560             break;
561             
562         case SPC_TERMIO_LMODE_FIELD : 
563             tio->c_lflag = SPC_Encode_TCflag(item, Local_modes); 
564             break;
565             
566         case SPC_TERMIO_ISPEED_FIELD : 
567             speed = SPC_Encode_Speed(item, Baud_rates);
568             cfsetispeed(tio, speed);
569             break;
570             
571         case SPC_TERMIO_OSPEED_FIELD : 
572             speed = SPC_Encode_Speed(item, Baud_rates);
573             cfsetospeed(tio, speed);
574             break;
575             
576         case SPC_TERMIO_CC_FIELD : 
577             SPC_Encode_CC(item, tio->c_cc, CC_Array); 
578             break;
579
580         default : 
581             break;
582         } /* switch */
583
584
585     } /* while */
586
587     if (item_cnt != SPC_TERMIO_LAST_FIELD)
588         SPC_Error(SPC_Bad_Termios_Proto, 
589                   (XeString) ((item_cnt < SPC_TERMIO_LAST_FIELD) ? "Too Few" : "Too Many"));
590
591 }    
592
593 #ifdef TESTING
594 /*----------------------------------------------------------------------+*/
595 main()
596 /*----------------------------------------------------------------------+*/
597 {
598     XeString s, s1, s2;
599     int i;
600     struct termios tio, tio2;
601     speed_t speed;
602     
603     tio.c_iflag = BRKINT | IGNPAR | ICRNL | IXON;
604     tio.c_oflag = OPOST | ONLCR;
605     tio.c_cflag = CS7 | CREAD | CLOCAL;
606     tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
607
608     tio.c_reserved = 0;    
609     for(i=0; i<NCCS; i++) 
610         tio.c_cc[i] = 0;
611     tio.c_cc[VERASE] = 101;
612     tio.c_cc[VEOF]   = 102;
613     tio.c_cc[VSTOP]  = 103;
614     
615
616     tio2.c_iflag = 0;
617     tio2.c_oflag = 0;
618     tio2.c_cflag = 0;
619     tio2.c_lflag = 0;
620
621     tio2.c_reserved = 0;    
622     for(i=0; i<NCCS; i++) 
623         tio2.c_cc[i] = 0;
624
625     cfsetispeed(&tio, B9600);
626     cfsetospeed(&tio, B1200);
627     
628     s1 = strdup(s = SPC_Decode_Termios(&tio));
629     printf("Decoded string=\n<%s>\n\n", s);
630
631
632     SPC_Encode_Termios(s, &tio2);
633     s2 = strdup(s = SPC_Decode_Termios(&tio2));
634     printf("String after Encoding/decoding=\n<%s>\n\n", s2);
635
636     if (strcmp(s1, s2) == 0)
637         printf("...Identical ...\n");
638     else
639         printf("...Mismatch ...\n");
640     
641 }    
642 #endif /* TESTING */