Example #1
0
inline void send_post(struct ir_remote *remote)
{
	if(has_post(remote))
	{
		if(remote->post_p>0 && remote->post_s>0)
		{
			send_pulse(remote->post_p);
			send_space(remote->post_s);
		}
		send_data(remote,remote->post_data,remote->post_data_bits,
			  remote->pre_data_bits+remote->bits);
	}
}
Example #2
0
static struct ir_remote * read_config_recursive(FILE *f, const char *name, int depth)
{
	char buf[LINE_LEN+1], *key, *val, *val2;
        int len,argc;
	struct ir_remote *top_rem=NULL,*rem=NULL;
        struct void_array codes_list,raw_codes,signals;
	struct ir_ncode raw_code={NULL,0,0,NULL};
	struct ir_ncode name_code={NULL,0,0,NULL};
	struct ir_ncode *code;
	int mode=ID_none;

	line=0;
	parse_error=0;
	LOGPRINTF(2, "parsing '%s'", name);

	while(fgets(buf,LINE_LEN,f)!=NULL)
	{
		line++;
		len=strlen(buf);
		if(len==LINE_LEN && buf[len-1]!='\n')
		{
			logprintf(LOG_ERR,"line %d too long in config file",
				  line);
			parse_error=1;
			break;
		}

		if(len>0)
		{
			len--;
			if(buf[len]=='\n') buf[len]=0;
		}
		if(len>0)
		{
			len--;
			if(buf[len]=='\r') buf[len]=0;
		}
                /* ignore comments */
                if(buf[0]=='#'){
			continue;
                }
		key=strtok(buf, whitespace);
		/* ignore empty lines */
		if(key==NULL) continue;
		val=strtok(NULL, whitespace);
		if(val!=NULL){
			val2=strtok(NULL, whitespace);
			LOGPRINTF(3,"\"%s\" \"%s\"",key,val);
			if (strcasecmp("include",key)==0){
                                FILE* childFile;
				const char *childName;
				const char *fullPath;
				char result[FILENAME_MAX+1];


				if (depth > MAX_INCLUDES) {
					logprintf(LOG_ERR,"error opening child file defined at %s:%d",name,line);
					logprintf(LOG_ERR,"too many files included");
					parse_error=-1;
					break;
				}

				childName = lirc_parse_include(val);
				if (!childName){
					logprintf(LOG_ERR,"error parsing child file value defined at line %d:",line);
					logprintf(LOG_ERR,"invalid quoting");
					parse_error=-1;
					break;
				}

				fullPath = lirc_parse_relative(result, sizeof(result), childName, name);
				if (!fullPath) {
					logprintf(LOG_ERR,"error composing relative file path defined at line %d:",line);
					logprintf(LOG_ERR,"resulting path too long");
					parse_error=-1;
					break;
				}

				childFile = fopen(fullPath, "r");
				if (childFile == NULL){
					logprintf(LOG_ERR,"error opening child file '%s' defined at line %d:",fullPath, line);
					logprintf(LOG_ERR,"ignoring this child file for now.");
				}
				else{
					int save_line = line;

					if (!top_rem){
						/* create first remote */
						LOGPRINTF(2,"creating first remote");
						rem = read_config_recursive(childFile, fullPath, depth + 1);
						if(rem != (void *) -1 && rem != NULL) {
							top_rem = rem;
						} else {
							rem = NULL;
						}
					}else{
						/* create new remote */
						LOGPRINTF(2,"creating next remote");
						rem->next=read_config_recursive(childFile, fullPath, depth + 1);
						if(rem->next != (void *) -1 && rem->next != NULL) {
							rem=rem->next;
						} else {
							rem->next = NULL;
						}
					}
					fclose(childFile);
					line = save_line;
				}
			}else if (strcasecmp("begin",key)==0){
				if (strcasecmp("codes", val)==0){
                                        /* init codes mode */
					LOGPRINTF(2,"    begin codes");
					if (!checkMode(mode, ID_remote,
						       "begin codes")) break;
					if (rem->codes){
						logprintf(LOG_ERR,"error in configfile line %d:",line);
						logprintf(LOG_ERR,"codes are already defined");
						parse_error=1;
						break;
					}

                                        init_void_array(&codes_list,30, sizeof(struct ir_ncode));
                                        mode=ID_codes;
                                }else if(strcasecmp("raw_codes",val)==0){
                                        /* init raw_codes mode */
					LOGPRINTF(2,"    begin raw_codes");
					if(!checkMode(mode, ID_remote,
						  "begin raw_codes")) break;
					if (rem->codes){
						logprintf(LOG_ERR,"error in configfile line %d:",line);
						logprintf(LOG_ERR,"codes are already defined");
						parse_error=1;
						break;
					}
					set_protocol(rem, RAW_CODES);
					raw_code.code=0;
                                        init_void_array(&raw_codes,30, sizeof(struct ir_ncode));
                                        mode=ID_raw_codes;
                                }else if(strcasecmp("remote",val)==0){
					/* create new remote */
					LOGPRINTF(1,"parsing remote");
					if(!checkMode(mode, ID_none,
						  "begin remote")) break;
                                        mode=ID_remote;
                                        if (!top_rem){
                                                /* create first remote */
						LOGPRINTF(2,"creating first remote");
                                                rem=top_rem=s_malloc(sizeof(struct ir_remote));
                                        }else{
                                                /* create new remote */
						LOGPRINTF(2,"creating next remote");
                                                rem->next=s_malloc(sizeof(struct ir_remote));;
                                                rem=rem->next;
                                        }
				}else if(mode==ID_codes){
					code=defineCode(key, val, &name_code);
					while(!parse_error && val2!=NULL)
					{
						struct ir_code_node *node;

						if(val2[0]=='#') break; /* comment */
						node=defineNode(code, val2);
						val2=strtok(NULL, whitespace);
					}
					code->current=NULL;
					add_void_array(&codes_list, code);
                                }else{
                                        logprintf(LOG_ERR,"error in configfile line %d:",line);
					logprintf(LOG_ERR,"unknown section \"%s\"",val);
                                        parse_error=1;
                                }
				if(!parse_error && val2!=NULL)
				{
					logprintf(LOG_WARNING,"garbage after "
						  "'%s' token in line %d ignored",
						  val,line);
				}
                        }else if (strcasecmp("end",key)==0){

				if (strcasecmp("codes", val)==0){
					/* end Codes mode */
					LOGPRINTF(2,"    end codes");
                                        if (!checkMode(mode, ID_codes,
						       "end codes")) break;
                                        rem->codes=get_void_array(&codes_list);
                                        mode=ID_remote;     /* switch back */

                                }else if(strcasecmp("raw_codes",val)==0){
                                        /* end raw codes mode */
					LOGPRINTF(2,"    end raw_codes");

					if(mode==ID_raw_name){
						raw_code.signals=get_void_array(&signals);
						raw_code.length=signals.nr_items;
						if(raw_code.length%2==0)
						{
							logprintf(LOG_ERR,"error in configfile line %d:",line);
							logprintf(LOG_ERR,"bad signal length");
							parse_error=1;
						}
						if(!add_void_array(&raw_codes, &raw_code))
							break;
						mode=ID_raw_codes;
					}
                                        if(!checkMode(mode,ID_raw_codes,
						      "end raw_codes")) break;
					rem->codes=get_void_array(&raw_codes);
					mode=ID_remote;     /* switch back */
                                }else if(strcasecmp("remote",val)==0){
                                        /* end remote mode */
					LOGPRINTF(2,"end remote");
					/* print_remote(rem); */
                                        if (!checkMode(mode,ID_remote,
                                                  "end remote")) break;
					if(!sanityChecks(rem)) {
                                                parse_error=1;
                                                break;
					}

#                                       ifdef DYNCODES
					if(rem->dyncodes_name==NULL)
					{
						rem->dyncodes_name=s_strdup("unknown");
					}
					rem->dyncodes[0].name=rem->dyncodes_name;
					rem->dyncodes[1].name=rem->dyncodes_name;
#                                       endif
					/* not really necessary because we
					   clear the alloced memory */
                                        rem->next=NULL;
					rem->last_code=NULL;
                                        mode=ID_none;     /* switch back */
				}else if(mode==ID_codes){
					code=defineCode(key, val, &name_code);
					while(!parse_error && val2!=NULL)
					{
						struct ir_code_node *node;

						if(val2[0]=='#') break; /* comment */
						node=defineNode(code, val2);
						val2=strtok(NULL, whitespace);
					}
					code->current=NULL;
					add_void_array(&codes_list, code);
                                }else{
                                        logprintf(LOG_ERR,"error in configfile line %d:",line);
					logprintf(LOG_ERR,"unknown section %s",val);
                                        parse_error=1;
                                }
				if(!parse_error && val2!=NULL)
				{
					logprintf(LOG_WARNING,"garbage after '%s'"
						  " token in line %d ignored",
						  val,line);
				}
                        } else {
				switch (mode){
				case ID_remote:
					argc=defineRemote(key, val, val2, rem);
					if(!parse_error && ((argc==1 && val2!=NULL) || 
					   (argc==2 && val2!=NULL && strtok(NULL, whitespace)!=NULL)))
					{
						logprintf(LOG_WARNING,"garbage after '%s'"
							  " token in line %d ignored",
							  key,line);
					}
					break;
				case ID_codes:
					code=defineCode(key, val, &name_code);
					while(!parse_error && val2!=NULL)
					{
						struct ir_code_node *node;

						if(val2[0]=='#') break; /* comment */
						node=defineNode(code, val2);
						val2=strtok(NULL, whitespace);
					}
					code->current=NULL;
					add_void_array(&codes_list, code);
					break;
				case ID_raw_codes:
				case ID_raw_name:
					if(strcasecmp("name",key)==0){
						LOGPRINTF(3,"Button: \"%s\"",val);
						if(mode==ID_raw_name)
						{
                                                        raw_code.signals=get_void_array(&signals);
							raw_code.length=signals.nr_items;
							if(raw_code.length%2==0)
							{
								logprintf(LOG_ERR,"error in configfile line %d:",line);
								logprintf(LOG_ERR,"bad signal length");
								parse_error=1;
							}
							if(!add_void_array(&raw_codes, &raw_code))
								break;
						}
						if(!(raw_code.name=s_strdup(val))){
							break;
						}
						raw_code.code++;
						init_void_array(&signals,50,sizeof(lirc_t));
						mode=ID_raw_name;
						if(!parse_error && val2!=NULL)
						{
							logprintf(LOG_WARNING,"garbage after '%s'"
								  " token in line %d ignored",
								  key,line);
						}
					}else{
						if(mode==ID_raw_codes)
						{
							logprintf(LOG_ERR,"no name for signal defined at line %d",line);
							parse_error=1;
							break;
						}
						if(!addSignal(&signals, key)) break;
						if(!addSignal(&signals, val)) break;
						if (val2){
							if (!addSignal(&signals, val2)){
								break;
							}
						}
						while ((val=strtok(NULL, whitespace))){
							if (!addSignal(&signals, val)) break;
						}
					}
					break;
				}
			}
		}else if(mode==ID_raw_name){
                        if(!addSignal(&signals, key)){
				break;
			}
		}else{
                        logprintf(LOG_ERR,"error in configfile line %d", line);
			parse_error=1;
			break;
                }
                if (parse_error){
                        break;
                }
        }
	if(mode!=ID_none)
	{
		switch(mode)
		{
		case ID_raw_name:
			if(raw_code.name!=NULL)
			{
				free(raw_code.name);
				if(get_void_array(&signals)!=NULL)
					free(get_void_array(&signals));
			}
		case ID_raw_codes:
			rem->codes=get_void_array(&raw_codes);
			break;
		case ID_codes:
			rem->codes=get_void_array(&codes_list);
			break;
		}
		if(!parse_error)
		{
			logprintf(LOG_ERR,"unexpected end of file");
			parse_error=1;
		}
	}
        if (parse_error){
		static int print_error = 1;

		if(print_error) {
			logprintf(LOG_ERR, "reading of file '%s' failed",
				  name);
			print_error = 0;
		}
		free_config(top_rem);
		if(depth == 0) print_error = 1;
                return((void *) -1);
        }
	/* kick reverse flag */
	/* handle RC6 flag to be backwards compatible: previous RC-6
	   config files did not set rc6_mask */
	rem=top_rem;
	while(rem!=NULL)
	{
		if((!is_raw(rem)) && rem->flags&REVERSE)
		{
			struct ir_ncode *codes;

			if(has_pre(rem))
			{
				rem->pre_data=reverse(rem->pre_data,
						      rem->pre_data_bits);
			}
			if(has_post(rem))
			{
				rem->post_data=reverse(rem->post_data,
						       rem->post_data_bits);
			}
			codes=rem->codes;
			while(codes->name!=NULL)
			{
				codes->code=reverse(codes->code,rem->bits);
				codes++;
			}
			 rem->flags=rem->flags&(~REVERSE);
			 rem->flags=rem->flags|COMPAT_REVERSE;
			/* don't delete the flag because we still need
			   it to remain compatible with older versions
			*/
		}
		if(rem->flags&RC6 && rem->rc6_mask==0 && rem->toggle_bit>0)
		{
			int all_bits=bit_count(rem);

			rem->rc6_mask=((ir_code) 1)<<(all_bits-rem->toggle_bit);
		}
		if(rem->toggle_bit > 0)
		{
			int all_bits=bit_count(rem);

			if(has_toggle_bit_mask(rem))
			{
				logprintf(LOG_WARNING,
					  "%s uses both toggle_bit and "
					  "toggle_bit_mask", rem->name);
			}
			else
			{
				rem->toggle_bit_mask=((ir_code) 1)<<(all_bits-rem->toggle_bit);
			}
			rem->toggle_bit = 0;
		}
		if(has_toggle_bit_mask(rem))
		{
			if(!is_raw(rem) && rem->codes)
			{
				rem->toggle_bit_mask_state = (rem->codes->code & rem->toggle_bit_mask);
				if(rem->toggle_bit_mask_state)
				{
					/* start with state set to 0 for backwards compatibility */
					rem->toggle_bit_mask_state ^= rem->toggle_bit_mask;
				}
			}
		}
		if(is_serial(rem))
		{
			lirc_t base;

			if(rem->baud>0)
			{
				base=1000000/rem->baud;
				if(rem->pzero==0 && rem->szero==0)
				{
					rem->pzero=base;
				}
				if(rem->pone==0 && rem->sone==0)
				{
					rem->sone=base;
				}
			}
			if(rem->bits_in_byte==0)
			{
				rem->bits_in_byte=8;
			}
		}
		if(rem->min_code_repeat>0)
		{
			if(!has_repeat(rem) ||
			   rem->min_code_repeat>rem->min_repeat)
			{
				logprintf(LOG_WARNING,
					  "invalid min_code_repeat value");
				rem->min_code_repeat = 0;
			}
		}
		calculate_signal_lengths(rem);
		rem=rem->next;
	}

	top_rem = sort_by_bit_count(top_rem);
#       if defined(DEBUG) && !defined(DAEMONIZE)
        /*fprint_remotes(stderr, top_rem);*/
#       endif
        return (top_rem);
}
struct ir_remote * read_config(FILE *f)
{
	char buf[LINE_LEN+1], *key, *val, *val2;
        int len,argc;
	struct ir_remote *top_rem=NULL,*rem=NULL;
        struct void_array codes_list,raw_codes,signals;
	struct ir_ncode raw_code={NULL,0,0,NULL};
	struct ir_ncode name_code={NULL,0,0,NULL};
	int mode=ID_none;

	line=0;
	parse_error=0;

	while(fgets(buf,LINE_LEN,f)!=NULL)
	{
		line++;
		len=strlen(buf);
		if(len==LINE_LEN && buf[len-1]!='\n')
		{
			logprintf(LOG_ERR,"line %d too long in config file",
				  line);
			parse_error=1;
			break;
		}

                /* ignore comments */
		len--;
		if(buf[len]=='\n') buf[len]=0;
                if(buf[0]=='#'){
			continue;
                }
		key=strtok(buf," \t");
		/* ignore empty lines */
		if(key==NULL) continue;
		val=strtok(NULL, " \t");
		if(val!=NULL){
			val2=strtok(NULL, " \t");
			LOGPRINTF(3,"\"%s\" \"%s\"",key,val);
                        if (strcasecmp("begin",key)==0){
				if (strcasecmp("codes", val)==0){
                                        /* init codes mode */
					LOGPRINTF(2,"    begin codes");
					if (!checkMode(mode, ID_remote,
						       "begin codes")) break;
					if (rem->codes){
						logprintf(LOG_ERR,"error in configfile line %d:",line);
						logprintf(LOG_ERR,"codes are already defined");
						parse_error=1;
						break;
					}
					
                                        init_void_array(&codes_list,30, sizeof(struct ir_ncode));
                                        mode=ID_codes;
                                }else if(strcasecmp("raw_codes",val)==0){
                                        /* init raw_codes mode */
					LOGPRINTF(2,"    begin raw_codes");
					if(!checkMode(mode, ID_remote,
						  "begin raw_codes")) break;
					if (rem->codes){
						logprintf(LOG_ERR,"error in configfile line %d:",line);
						logprintf(LOG_ERR,"codes are already defined");
						parse_error=1;
						break;
					}
					rem->flags|=RAW_CODES;
					raw_code.code=0;
                                        init_void_array(&raw_codes,30, sizeof(struct ir_ncode));
                                        mode=ID_raw_codes;
                                }else if(strcasecmp("remote",val)==0){
					/* create new remote */
					LOGPRINTF(1,"parsing remote");
					if(!checkMode(mode, ID_none,
						  "begin remote")) break;
                                        mode=ID_remote;
                                        if (!top_rem){
                                                /* create first remote */
						LOGPRINTF(2,"creating first remote");
                                                rem=top_rem=s_malloc(sizeof(struct ir_remote));
                                        }else{
                                                /* create new remote */
						LOGPRINTF(2,"creating next remote");
                                                rem->next=s_malloc(sizeof(struct ir_remote));;
                                                rem=rem->next;
                                        }
                                }else{
                                        logprintf(LOG_ERR,"error in configfile line %d:",line);
					logprintf(LOG_ERR,"unknown section \"%s\"",val);
                                        parse_error=1;
                                }
				if(!parse_error && val2!=NULL)
				{
					logprintf(LOG_WARNING,"garbage after "
						  "'%s' token in line %d ignored",
						  val,line);
				}
                        }else if (strcasecmp("end",key)==0){

				if (strcasecmp("codes", val)==0){
					/* end Codes mode */
					LOGPRINTF(2,"    end codes");
                                        if (!checkMode(mode, ID_codes,
						       "end codes")) break;
                                        rem->codes=get_void_array(&codes_list);
                                        mode=ID_remote;     /* switch back */

                                }else if(strcasecmp("raw_codes",val)==0){
                                        /* end raw codes mode */
					LOGPRINTF(2,"    end raw_codes");
					
					if(mode==ID_raw_name){
						raw_code.signals=get_void_array(&signals);
						raw_code.length=signals.nr_items;
						if(raw_code.length%2==0)
						{
							logprintf(LOG_ERR,"error in configfile line %d:",line);
							logprintf(LOG_ERR,"bad signal length",val);
							parse_error=1;
						}
						if(!add_void_array(&raw_codes, &raw_code))
							break;
						mode=ID_raw_codes;
					}
                                        if(!checkMode(mode,ID_raw_codes,
						      "end raw_codes")) break;
					rem->codes=get_void_array(&raw_codes);
					mode=ID_remote;     /* switch back */
                                }else if(strcasecmp("remote",val)==0){
                                        /* end remote mode */
					LOGPRINTF(2,"end remote");
					/* print_remote(rem); */
                                        if (!checkMode(mode,ID_remote,
                                                  "end remote")) break;
                                        if (!rem->name){
                                                logprintf(LOG_ERR,"you must specify a remote name");
                                                parse_error=1;
                                                break;
                                        }

					/* not really necessary because we
					   clear the alloced memory */
                                        rem->next=NULL;
					rem->last_code=NULL;
                                        mode=ID_none;     /* switch back */
					if(has_repeat_gap(rem) && 
					   is_const(rem))
					{
						logprintf(LOG_WARNING,"repeat_gap will be ignored if CONST_LENGTH flag is set");
					}
                                }else{
                                        logprintf(LOG_ERR,"error in configfile line %d:",line);
					logprintf(LOG_ERR,"unknown section %s",val);
                                        parse_error=1;
                                }
				if(!parse_error && val2!=NULL)
				{
					logprintf(LOG_WARNING,"garbage after '%s'"
						  " token in line %d ignored",
						  val,line);
				}
                        } else {
				switch (mode){
				case ID_remote:
					argc=defineRemote(key, val, val2, rem);
					if(!parse_error && ((argc==1 && val2!=NULL) || 
					   (argc==2 && val2!=NULL && strtok(NULL," \t")!=NULL)))
					{
						logprintf(LOG_WARNING,"garbage after '%s'"
							  " token in line %d ignored",
							  key,line);
					}
					break;
				case ID_codes:
					add_void_array(&codes_list, defineCode(key, val, &name_code));
					if(!parse_error && val2!=NULL)
					{
						logprintf(LOG_WARNING,"garbage after '%s'"
							  " code in line %d ignored",
							  key,line);
					}
					break;
				case ID_raw_codes:
				case ID_raw_name:
					if(strcasecmp("name",key)==0){
						LOGPRINTF(3,"Button: \"%s\"",val);
						if(mode==ID_raw_name)
						{
                                                        raw_code.signals=get_void_array(&signals);
							raw_code.length=signals.nr_items;
							if(raw_code.length%2==0)
							{
								logprintf(LOG_ERR,"error in configfile line %d:",line);
								logprintf(LOG_ERR,"bad signal length",val);
								parse_error=1;
							}
							if(!add_void_array(&raw_codes, &raw_code))
								break;
						}
						if(!(raw_code.name=s_strdup(val))){
							break;
						}
						raw_code.code++;
						init_void_array(&signals,50,sizeof(lirc_t));
						mode=ID_raw_name;
						if(!parse_error && val2!=NULL)
						{
							logprintf(LOG_WARNING,"garbage after '%s'"
								  " token in line %d ignored",
								  key,line);
						}
					}else{
						if(mode==ID_raw_codes)
						{
							logprintf(LOG_ERR,"no name for signal defined at line %d",line);
							parse_error=1;
							break;
						}
						if(!addSignal(&signals, key)) break;
						if(!addSignal(&signals, val)) break;
						if (val2){
							if (!addSignal(&signals, val2)){
								break;
							}
						}
						while ((val=strtok(NULL," \t"))){
							if (!addSignal(&signals, val)) break;
						}
					}
					break;
				}
			}
		}else if(mode==ID_raw_name){
                        if(!addSignal(&signals, key)){
				break;
			}
		}else{
                        logprintf(LOG_ERR,"error in configfile line %d", line);
			parse_error=1;
			break;
                }
                if (parse_error){
                        break;
                }
        }
	if(mode!=ID_none)
	{
		switch(mode)
		{
		case ID_raw_name:
			if(raw_code.name!=NULL)
			{
				free(raw_code.name);
				if(get_void_array(&signals)!=NULL)
					free(get_void_array(&signals));
			}
		case ID_raw_codes:
			rem->codes=get_void_array(&raw_codes);
			break;
		case ID_codes:
			rem->codes=get_void_array(&codes_list);
			break;
		}
		if(!parse_error)
		{
			logprintf(LOG_ERR,"unexpected end of file");
			parse_error=1;
		}
	}
        if (parse_error){
		free_config(top_rem);
                return((void *) -1);
        }
	/* kick reverse flag */
	rem=top_rem;
	while(rem!=NULL)
	{
		if((!is_raw(rem)) && rem->flags&REVERSE)
		{
			struct ir_ncode *codes;
			
			if(has_pre(rem))
			{
				rem->pre_data=reverse(rem->pre_data,
						      rem->pre_data_bits);
			}
			if(has_post(rem))
			{
				rem->post_data=reverse(rem->post_data,
						       rem->post_data_bits);
			}
			codes=rem->codes;
			while(codes->name!=NULL)
			{
				codes->code=reverse(codes->code,rem->bits);
				codes++;
			}
			/* rem->flags=rem->flags&(~REVERSE); */
			/* don't delete the flag because we still need
			   it to remain compatible with older versions
			*/
		}
		rem=rem->next;
	}

#       if defined(DEBUG) && !defined(DAEMONIZE)
        /*fprint_remotes(stderr, top_rem);*/
#       endif
        return (top_rem);
}