Add GNU LGPL headers to all .c .C and .h files
[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 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 /*
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)
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     "OFILL",    OFILL,
149     "OFDEL",    OFDEL,
150     "NLDLY",    NLDLY,
151     "NL0",      NL0,
152     "NL1",      NL1,
153     "CRDLY",    CRDLY,
154     "CR0",      CR0,
155     "CR1",      CR1,
156     "CR2",      CR2,
157     "CR3",      CR3,
158     "TABDLY",   TABDLY,
159     "TAB0",     TAB0,
160     "TAB1",     TAB1,
161     "TAB2",     TAB2,
162     "TAB3",     TAB3,
163     "BSDLY",    BSDLY,
164     "BS0",      BS0,
165     "BS1",      BS1,
166     "VTDLY",    VTDLY,
167     "VT0",      VT0,
168     "VT1",      VT1,
169     "FFDLY",    FFDLY,
170     "FF0",      FF0,
171     "FF1",      FF1,
172     END_OF_LIST, 0
173 };
174
175
176 static struct baud_s Baud_rates[] = {    
177     "B0",       B0,
178     "B50",      B50,
179     "B75",      B75,
180     "B110",     B110,
181     "B134",     B134,
182     "B150",     B150,
183     "B200",     B200,
184     "B300",     B300,
185     "B600",     B600,
186     "B1200",    B1200,
187     "B1800",    B1800,
188     "B2400",    B2400,
189     "B4800",    B4800,
190     "B9600",    B9600,
191     "B19200",   B19200,
192     "B38400",   B38400,
193     END_OF_LIST, 0
194 };
195
196
197 static struct modes_s Control_modes[] = {    
198     "CSIZE",    CSIZE,
199     "CS5",      CS5,
200     "CS6",      CS6,
201     "CS7",      CS7,
202     "CS8",      CS8,
203     "CSTOPB",   CSTOPB,
204     "CREAD",    CREAD,
205     "PARENB",   PARENB,
206     "PARODD",   PARODD,
207     "HUPCL",    HUPCL,
208     "CLOCAL",   CLOCAL,
209     END_OF_LIST, 0
210 };
211
212
213 static struct modes_s Local_modes[] = {    
214     "ECHO",     ECHO,
215     "ECHOE",    ECHOE,
216     "ECHOK",    ECHOK,
217     "ECHONL",   ECHONL,
218     "ICANON",   ICANON,
219     "IEXTEN",   IEXTEN,
220     "ISIG",     ISIG,
221     "NOFLSH",   NOFLSH,
222     "TOSTOP",   TOSTOP,
223     END_OF_LIST, 0
224 };
225
226
227 static struct cc_s CC_Array[] = {    
228     "VEOF",     VEOF,
229     "VEOL",     VEOL,
230     "VERASE",   VERASE,
231     "VINTR",    VINTR,
232     "VKILL",    VKILL,
233     "VMIN",     VMIN,
234     "VQUIT",    VQUIT,
235     "VSTART",   VSTART,
236     "VSTOP",    VSTOP,
237     "VSUSP",    VSUSP,
238     "VTIME",    VTIME,
239     END_OF_LIST, 0
240 };
241
242     
243 /*----------------------------------------------------------------------+*/
244 static void 
245     SPC_Decode_TCflag(tcflag_t       flag, 
246                       struct modes_s modes[], 
247                       XeStringBuffer buff)
248 /*----------------------------------------------------------------------+*/
249 {
250     Boolean first_time = TRUE;
251     
252     /* Given a binary representation of flag (tcflag_t), convert */
253     /* it into a comma separated list of ASCII flag names.            */
254
255     while (strcmp(modes->name, END_OF_LIST) != 0)
256     {
257         if ( (modes->value & flag) == modes->value)
258         {
259             if (first_time) 
260                 first_time = FALSE;
261             else
262                 XeAppendToStringBuffer(buff, SPC_TCFLAG_SEP);
263
264             XeAppendToStringBuffer(buff, modes->name);
265         }
266         modes++;
267     }
268     
269     /* We need at least one blank for strtokx to work when */
270     /* we take this string apart on the other side.        */
271     /* --------------------------------------------------- */
272     if (first_time)
273         XeAppendToStringBuffer(buff, (XeString)" ");
274 }
275
276 /*----------------------------------------------------------------------+*/
277 static tcflag_t 
278     SPC_Encode_TCflag(XeString       buff,  
279                       struct modes_s modes[])
280 /*----------------------------------------------------------------------+*/
281 {
282     /* Given a comma separated list of flag names, convert the list */
283     /* into a "tcflag_t" (binary) representation of that list.      */
284
285     XeString item;
286     tcflag_t flag = (tcflag_t)0;
287     struct modes_s *orig_modes = modes;
288     
289     if (!*buff) 
290         return flag;
291     
292     while (item = (XeString)STRTOKX(buff, SPC_TCFLAG_SEP))
293     {
294         Boolean found = FALSE;
295         
296         modes = orig_modes;
297         while (strcmp(modes->name, END_OF_LIST) != 0)
298         {
299             if (strcmp(modes->name, item) == 0)
300             {
301                 flag |= modes->value;
302                 found = TRUE;
303                 break;
304             }
305             modes++;
306         }
307
308         if (!found)
309             SPC_Error(SPC_Bad_Termios_Mode, item);
310     }
311
312     return flag;
313 }
314
315 /*----------------------------------------------------------------------+*/
316 static void 
317     SPC_Decode_Speed(speed_t        speed, 
318                      struct baud_s  bauds[], 
319                      XeStringBuffer buff)
320 /*----------------------------------------------------------------------+*/
321 {
322     /* Given a binary "speed_t" speed specification, convert it into */
323     /* a single ASCII string.                                        */
324
325     while (strcmp(bauds->name, END_OF_LIST) != 0)
326     {
327         if (bauds->speed == speed)
328         {
329             XeAppendToStringBuffer(buff, bauds->name);
330             return;
331         }
332         bauds++;
333     }
334
335     /* We need at least one blank for strtokx to work when */
336     /* we take this string apart on the other side.        */
337     /* --------------------------------------------------- */
338     XeAppendToStringBuffer(buff, (XeString)" ");
339 }
340
341 /*----------------------------------------------------------------------+*/
342 static speed_t 
343     SPC_Encode_Speed(XeString      buff,  
344                      struct baud_s bauds[])
345 /*----------------------------------------------------------------------+*/
346 {
347 #define DEFAULT_SPEED B9600
348     
349     /* Given a single ASCII name of a termio speed item, convert it into */
350     /* a binary (speed_t) representation.                                */
351     
352     if (!*buff) 
353         return DEFAULT_SPEED;
354     
355     while (strcmp(bauds->name, END_OF_LIST) != 0)
356     {
357         if (strcmp(bauds->name, buff) == 0)
358             return bauds->speed;
359         bauds++;
360     }
361     
362     SPC_Error(SPC_Bad_Termios_Speed, buff);
363     return DEFAULT_SPEED;
364 }
365
366 /*----------------------------------------------------------------------+*/
367 static void 
368     SPC_Decode_CC(cc_t           ccs[], 
369                   struct cc_s    cc_array[], 
370                   XeStringBuffer buff)
371 /*----------------------------------------------------------------------+*/
372 {
373     Boolean first_time = TRUE;
374
375     /* Given an array of cc_s from a termios struct (binary        */
376     /* representation), convert it into a comma sepearted list of  */
377     /* CC names and values of the form <name>=<value>              */
378     
379     while (strcmp(cc_array->name, END_OF_LIST) != 0)
380     {
381         int index = ccs[cc_array->value];
382         if ( index != 0 )
383         {
384             XeChar num[30];
385
386             if (first_time) 
387                 first_time = FALSE;
388             else
389                 XeAppendToStringBuffer(buff, SPC_TCFLAG_SEP);
390
391             XeAppendToStringBuffer(buff, cc_array->name);
392             XeAppendToStringBuffer(buff, SPC_CC_SEP);
393             sprintf(num, SPC_CC_FORMAT, index);
394             XeAppendToStringBuffer(buff, num);
395         }
396         cc_array++;
397     }
398
399     /* We need at least one blank for strtokx to work when */
400     /* we take this string apart on the other side.        */
401     /* --------------------------------------------------- */
402     if (first_time)
403         XeAppendToStringBuffer(buff, (XeString)" ");
404 }
405
406 /*----------------------------------------------------------------------+*/
407 static void 
408     SPC_Encode_CC(XeString    buff,  
409                   cc_t        ccs[], 
410                   struct cc_s cc_array[])
411 /*----------------------------------------------------------------------+*/
412 {
413     /* we should have gotten a string that looks like this:               */
414     /*                                                                    */
415     /* <V-Name>=<value>,<V-Name>=<value>...                               */
416     /*                                                                    */
417     /* For example:   VEOF=4,VKILL=8                                      */
418     /*                                                                    */
419     /* Parse this array and store the values in the "ccs" array passed in */
420     /* to us.  It is assumed that the <V-name> strings are all defined in */
421     /* the "cc_array" list passed to us.                                  */
422     /* ------------------------------------------------------------------ */
423
424     XeString cc_name, cc_value;
425     int i;
426     unsigned int a_cc;
427     struct cc_s *orig_cc_array = cc_array;
428
429     for(i=0; i<NCCS; i++) 
430         ccs[i] = 0;
431     
432     if (!*buff) return;
433     
434     while (cc_name = (XeString)STRTOKX(buff, SPC_TCFLAG_SEP))
435     {
436         Boolean found = FALSE;
437
438         cc_value = strchr(cc_name, SPC_CC_SEP[0]);      /* Go find the "=" */
439         if (!cc_value)
440         {
441             SPC_Error(SPC_Bad_Termios_CC, cc_name);
442             continue;
443         }
444         *cc_value++ = XeChar_NULL;                      /* Replace "=" with null */
445         
446
447         /* Look for "V-Name" in table ... */
448         /* ------------------------------ */
449         cc_array = orig_cc_array;
450         while (strcmp(cc_array->name, END_OF_LIST) != 0)
451         {
452             if (strcmp(cc_array->name, cc_name) == 0)
453             {
454                 if (sscanf(cc_value, SPC_CC_FORMAT, &a_cc) != 1)
455                 {
456                     *(cc_value-1) = SPC_CC_SEP[0];
457                     SPC_Error(SPC_Bad_Termios_CC, cc_name);
458                 }
459                 else
460                     ccs[cc_array->value] = a_cc;
461
462                 found = TRUE;
463                 break;
464             }
465             cc_array++;
466         }
467
468         if (!found)
469         {
470             *(cc_value-1) = SPC_CC_SEP[0];
471             SPC_Error(SPC_Bad_Termios_CC, cc_name);
472         }
473     }
474 }
475
476 /*----------------------------------------------------------------------+*/
477 XeString SPC_Decode_Termios(struct termios *tio)
478 /*----------------------------------------------------------------------+*/
479 {
480     /* Given a termios struct, return an ascii string representation of */
481     /* it as defined at the front of this file.                         */
482
483 #define RESULT_BUFF_SIZE 32
484
485     XeString all;
486     speed_t speed;
487     XeStringBuffer result = XeMakeStringBuffer(RESULT_BUFF_SIZE);
488
489     XeAppendToStringBuffer(result, SPC_TERMIO_VERSION);
490     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
491     
492     SPC_Decode_TCflag(tio->c_iflag, Input_modes, result);
493     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
494     
495     SPC_Decode_TCflag(tio->c_oflag, Output_modes, result);
496     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
497
498     SPC_Decode_TCflag(tio->c_cflag, Control_modes, result);
499     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
500
501     SPC_Decode_TCflag(tio->c_lflag, Local_modes, result);
502     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
503     
504     speed = cfgetispeed(tio);
505     SPC_Decode_Speed(speed, Baud_rates, result);
506     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
507
508     speed = cfgetospeed(tio);
509     SPC_Decode_Speed(speed, Baud_rates, result);
510     XeAppendToStringBuffer(result, SPC_TERMIO_SEP);
511
512     SPC_Decode_CC(tio->c_cc, CC_Array, result);
513     
514     all = strdup(result->buffer);
515
516     XeFree(result->buffer);
517     XeFree(result);
518
519     return all;
520 }
521
522 /*----------------------------------------------------------------------+*/
523 void SPC_Encode_Termios(XeString buff, struct termios *tio)
524 /*----------------------------------------------------------------------+*/
525 {
526     /* Decodes the ascii representation of the termios struct.  The format */
527     /* of the string is defined at the front of this file.                 */
528
529     XeString    item;
530     XeString    protocol_version;
531     int         item_cnt = 0;
532     speed_t     speed;    
533     
534     while (item = (XeString)STRTOKX(buff, SPC_TERMIO_SEP))
535     {
536         /* We can possibly have an all blank field.  Walk past them  */
537         /* because the routines we will be calling don't expect any  */
538         /* blanks in the string (but they do check for empty stings).*/
539         while (*item == (XeChar)' ') item++;
540         
541         switch(++item_cnt) 
542         {
543         case SPC_TERMIO_VER_FIELD : 
544             protocol_version = item; 
545             /* Check this some day ??? */
546             break;
547
548         case SPC_TERMIO_IMODE_FIELD : 
549             tio->c_iflag = SPC_Encode_TCflag(item, Input_modes); 
550             break;
551             
552         case SPC_TERMIO_OMODE_FIELD : 
553             tio->c_oflag = SPC_Encode_TCflag(item, Output_modes); 
554             break;
555             
556         case SPC_TERMIO_CMODE_FIELD : 
557             tio->c_cflag = SPC_Encode_TCflag(item, Control_modes); 
558             break;
559             
560         case SPC_TERMIO_LMODE_FIELD : 
561             tio->c_lflag = SPC_Encode_TCflag(item, Local_modes); 
562             break;
563             
564         case SPC_TERMIO_ISPEED_FIELD : 
565             speed = SPC_Encode_Speed(item, Baud_rates);
566             cfsetispeed(tio, speed);
567             break;
568             
569         case SPC_TERMIO_OSPEED_FIELD : 
570             speed = SPC_Encode_Speed(item, Baud_rates);
571             cfsetospeed(tio, speed);
572             break;
573             
574         case SPC_TERMIO_CC_FIELD : 
575             SPC_Encode_CC(item, tio->c_cc, CC_Array); 
576             break;
577
578         default : 
579             break;
580         } /* switch */
581
582
583     } /* while */
584
585     if (item_cnt != SPC_TERMIO_LAST_FIELD)
586         SPC_Error(SPC_Bad_Termios_Proto, 
587                   (XeString) ((item_cnt < SPC_TERMIO_LAST_FIELD) ? "Too Few" : "Too Many"));
588
589 }    
590
591 #ifdef TESTING
592 /*----------------------------------------------------------------------+*/
593 main()
594 /*----------------------------------------------------------------------+*/
595 {
596     XeString s, s1, s2;
597     int i;
598     struct termios tio, tio2;
599     speed_t speed;
600     
601     tio.c_iflag = BRKINT | IGNPAR | ICRNL | IXON;
602     tio.c_oflag = OPOST | ONLCR;
603     tio.c_cflag = CS7 | CREAD | CLOCAL;
604     tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
605
606     tio.c_reserved = 0;    
607     for(i=0; i<NCCS; i++) 
608         tio.c_cc[i] = 0;
609     tio.c_cc[VERASE] = 101;
610     tio.c_cc[VEOF]   = 102;
611     tio.c_cc[VSTOP]  = 103;
612     
613
614     tio2.c_iflag = 0;
615     tio2.c_oflag = 0;
616     tio2.c_cflag = 0;
617     tio2.c_lflag = 0;
618
619     tio2.c_reserved = 0;    
620     for(i=0; i<NCCS; i++) 
621         tio2.c_cc[i] = 0;
622
623     cfsetispeed(&tio, B9600);
624     cfsetospeed(&tio, B1200);
625     
626     s1 = strdup(s = SPC_Decode_Termios(&tio));
627     printf("Decoded string=\n<%s>\n\n", s);
628
629
630     SPC_Encode_Termios(s, &tio2);
631     s2 = strdup(s = SPC_Decode_Termios(&tio2));
632     printf("String after Encoding/decoding=\n<%s>\n\n", s2);
633
634     if (strcmp(s1, s2) == 0)
635         printf("...Identical ...\n");
636     else
637         printf("...Mismatch ...\n");
638     
639 }    
640 #endif /* TESTING */