1 /*
2  * tio - a simple TTY terminal I/O application
3  *
4  * Copyright (c) 2014-2018  Martin Lund
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
22 #include "config.h"
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <stdbool.h>
29 #include <errno.h>
30 #include <getopt.h>
31 #include <termios.h>
32 #include <limits.h>
33 #include "tio/options.h"
34 #include "tio/error.h"
35 
36 /* Default options */
37 struct option_t option =
38 {
39     "",       // Device name
40     115200,   // Baudrate
41     8,        // Databits
42     "none",   // Flow
43     1,        // Stopbits
44     "none",   // Parity
45     0,        // No output delay
46     false,    // No autoconnect
47     false,    // No log
48     false,    // No local echo
49     false,    // No timestamp
50     "",       // Log filename
51     ""        // Map string
52 };
53 
print_help(char * argv[])54 void print_help(char *argv[])
55 {
56     printf("Usage: %s [<options>] <tty-device>\n", argv[0]);
57     printf("\n");
58     printf("Options:\n");
59     printf("  -b, --baudrate <bps>        Baud rate (default: 115200)\n");
60     printf("  -d, --databits 5|6|7|8      Data bits (default: 8)\n");
61     printf("  -f, --flow hard|soft|none   Flow control (default: none)\n");
62     printf("  -s, --stopbits 1|2          Stop bits (default: 1)\n");
63     printf("  -p, --parity odd|even|none  Parity (default: none)\n");
64     printf("  -o, --output-delay <ms>     Output delay (default: 0)\n");
65     printf("  -n, --no-autoconnect        Disable automatic connect\n");
66     printf("  -e, --local-echo            Do local echo\n");
67     printf("  -t, --timestamp             Prefix each new line with a timestamp\n");
68     printf("  -l, --log <filename>        Log to file\n");
69     printf("  -m, --map <flags>           Map special characters\n");
70     printf("  -v, --version               Display version\n");
71     printf("  -h, --help                  Display help\n");
72     printf("\n");
73     printf("See the man page for list of supported mapping flags.\n");
74     printf("\n");
75     printf("In session, press ctrl-t q to quit.\n");
76     printf("\n");
77 }
78 
string_to_long(char * string)79 long string_to_long(char *string)
80 {
81     long result;
82     char *end_token;
83 
84     errno = 0;
85     result = strtol(string, &end_token, 10);
86     if ((errno != 0) || (*end_token != 0))
87     {
88         error_printf("Invalid digit");
89         exit(EXIT_FAILURE);
90     }
91 
92     return result;
93 }
94 
parse_options(int argc,char * argv[])95 void parse_options(int argc, char *argv[])
96 {
97     int c;
98 
99     if (argc == 1)
100     {
101         print_help(argv);
102         exit(EXIT_SUCCESS);
103     }
104 
105     while (1)
106     {
107         static struct option long_options[] =
108         {
109             {"baudrate",       required_argument, 0, 'b'},
110             {"databits",       required_argument, 0, 'd'},
111             {"flow",           required_argument, 0, 'f'},
112             {"stopbits",       required_argument, 0, 's'},
113             {"parity",         required_argument, 0, 'p'},
114             {"output-delay",   required_argument, 0, 'o'},
115             {"no-autoconnect", no_argument,       0, 'n'},
116             {"local-echo",     no_argument,       0, 'e'},
117             {"timestamp",      no_argument,       0, 't'},
118             {"log",            required_argument, 0, 'l'},
119             {"map",            required_argument, 0, 'm'},
120             {"version",        no_argument,       0, 'v'},
121             {"help",           no_argument,       0, 'h'},
122             {0,                0,                 0,  0 }
123         };
124 
125         /* getopt_long stores the option index here */
126         int option_index = 0;
127 
128         /* Parse argument using getopt_long */
129         c = getopt_long(argc, argv, "b:d:f:s:p:o:netl:m:vh", long_options, &option_index);
130 
131         /* Detect the end of the options */
132         if (c == -1)
133             break;
134 
135         switch (c)
136         {
137             case 0:
138                 /* If this option sets a flag, do nothing else now */
139                 if (long_options[option_index].flag != 0)
140                     break;
141                 printf("option %s", long_options[option_index].name);
142                 if (optarg)
143                     printf(" with arg %s", optarg);
144                 printf("\n");
145                 break;
146 
147             case 'b':
148                 option.baudrate = string_to_long(optarg);
149                 break;
150 
151             case 'd':
152                 option.databits = string_to_long(optarg);
153                 break;
154 
155             case 'f':
156                 option.flow = optarg;
157                 break;
158 
159             case 's':
160                 option.stopbits = string_to_long(optarg);
161                 break;
162 
163             case 'p':
164                 option.parity = optarg;
165                 break;
166 
167             case 'o':
168                 option.output_delay = string_to_long(optarg);
169                 break;
170 
171             case 'n':
172                 option.no_autoconnect = true;
173                 break;
174 
175             case 'e':
176                 option.local_echo = true;
177                 break;
178 
179             case 't':
180                 option.timestamp = true;
181                 break;
182 
183             case 'l':
184                 option.log = true;
185                 option.log_filename = optarg;
186                 break;
187 
188             case 'm':
189                 option.map = optarg;
190                 break;
191 
192             case 'v':
193                 printf("tio v%s\n", VERSION);
194                 printf("Copyright (c) 2014-2018 Martin Lund\n");
195                 printf("\n");
196                 printf("License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl-2.0.html>.\n");
197                 printf("This is free software: you are free to change and redistribute it.\n");
198                 printf("There is NO WARRANTY, to the extent permitted by law.\n");
199                 exit(EXIT_SUCCESS);
200                 break;
201 
202             case 'h':
203                 print_help(argv);
204                 exit(EXIT_SUCCESS);
205                 break;
206 
207             case '?':
208                 /* getopt_long already printed an error message */
209                 exit(EXIT_FAILURE);
210                 break;
211 
212             default:
213                 exit(EXIT_FAILURE);
214         }
215     }
216 
217     /* Assume first non-option is the tty device name */
218     if (optind < argc)
219         option.tty_device = argv[optind++];
220 
221     if (strlen(option.tty_device) == 0)
222     {
223         error_printf("Missing device name");
224         exit(EXIT_FAILURE);
225     }
226 
227     /* Print any remaining command line arguments (unknown options) */
228     if (optind < argc)
229     {
230         printf("Error: unknown arguments: ");
231         while (optind < argc)
232             printf("%s ", argv[optind++]);
233         printf("\n");
234         exit(EXIT_FAILURE);
235     }
236 }
237