Пример #1
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);
}
Пример #2
0
static int lirc_readconfig_only_internal(const struct lirc_state *state,
                                         const char *file,
                                         struct lirc_config **config,
                                         int (check)(char *s),
                                         char **full_name,
                                         char **sha_bang)
{
	char *string,*eq,*token,*token2,*token3;
	struct filestack_t *filestack, *stack_tmp;
	int open_files;
	struct lirc_config_entry *new_entry,*first,*last;
	char *mode,*remote;
	int ret=0;
	int firstline=1;
	char *save_full_name = NULL;
	
	filestack = stack_push(state, NULL);
	if (filestack == NULL)
	{
		return -1;
	}
	filestack->file = lirc_open(state, file, NULL, &(filestack->name));
	if (filestack->file == NULL)
	{
		stack_free(filestack);
		return -1;
	}
	filestack->line = 0;
	open_files = 1;

	first=new_entry=last=NULL;
	mode=NULL;
	remote=LIRC_ALL;
	while (filestack)
	{
		if((ret=lirc_readline(state,&string,filestack->file))==-1 ||
		   string==NULL)
		{
			fclose(filestack->file);
			if(open_files == 1 && full_name != NULL)
			{
				save_full_name = filestack->name;
				filestack->name = NULL;
			}
			filestack = stack_pop(filestack);
			open_files--;
			continue;
		}
		/* check for sha-bang */
		if(firstline && sha_bang)
		{
			firstline = 0;
			if(strncmp(string, "#!", 2)==0)
			{
				*sha_bang=strdup(string+2);
				if(*sha_bang==NULL)
				{
					lirc_printf(state, "%s: out of memory\n",
						    state->lirc_prog);
					ret=-1;
					free(string);
					break;
				}
			}
		}
		filestack->line++;
		eq=strchr(string,'=');
		if(eq==NULL)
		{
			token=strtok(string," \t");
			if(token==NULL)
			{
				/* ignore empty line */
			}
			else if(token[0]=='#')
			{
				/* ignore comment */
			}
			else if(strcasecmp(token, "include") == 0)
			{
				if (open_files >= MAX_INCLUDES)
				{
					lirc_printf(state, "%s: too many files "
						    "included at %s:%d\n",
						    state->lirc_prog,
						    filestack->name,
						    filestack->line);
					ret=-1;
				}
				else
				{
					token2 = strtok(NULL, "");
					token2 = lirc_trim(token2);
					lirc_parse_include
						(token2, filestack->name,
						 filestack->line);
					stack_tmp = stack_push(state, filestack);
					if (stack_tmp == NULL)
					{
						ret=-1;
					}
					else
					{
						stack_tmp->file = lirc_open(state, token2, filestack->name, &(stack_tmp->name));
						stack_tmp->line = 0;
						if (stack_tmp->file)
						{
							open_files++;
							filestack = stack_tmp;
						}
						else
						{
							stack_pop(stack_tmp);
							ret=-1;
						}
					}
				}
			}
			else
			{
				token2=strtok(NULL," \t");
				if(token2!=NULL && 
				   (token3=strtok(NULL," \t"))!=NULL)
				{
					lirc_printf(state, "%s: unexpected token in line %s:%d\n",
						    state->lirc_prog,filestack->name,filestack->line);
				}
				else
				{
					ret=lirc_mode(state, token,token2,&mode,
						      &new_entry,&first,&last,
						      check,
						      filestack->name,
						      filestack->line);
					if(ret==0)
					{
						if(remote!=LIRC_ALL)
							free(remote);
						remote=LIRC_ALL;
					}
					else
					{
						if(mode!=NULL)
						{
							free(mode);
							mode=NULL;
						}
						if(new_entry!=NULL)
						{
							lirc_freeconfigentries
								(new_entry);
							new_entry=NULL;
						}
					}
				}
			}
		}
		else
		{
			eq[0]=0;
			token=lirc_trim(string);
			token2=lirc_trim(eq+1);
			if(token[0]=='#')
			{
				/* ignore comment */
			}
			else if(new_entry==NULL)
			{
				lirc_printf(state, "%s: bad file format, %s:%d\n",
					state->lirc_prog,filestack->name,filestack->line);
				ret=-1;
			}
			else
			{
				token2=strdup(token2);
				if(token2==NULL)
				{
					lirc_printf(state, "%s: out of memory\n",
						    state->lirc_prog);
					ret=-1;
				}
				else if(strcasecmp(token,"prog")==0)
				{
					if(new_entry->prog!=NULL) free(new_entry->prog);
					new_entry->prog=token2;
				}
				else if(strcasecmp(token,"remote")==0)
				{
					if(remote!=LIRC_ALL)
						free(remote);
					
					if(strcasecmp("*",token2)==0)
					{
						remote=LIRC_ALL;
						free(token2);
					}
					else
					{
						remote=token2;
					}
				}
				else if(strcasecmp(token,"button")==0)
				{
					struct lirc_code *code;
					
					code=(struct lirc_code *)
					malloc(sizeof(struct lirc_code));
					if(code==NULL)
					{
						free(token2);
						lirc_printf(state, "%s: out of "
							    "memory\n",
							    state->lirc_prog);
						ret=-1;
					}
					else
					{
						code->remote=remote;
						if(strcasecmp("*",token2)==0)
						{
							code->button=LIRC_ALL;
							free(token2);
						}
						else
						{
							code->button=token2;
						}
						code->next=NULL;

						if(new_entry->code==NULL)
						{
							new_entry->code=code;
						}
						else
						{
							new_entry->next_code->next
							=code;
						}
						new_entry->next_code=code;
						if(remote!=LIRC_ALL)
						{
							remote=strdup(remote);
							if(remote==NULL)
							{
								lirc_printf(state, "%s: out of memory\n",state->lirc_prog);
								ret=-1;
							}
						}
					}
				}
				else if(strcasecmp(token,"delay")==0)
				{
					char *end;

					errno=ERANGE+1;
					new_entry->rep_delay=strtoul(token2,&end,0);
					if((new_entry->rep_delay==UINT_MAX 
					    && errno==ERANGE)
					   || end[0]!=0
					   || strlen(token2)==0)
					{
						lirc_printf(state, "%s: \"%s\" not"
							    " a  valid number for "
							    "delay\n",state->lirc_prog,
							    token2);
					}
					free(token2);
				}
				else if(strcasecmp(token,"repeat")==0)
				{
					char *end;

					errno=ERANGE+1;
					new_entry->rep=strtoul(token2,&end,0);
					if((new_entry->rep==UINT_MAX
					    && errno==ERANGE)
					   || end[0]!=0
					   || strlen(token2)==0)
					{
						lirc_printf(state, "%s: \"%s\" not"
							    " a  valid number for "
							    "repeat\n",state->lirc_prog,
							    token2);
					}
					free(token2);
				}
				else if(strcasecmp(token,"config")==0)
				{
					struct lirc_list *new_list;

					new_list=(struct lirc_list *) 
					malloc(sizeof(struct lirc_list));
					if(new_list==NULL)
					{
						free(token2);
						lirc_printf(state, "%s: out of "
							    "memory\n",
							    state->lirc_prog);
						ret=-1;
					}
					else
					{
						lirc_parse_string(state,token2,filestack->name,filestack->line);
						new_list->string=token2;
						new_list->next=NULL;
						if(new_entry->config==NULL)
						{
							new_entry->config=new_list;
						}
						else
						{
							new_entry->next_config->next
							=new_list;
						}
						new_entry->next_config=new_list;
					}
				}
				else if(strcasecmp(token,"mode")==0)
				{
					if(new_entry->change_mode!=NULL) free(new_entry->change_mode);
					new_entry->change_mode=token2;
				}
				else if(strcasecmp(token,"flags")==0)
				{
					new_entry->flags=lirc_flags(state, token2);
					free(token2);
				}
				else
				{
					free(token2);
					lirc_printf(state, "%s: unknown token \"%s\" in %s:%d ignored\n",
						    state->lirc_prog,token,filestack->name,filestack->line);
				}
			}
		}
		free(string);
		if(ret==-1) break;
	}
	if(remote!=LIRC_ALL)
		free(remote);
	if(new_entry!=NULL)
	{
		if(ret==0)
		{
			ret=lirc_mode(state, "end",NULL,&mode,&new_entry,
				      &first,&last,check,"",0);
			lirc_printf(state, "%s: warning: end token missing at end "
				    "of file\n",state->lirc_prog);
		}
		else
		{
			lirc_freeconfigentries(new_entry);
			new_entry=NULL;
		}
	}
	if(mode!=NULL)
	{
		if(ret==0)
		{
			lirc_printf(state, "%s: warning: no end token found for mode "
				    "\"%s\"\n",state->lirc_prog,mode);
		}
		free(mode);
	}
	if(ret==0)
	{
		char *startupmode;
		
		*config=(struct lirc_config *)
			malloc(sizeof(struct lirc_config));
		if(*config==NULL)
		{
			lirc_printf(state, "%s: out of memory\n",state->lirc_prog);
			lirc_freeconfigentries(first);
			return(-1);
		}
		(*config)->first=first;
		(*config)->next=first;
		startupmode = lirc_startupmode(state, (*config)->first);
		(*config)->current_mode=startupmode ? strdup(startupmode):NULL;
		(*config)->sockfd=-1;
		if(full_name != NULL)
		{
			*full_name = save_full_name;
			save_full_name = NULL;
		}
	}
	else
	{
		*config=NULL;
		lirc_freeconfigentries(first);
		if(sha_bang && *sha_bang!=NULL)
		{
			free(*sha_bang);
			*sha_bang=NULL;
		}
	}
	if(filestack)
	{
		stack_free(filestack);
	}
	if(save_full_name)
	{
		free(save_full_name);
	}
	return(ret);
}