1 /*      $Id: slinke.c,v 5.6 2010/04/11 18:50:38 lirc Exp $      */
2 
3 /****************************************************************************
4  ** slinke.c ****************************************************************
5  ****************************************************************************
6  *
7  * slinke - simple hack to convert Nirvis Systems Device Files to LIRC
8  + config files
9  *
10  * Copyright (C) 2000 Christoph Bartelmus <lirc@bartelmus.de>
11  *
12  */
13 
14 #ifdef HAVE_CONFIG_H
15 #include <config.h>
16 #endif
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <getopt.h>
21 #include <stdarg.h>
22 #include <ctype.h>
23 #include <limits.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 
28 #include "ir_remote.h"
29 #include "config_file.h"
30 #include "dump_config.h"
31 
32 const char *usage = "Usage: %s --help | --version | [options] file\n";
33 char *progname;
34 struct hardware hw = {
35 	"/dev/null",		/* default device */
36 	-1,			/* fd */
37 	0,			/* features */
38 	0,			/* send_mode */
39 	0,			/* rec_mode */
40 	0,			/* code_length */
41 	NULL,			/* init_func */
42 	NULL,			/* deinit_func */
43 	NULL,			/* send_func */
44 	NULL,			/* rec_func */
45 	NULL,			/* decode_func */
46 	NULL,			/* ioctl_func */
47 	NULL,			/* readdata */
48 	"slinke",		/* name */
49 };
50 
51 #define MAX_LINE_WIDTH 300
52 #define MAX_CODES 100
53 
54 int debug = 0;
55 
logprintf(int prio,const char * format_str,...)56 void logprintf(int prio, const char *format_str, ...)
57 {
58 }
59 
logperror(int prio,const char * s)60 void logperror(int prio, const char *s)
61 {
62 }
63 
get_val(char * buffer,...)64 int get_val(char *buffer, ...)
65 {
66 	va_list ap;
67 	char *next;
68 	int count, flag;
69 	int *n;
70 
71 	va_start(ap, buffer);
72 	count = 0;
73 	flag = 1;
74 
75 	next = strtok(buffer, " \t");
76 	while (next != NULL) {
77 		if (flag) {
78 			n = va_arg(ap, int *);
79 			if (n != NULL) {
80 				*n = atoi(next);
81 			} else {
82 				flag = 0;
83 			}
84 		}
85 		next = strtok(NULL, " \t");
86 		count++;
87 	}
88 	return (count);
89 }
90 
get_data(char * s,ir_code * data,int * bits)91 int get_data(char *s, ir_code * data, int *bits)
92 {
93 	*data = 0;
94 	*bits = 0;
95 	while (*s) {
96 		*data <<= 1;
97 		if (*s == '1') {
98 			*data |= 1;
99 		} else if (*s != '0' && !isspace(*s)) {
100 			return (0);
101 		}
102 		s++;
103 		(*bits)++;
104 	}
105 	return (1);
106 }
107 
strtoupper(char * s)108 void strtoupper(char *s)
109 {
110 	while (*s) {
111 		*s = toupper(*s);
112 		s++;
113 	}
114 }
115 
append_code(struct ir_remote * r,ir_code code,char * name)116 int append_code(struct ir_remote *r, ir_code code, char *name)
117 {
118 	struct ir_ncode *codes;
119 	int count;
120 
121 	count = 0;
122 	codes = r->codes;
123 	while (codes->name != NULL) {
124 		count++;
125 		codes++;
126 	}
127 	if (count > MAX_CODES)
128 		return (0);
129 
130 	codes->name = strdup(name);
131 	strtoupper(codes->name);
132 	codes->code = code;
133 	return (1);
134 }
135 
trim(char * s)136 char *trim(char *s)
137 {
138 	char *end;
139 
140 	while (isspace(*s))
141 		s++;
142 	end = s + strlen(s) - 1;
143 	while (end >= s) {
144 		if (!isspace(*end)) {
145 			end++;
146 			*end = 0;
147 			break;
148 		}
149 		end--;
150 	}
151 	return (s);
152 }
153 
fill_struct(struct ir_remote * r,FILE * f,char ** desc)154 int fill_struct(struct ir_remote *r, FILE * f, char **desc)
155 {
156 	char buffer[MAX_LINE_WIDTH], backup[MAX_LINE_WIDTH];
157 	char *eq, *dp, *cr, *s;
158 
159 	while ((s = fgets(buffer, MAX_LINE_WIDTH, f)) != NULL) {
160 		cr = strrchr(buffer, '\r');
161 		if (cr != NULL)
162 			*cr = 0;
163 		cr = strrchr(buffer, '\n');
164 		if (cr != NULL)
165 			*cr = 0;
166 		printf("%s\n", buffer);
167 		cr = strchr(buffer, '#');
168 		if (cr != NULL)
169 			*cr = 0;
170 
171 		strcpy(backup, buffer);
172 		eq = strchr(buffer, '=');
173 		if (eq != NULL) {
174 			*eq = 0;
175 			eq++;
176 			eq = trim(eq);
177 			if (strcasecmp(buffer, "desc") == 0) {
178 				/* todo */
179 				if (*desc != NULL) {
180 					fprintf(stderr, "%s: mulitple descriptions\n", progname);
181 					break;
182 				}
183 				*desc = strdup(eq);
184 				continue;
185 			} else if (strcasecmp(buffer, "name") == 0) {
186 				if (r->name != NULL) {
187 					fprintf(stderr, "%s: multiple names\n", progname);
188 					break;
189 				}
190 				if (strlen(eq) == 0)
191 					continue;
192 				r->name = strdup(eq);
193 				if (r->name == NULL) {
194 					fprintf(stderr, "%s: out of memory\n", progname);
195 				}
196 				strtoupper(r->name);
197 				continue;
198 			} else if (strcasecmp(buffer, "type") == 0) {
199 				continue;
200 			} else if (strcasecmp(buffer, "group") == 0) {
201 				continue;
202 			} else if (strcasecmp(buffer, "carrier") == 0) {
203 				r->freq = (__u32) atof(eq);
204 				continue;
205 			} else if (strcasecmp(buffer, "repeat") == 0) {
206 				r->min_repeat = atoi(eq);
207 				continue;
208 			} else if (strcasecmp(buffer, "pause") == 0) {
209 				int n, gap;
210 
211 				n = get_val(eq, &gap, 0);
212 				if (n > 1)
213 					break;
214 				if (n == 0)
215 					continue;
216 				/* may be zero for now, but we have to
217 				   check at the end */
218 				if (gap > 0) {
219 					break;
220 				}
221 				r->gap = abs(gap);
222 				continue;
223 			} else if (strcasecmp(buffer, "sleep") == 0) {
224 				int n, gap;
225 
226 				/* no equivalent in LIRC */
227 				if (r->gap == 0) {
228 					n = get_val(eq, &gap, 0);
229 					if (n == 1 && gap < 0) {
230 						r->gap = (lirc_t) abs(gap);
231 					}
232 				}
233 				continue;
234 			} else if (strcasecmp(buffer, "zero") == 0) {
235 				int a, b;
236 
237 				if (get_val(eq, &a, &b, 0) != 2 || a <= 0 || b >= 0) {
238 					break;
239 				}
240 				r->pzero = (lirc_t) a;
241 				r->szero = (lirc_t) abs(b);
242 				continue;
243 			} else if (strcasecmp(buffer, "one") == 0) {
244 				int a, b;
245 
246 				if (get_val(eq, &a, &b, 0) != 2) {
247 					break;
248 				}
249 				if (a < 0 && b > 0) {
250 					r->pone = (lirc_t) b;
251 					r->sone = (lirc_t) abs(a);
252 					set_protocol(r, RC5);
253 					continue;
254 				}
255 				r->pone = (lirc_t) a;
256 				r->sone = (lirc_t) abs(b);
257 				continue;
258 			} else if (strcasecmp(buffer, "start") == 0) {
259 				int a, b, n;
260 
261 				n = get_val(eq, &a, &b, 0);
262 				if (is_rc5(r) && n == 1) {
263 					if (a <= 0) {
264 						break;
265 					}
266 					r->plead = (lirc_t) a;
267 					continue;
268 				}
269 				if (n == 0) {
270 					continue;
271 				}
272 				if (n != 2 || a <= 0 || b >= 0) {
273 					break;
274 				}
275 				r->phead = (lirc_t) a;
276 				r->shead = (lirc_t) abs(b);
277 				continue;
278 			} else if (strcasecmp(buffer, "stop") == 0) {
279 				int n;
280 				int a, b, c, d, e;
281 
282 				n = get_val(eq, &a, &b, &c, &d, &e, 0);
283 				if (n == 5) {
284 
285 					if (a > 0 && c > 0 && e > 0 && b < 0 && d < 0 && a == e) {
286 						r->ptrail = (lirc_t) a;
287 						r->gap = (lirc_t) abs(b);
288 						r->prepeat = (lirc_t) c;
289 						r->srepeat = (lirc_t) abs(d);
290 						if (e != a) {
291 							break;
292 						}
293 						continue;
294 					}
295 				}
296 				if (n == 0) {
297 					r->ptrail = (lirc_t) 0;
298 					continue;
299 				}
300 				if (n > 2 || a <= 0) {
301 					break;
302 				}
303 				if (n == 2 && b < 0) {
304 					if (r->gap == 0)
305 						r->gap = abs(b);
306 				}
307 				r->ptrail = (lirc_t) a;
308 				continue;
309 			} else if (strcasecmp(buffer, "prefix") == 0) {
310 				if (has_pre(r)) {
311 					fprintf(stderr, "warning: multiple prefix tokens\n");
312 					continue;
313 				}
314 				if (!get_data(eq, &r->pre_data, &r->pre_data_bits)) {
315 					break;
316 				}
317 				continue;
318 			} else if (strcasecmp(buffer, "suffix") == 0) {
319 				if (has_post(r)) {
320 					fprintf(stderr, "warning: multiple suffix tokens\n");
321 					continue;
322 				}
323 				if (!get_data(eq, &r->post_data, &r->post_data_bits)) {
324 					break;
325 				}
326 				continue;
327 			} else if (strcasecmp(buffer, "include") == 0) {
328 				FILE *nf;
329 
330 				nf = fopen(eq, "r");
331 				if (nf == NULL) {
332 					fprintf(stderr, "%s: could not open file %s\n", progname, eq);
333 					perror(progname);
334 					break;
335 				}
336 				if (!fill_struct(r, nf, desc)) {
337 					fclose(nf);
338 					return (0);
339 				}
340 				fclose(nf);
341 				continue;
342 			}
343 		}
344 		dp = strchr(buffer, ':');
345 		if (dp != NULL) {
346 			int bits;
347 			ir_code code;
348 
349 			*dp = 0;
350 			dp++;
351 			dp = trim(dp);
352 			get_data(buffer, &code, &bits);
353 			if (r->bits == 0)
354 				r->bits = bits;
355 			else if (r->bits != bits) {
356 				fprintf(stderr, "%s: variable bit length!\n", progname);
357 				break;
358 			}
359 			if (!append_code(r, code, dp)) {
360 				break;
361 			}
362 			continue;
363 
364 		}
365 		if (strtok(buffer, " \t") == NULL) {
366 			continue;
367 		}
368 		printf("%s\n", buffer);
369 	}
370 	if (s == NULL) {
371 		if (r->gap == 0) {
372 			if (r->repeat_gap != 0) {
373 				r->gap = r->repeat_gap;
374 				r->repeat_gap = 0;
375 			} else {
376 				fprintf(stderr, "%s: no gap!\n", progname);
377 				return (0);
378 			}
379 		}
380 		return (1);
381 	}
382 
383 	fprintf(stderr, "%s: can't convert \"%s\"\n", progname, backup);
384 	free_config(r);
385 	return (0);
386 }
387 
read_slinke(char * filename,char ** desc)388 struct ir_remote *read_slinke(char *filename, char **desc)
389 {
390 	struct ir_remote *r;
391 	FILE *f;
392 
393 	r = malloc(sizeof(*r));
394 	if (r == NULL) {
395 		fprintf(stderr, "%s: out of memory\n", progname);
396 		return (NULL);
397 	}
398 	/* set defaults */
399 	memset(r, 0, sizeof(*r));
400 	set_protocol(r, SPACE_ENC);
401 	r->eps = 20;
402 	r->aeps = 200;
403 
404 	r->codes = malloc(sizeof(struct ir_ncode) * (MAX_CODES + 1));
405 	if (r->codes == NULL) {
406 		fprintf(stderr, "%s: out of memory\n", progname);
407 		free(r);
408 		return (NULL);
409 	}
410 	memset(r->codes, 0, sizeof(struct ir_ncode) * (MAX_CODES + 1));
411 	f = fopen(filename, "r");
412 	if (f == NULL) {
413 		fprintf(stderr, "%s: could not open file %s\n", progname, filename);
414 		perror(progname);
415 		free(r->codes);
416 		free(r);
417 		return (NULL);
418 	}
419 	if (!fill_struct(r, f, desc)) {
420 		fclose(f);
421 		return (NULL);
422 	}
423 	fclose(f);
424 	return (r);
425 }
426 
get_pre_data(struct ir_remote * remote)427 void get_pre_data(struct ir_remote *remote)
428 {
429 	struct ir_ncode *codes;
430 	ir_code mask, last;
431 	int count, i;
432 
433 	if (remote->bits == 0)
434 		return;
435 
436 	mask = (-1);
437 	codes = remote->codes;
438 	if (codes->name != NULL) {
439 		last = codes->code;
440 		codes++;
441 	}
442 	if (codes->name == NULL)
443 		return;		/* at least 2 codes needed */
444 	while (codes->name != NULL) {
445 		mask &= ~(last ^ codes->code);
446 		last = codes->code;
447 		codes++;
448 	}
449 	count = 0;
450 	while (mask & 0x8000000000000000LL) {
451 		count++;
452 		mask = mask << 1;
453 	}
454 	count -= sizeof(ir_code) * CHAR_BIT - remote->bits;
455 	if (count > 0) {
456 		mask = 0;
457 		for (i = 0; i < count; i++) {
458 			mask = mask << 1;
459 			mask |= 1;
460 		}
461 		remote->bits -= count;
462 		mask = mask << (remote->bits);
463 		remote->pre_data_bits = count;
464 		remote->pre_data = (last & mask) >> (remote->bits);
465 
466 		codes = remote->codes;
467 		while (codes->name != NULL) {
468 			codes->code &= ~mask;
469 			codes++;
470 		}
471 	}
472 }
473 
get_post_data(struct ir_remote * remote)474 void get_post_data(struct ir_remote *remote)
475 {
476 	struct ir_ncode *codes;
477 	ir_code mask, last;
478 	int count, i;
479 
480 	if (remote->bits == 0)
481 		return;
482 
483 	mask = (-1);
484 	codes = remote->codes;
485 	if (codes->name != NULL) {
486 		last = codes->code;
487 		codes++;
488 	}
489 	if (codes->name == NULL)
490 		return;		/* at least 2 codes needed */
491 	while (codes->name != NULL) {
492 		mask &= ~(last ^ codes->code);
493 		last = codes->code;
494 		codes++;
495 	}
496 	count = 0;
497 	while (mask & 0x1) {
498 		count++;
499 		mask = mask >> 1;
500 	}
501 	if (count > 0) {
502 		mask = 0;
503 		for (i = 0; i < count; i++) {
504 			mask = mask << 1;
505 			mask |= 1;
506 		}
507 		remote->bits -= count;
508 		remote->post_data_bits = count;
509 		remote->post_data = last & mask;
510 
511 		codes = remote->codes;
512 		while (codes->name != NULL) {
513 			codes->code = codes->code >> count;
514 			codes++;
515 		}
516 	}
517 }
518 
main(int argc,char ** argv)519 int main(int argc, char **argv)
520 {
521 	char *filename, *model, *brand, *description, *path, cwd[PATH_MAX + 1];
522 	struct ir_remote *remote;
523 	int fd;
524 	FILE *fout;
525 	int pre, post;
526 
527 	progname = argv[0];
528 	model = brand = NULL;
529 	pre = post = 0;
530 	while (1) {
531 		int c;
532 		static struct option long_options[] = {
533 			{"help", no_argument, NULL, 'h'},
534 			{"version", no_argument, NULL, 'v'},
535 			{"brand", required_argument, NULL, 'b'},
536 			{"model", required_argument, NULL, 'm'},
537 			{"pre", no_argument, NULL, 'p'},
538 			{"post", no_argument, NULL, 'P'},
539 			{0, 0, 0, 0}
540 		};
541 		c = getopt_long(argc, argv, "hvb:m:pP", long_options, NULL);
542 		if (c == -1)
543 			break;
544 		switch (c) {
545 		case 'h':
546 			printf(usage, progname);
547 			printf("\t -h --help\t\tdisplay this message\n");
548 			printf("\t -v --version\t\tdisplay version\n\n");
549 			printf("\t -b --brand\t\tremote control manufacturer\n");
550 			printf("\t -m --model\t\tremote control model = name of new file\n");
551 			exit(EXIT_SUCCESS);
552 		case 'v':
553 			printf("slinke-%s\n", VERSION);
554 			exit(EXIT_SUCCESS);
555 		case 'b':
556 			brand = optarg;
557 			break;
558 		case 'm':
559 			model = optarg;
560 			break;
561 		case 'p':
562 			pre = 1;
563 			break;
564 		case 'P':
565 			post = 1;
566 			break;
567 		default:
568 			printf("Try %s -h for help!\n", progname);
569 			exit(EXIT_FAILURE);
570 		}
571 	}
572 	if (argc == 1) {
573 		printf(usage, progname);
574 	}
575 	if (optind + 1 != argc) {
576 		fprintf(stderr, "%s: invalid argument count\n", progname);
577 		exit(EXIT_FAILURE);
578 	}
579 	filename = argv[optind];
580 
581 	path = strrchr(filename, '/');
582 	if (path != NULL) {
583 		char *help;
584 
585 		*path = 0;
586 		help = path + 1;
587 		path = filename;
588 		filename = help;
589 		if (getcwd(cwd, PATH_MAX) == NULL) {
590 			fprintf(stderr, "%s: can't get current work directory\n", progname);
591 			perror(progname);
592 			return (EXIT_FAILURE);
593 		}
594 		chdir(path);
595 	}
596 	description = NULL;
597 	remote = read_slinke(filename, &description);
598 	if (remote == NULL) {
599 		exit(EXIT_FAILURE);
600 	}
601 	if (model != NULL) {
602 		if (remote->name != NULL)
603 			free(remote->name);
604 		remote->name = strdup(model);
605 		if (remote->name == NULL) {
606 			free_config(remote);
607 			exit(EXIT_FAILURE);
608 		}
609 	}
610 	if (pre)
611 		get_pre_data(remote);
612 	if (post)
613 		get_post_data(remote);
614 
615 	if (remote->name == NULL) {
616 		char newname[100];
617 		char *cr;
618 
619 		if (description != NULL) {
620 			printf("Description: %s\n", description);
621 		}
622 		printf("Please enter name: ");
623 		fflush(stdout);
624 		if (fgets(newname, 100, stdin) == NULL) {
625 			free_config(remote);
626 			exit(EXIT_FAILURE);
627 		}
628 		cr = strrchr(newname, '\n');
629 		if (cr != NULL)
630 			*cr = 0;
631 		cr = strrchr(newname, '\r');
632 		if (cr != NULL)
633 			*cr = 0;
634 
635 		remote->name = strdup(newname);
636 		if (remote->name == NULL) {
637 			fprintf(stderr, "%s: out of memory\n", progname);
638 			free_config(remote);
639 			exit(EXIT_FAILURE);
640 		}
641 
642 	}
643 	if (path != NULL) {
644 		chdir(cwd);
645 	}
646 	fd = open(remote->name, O_CREAT | O_EXCL | O_RDWR, 0644);
647 	if (fd == -1) {
648 		fprintf(stderr, "%s: could not open output file\n", progname);
649 		perror(progname);
650 		free_config(remote);
651 		if (description != NULL)
652 			free(description);
653 		exit(EXIT_FAILURE);
654 	}
655 	fout = fdopen(fd, "w");
656 	if (fout == NULL) {
657 		fprintf(stderr, "%s: could not reopen output file\n", progname);
658 		perror(progname);
659 		free_config(remote);
660 		if (description != NULL)
661 			free(description);
662 		exit(EXIT_FAILURE);
663 	}
664 	fprintf(fout,
665 		"#\n"
666 		"# This config file has been automatically converted from a device file\n"
667 		"# found in the 06/26/00 release of the Windows Slink-e software\n"
668 		"# package.\n" "#\n" "# Many thanks to Colby Boles of Nirvis Systems Inc. for allowing us to\n"
669 		"# use these files.\n" "#\n" "# The original filename was: \"%s\"\n", filename);
670 	if (description != NULL) {
671 		fprintf(fout, "#\n" "# The original description for this device was:\n" "#\n" "# %s\n" "#\n",
672 			description);
673 		free(description);
674 	}
675 	fprintf(fout, "\n\n");
676 	fprint_remote_head(fout, remote);
677 	fprint_remote_signals(fout, remote);
678 	fprint_remote_foot(fout, remote);
679 	fclose(fout);
680 
681 	free_config(remote);
682 	exit(EXIT_SUCCESS);
683 }
684