29#include <sys/socket.h>
72static std::string
lirc_trim(
const std::string& s);
74 size_t bs,
const std::string& name,
int line);
79 const std::string& token,
const std::string& token2,std::string& mode,
83 int (check)(std::string& s),
84 const std::string& name,
int line);
92 const std::string&
file,
93 const std::string& current_file);
95 const std::string&
file,
const std::string& current_file,
96 std::string& full_name);
101 const std::string&
file,
103 int (check)(std::string& s),
104 std::string& full_name,
105 std::string& sha_bang);
113static int sstrcasecmp(std::string s1, std::string s2);
115 std::string& button,
unsigned int rep);
117 struct lirc_config *config,
const std::string& code,
118 std::string&
string, std::string& prog);
122static int lirc_send_command(
const struct lirc_state *state,
int sockfd,
const std::string& command,
char *buf,
size_t *buf_len,
int *ret_status);
132 std::string lformat = state->
lirc_prog +
": " + format_str;
133 va_start(ap,format_str);
134 vfprintf(
stderr,lformat.data(),ap);
139 va_start(ap,format_str);
140 vfprintf(
stderr,format_str,ap);
157 struct sockaddr_un addr {};
161 if(lircrc_root_file==
nullptr || lircrc_user_file ==
nullptr || prog==
nullptr)
163 lirc_printf(
nullptr,
"%s: lirc_init invalid params\n",prog);
182 addr.sun_family=AF_UNIX;
183 strncpy(addr.sun_path,lircd,
sizeof(addr.sun_path)-1);
184 state->
lirc_lircd=socket(AF_UNIX,SOCK_STREAM,0);
192 if(connect(state->
lirc_lircd,(
struct sockaddr *)&addr,
sizeof(addr))==-1)
195 lirc_printf(state,
"could not connect to socket\n");
221 std::array<char,LIRC_READ+1> newline {};
225 char *ret=fgets(newline.data(),
LIRC_READ+1,f);
228 return(line.empty() ? -1 : 0);
230 line += newline.data();
231 if (line.back() ==
'\n')
241 const size_t start = s.find_first_not_of(
" \t");
242 if (start == std::string::npos)
244 const size_t end = s.find_last_not_of(
" \t");
245 if (end == std::string::npos)
246 return s.substr(start);
247 return s.substr(start, end-start+1);
253 size_t bs,
const std::string& name,
int line)
258 const char c=s[bs+1];
261 case 'a': i =
'\a';
break;
262 case 'b': i =
'\b';
break;
263 case 'e': i =
'\e';
break;
264 case 'f': i =
'\f';
break;
265 case 'n': i =
'\n';
break;
266 case 'r': i =
'\r';
break;
267 case 't': i =
'\t';
break;
268 case 'v': i =
'\v';
break;
283 i = std::stoi(s.substr(bs+1), &count, 8);
285 catch (std::out_of_range& e) {
288 if(i>(1<<CHAR_BIT)-1)
292 "out of range in %s:%d\n",name.c_str(),line);
297 i = std::stoi(s.substr(bs+2), &count, 16);
300 catch (std::invalid_argument& e) {
302 "following hex digits in %s:%d\n",
305 catch (std::out_of_range& e) {
313 if(i>(1<<CHAR_BIT)-1)
317 "of range in %s:%d\n",name.c_str(),line);
327 i =
static_cast<uint8_t
>(c);
331 s.erase(bs+1, count);
336 size_t bs = s.find_first_of(
'\\');
337 while(bs != std::string::npos)
340 bs = s.find_first_of(
'\\',bs);
345 [[maybe_unused]]
const std::string& name,
346 [[maybe_unused]]
int line)
352 if(s.front() !=
'"' && s.front() !=
'<')
356 if (((s.front() ==
'"') && (s.back() !=
'"')) ||
357 ((s.front() ==
'<') && (s.back() !=
'>')))
366 const std::string& token,
const std::string& token2,std::string& mode,
370 int (check)(std::string& s),
371 const std::string& name,
int line)
378 if(new_entry==
nullptr)
381 if(new_entry==
nullptr)
386 *new_config=new_entry;
391 "%s:%d\n",name.c_str(),line);
397 if(new_entry==
nullptr)
404 "%s:%d\n",name.c_str(),line);
409 else if(token ==
"end")
413 if(new_entry!=
nullptr)
416 if(new_entry->
prog.empty())
419 "config before line %d\n",
434 if(*last_config==
nullptr)
436 *first_config=new_entry;
437 *last_config=new_entry;
441 (*last_config)->
next=new_entry;
442 *last_config=new_entry;
457 if(check(list->
string)==-1)
474 "'begin'\n",name.c_str(),line);
482 if(new_entry!=
nullptr)
485 "'end' token\n",name.c_str(),line);
495 "match mode \"%s\"\n",
496 token2.c_str(),mode.c_str());
503 "'begin'\n",name.c_str(),line,token2.c_str());
510 lirc_printf(state,
"unknown token \"%s\" in %s:%d ignored\n",
511 token.c_str(),name.c_str(),line);
518 unsigned int flags=
none;
519 size_t start =
string.find_first_not_of(
" \t|");
520 while(start != std::string::npos)
522 size_t end =
string.find_first_of(
" \t|", start);
523 std::string s =
string.substr(start,end-start);
536 else if(s ==
"startup_mode")
540 else if(s ==
"toggle_reset")
546 lirc_printf(state,
"unknown flag \"%s\"\n",s.c_str());
548 start =
string.find_first_not_of(
" \t|", end);
554 const std::string&
file,
555 const std::string& current_file)
561 const char *home=getenv(
"HOME");
567 if(strlen(home)>0 &&
filename.back()!=
'/')
573 else if(
file.compare(0,2,
"~/")==0)
575 const char *home=getenv(
"HOME");
583 else if(
file[0]==
'/' || current_file.empty())
601 const std::string&
file,
const std::string& current_file,
602 std::string& full_name)
611 if(fin==
nullptr && (!
file.empty() || errno!=ENOENT))
613 lirc_printf(state,
"could not open config file %s\n",
617 else if(fin==
nullptr)
620 if(fin==
nullptr && errno!=ENOENT)
622 lirc_printf(state,
"could not open config file %s\n",
626 else if(fin==
nullptr)
628 lirc_printf(state,
"could not open config files %s and %s\n",
656 }
catch (
const std::bad_alloc& e) {
681 const std::string&
file,
683 int (check)(std::string& s))
685 struct sockaddr_un addr {};
687 unsigned int ret = 0;
690 std::string sha_bang;
701 addr.sun_family=AF_UNIX;
704 lirc_printf(state,
"WARNING: file name too long\n");
707 sockfd=socket(AF_UNIX,SOCK_STREAM,0);
710 lirc_printf(state,
"WARNING: could not open socket\n");
714 if(connect(sockfd, (
struct sockaddr *)&addr,
sizeof(addr))!=-1)
716 (*config)->sockfd=sockfd;
732 std::string command = sha_bang +
" " +
filename;
733 ret = system(command.data());
735 if(ret!=EXIT_SUCCESS)
738 sockfd=socket(AF_UNIX,SOCK_STREAM,0);
741 lirc_printf(state,
"WARNING: could not open socket\n");
745 if(connect(sockfd, (
struct sockaddr *)&addr,
sizeof(addr))!=-1)
749 (*config)->sockfd=sockfd;
760 const std::string&
file,
762 int (check)(std::string& s))
765 std::string sha_bang;
769static std::string
parse_token (
const std::string&
string,
size_t& next)
771 if (next == std::string::npos)
773 size_t start =
string.find_first_not_of(
" \t", next);
774 if (start == std::string::npos) {
775 next = std::string::npos;
778 next =
string.find_first_of(
" \t", start);
779 if (next == std::string::npos)
780 return string.substr(start);
781 return string.substr(start, next-start);
785 const std::string&
file,
787 int (check)(std::string& s),
788 std::string& full_name,
789 std::string& sha_bang)
795 if (filestack ==
nullptr)
801 if (filestack->
m_file ==
nullptr)
820 fclose(filestack->
m_file);
823 full_name = filestack->
m_name;
834 if(
string.compare(0,2,
"#!")==0)
836 sha_bang=
string.substr(2);
840 const size_t eq =
string.find_first_of(
'=');
841 if(eq == std::string::npos)
845 std::transform(token.begin(), token.end(), token.begin(),
846 [](
char c){return std::tolower(c); });
851 else if(token ==
"include")
856 "included at %s:%d\n",
857 filestack->
m_name.c_str(),
863 std::string token2 {};
864 if (
next != std::string::npos)
865 token2 =
string.substr(
next);
868 (token2, filestack->
m_name,
872 if (stack_tmp ==
nullptr)
883 filestack = stack_tmp;
896 std::transform(token2.begin(), token2.end(), token2.begin(),
897 [](
char c){return std::tolower(c); });
898 if (
string.find_first_not_of(
" \t", next) != std::string::npos)
900 lirc_printf(state,
"unexpected token in line %s:%d\n",
906 &new_entry,&first,&last,
917 if(new_entry!=
nullptr)
929 std::string token=
lirc_trim(
string.substr(0,eq));
930 std::string token2=
lirc_trim(
string.substr(eq+1));
931 std::transform(token.begin(), token.end(), token.begin(),
932 [](
char c){return std::tolower(c); });
937 else if(new_entry==
nullptr)
947 new_entry->
prog=token2;
949 else if(token ==
"remote")
960 else if(token ==
"button")
981 if(new_entry->
code==
nullptr)
983 new_entry->
code=code;
993 else if(token ==
"delay")
998 new_entry->
rep_delay=std::stoi(token2,&end,0);
1000 catch (std::invalid_argument& e) { fail =
true; }
1001 catch (std::out_of_range& e) { fail =
true; }
1002 if(fail || (end == 0) || (token2[end] != 0))
1005 " a valid number for "
1006 "delay\n",token2.c_str());
1009 else if(token ==
"repeat")
1012 bool fail {
false };
1014 new_entry->
rep=std::stoi(token2,&end,0);
1016 catch (std::invalid_argument& e) { fail =
true; }
1017 catch (std::out_of_range& e) { fail =
true; }
1018 if(fail || (end == 0) || (token2[end] != 0))
1021 " a valid number for "
1022 "repeat\n",token2.c_str());
1025 else if(token ==
"config")
1030 new_list->string=token2;
1031 new_list->next=
nullptr;
1032 if(new_entry->
config==
nullptr)
1034 new_entry->
config=new_list;
1044 else if(token ==
"mode")
1048 else if(token ==
"flags")
1054 lirc_printf(state,
"unknown token \"%s\" in %s:%d ignored\n",
1055 token.c_str(),filestack->
m_name.c_str(),filestack->
m_line);
1061 if(new_entry!=
nullptr)
1067 ret=
lirc_mode(state,
"end",
"",mode,&new_entry,
1068 &first,&last,check,
"",0);
1069 lirc_printf(state,
"warning: end token missing at end "
1082 lirc_printf(state,
"warning: no end token found for mode "
1083 "\"%s\"\n",mode.c_str());
1090 if(*config==
nullptr)
1096 (*config)->first=first;
1097 (*config)->
next=first;
1099 (*config)->current_mode= startupmode;
1100 (*config)->sockfd=-1;
1117 std::string startupmode;
1121 while(
scan!=
nullptr)
1124 if(!
scan->change_mode.empty()) {
1125 startupmode=
scan->change_mode;
1127 scan->change_mode.clear();
1130 lirc_printf(state,
"startup_mode flags requires 'mode ='\n");
1136 if(startupmode.empty()) {
1138 while(
scan!=
nullptr)
1149 if(startupmode.empty())
return {};
1151 while(
scan!=
nullptr)
1153 if(!
scan->change_mode.empty() &&
1161 return(startupmode);
1174 config->current_mode.clear();
1189 while(code!=
nullptr)
1199 while(list!=
nullptr)
1214 if(
config->current_mode.empty())
1219 while(
scan!=
nullptr)
1221 if(!
scan->change_mode.empty())
1230 config->current_mode.clear();
1243 if(!
scan->change_mode.empty())
1258 if(
scan->next_config!=
nullptr &&
1262 std::string s=
scan->next_config->string;
1263 scan->next_config=
scan->next_config->next;
1264 if(
scan->next_config==
nullptr)
1273 std::transform(s1.begin(), s1.end(), s1.begin(),
1274 [](
char c){ return std::tolower(c); });
1275 std::transform(s2.begin(), s2.end(), s2.begin(),
1276 [](
char c){ return std::tolower(c); });
1277 return(strcasecmp(s1.data(), s2.data()));
1281 std::string& button,
unsigned int rep)
1284 if(
scan->code==
nullptr)
1286 return static_cast<int>(
rep==0 ||
1300 if(
scan->code->next==
nullptr ||
rep==0)
1302 scan->next_code=
scan->next_code->next;
1303 if(
scan->code->next !=
nullptr)
1309 if(
scan->next_code==
nullptr)
1312 if(
scan->code->next!=
nullptr ||
rep==0 ||
1321 if(
rep!=0)
return(0);
1330 if(codes==
scan->next_code)
return(0);
1333 while(codes!=
scan->next_code->next)
1382 const std::string& code,std::string&
string)
1386 std::string command;
1387 static std::array<char,LIRC_PACKET_SIZE> s_buf;
1388 size_t buf_len = s_buf.size();
1396 s_buf.data(), &buf_len, &success);
1401 string = s_buf.data();
1416 struct lirc_config *config,
const std::string& code,
1417 std::string&
string, std::string& prog)
1419 unsigned int rep = 0;
1422 if(sscanf(code.c_str(),
"%*20x %20x %*5000s %*5000s\n",&rep)==1)
1425 size_t end = code.find_first_of(
" \t\n", 0);
1426 size_t start = code.find_first_not_of(
" \t\n",end);
1428 end = code.find_first_of(
" \t\n",start);
1429 start = code.find_first_not_of(
" \t\n",end);
1431 end = code.find_first_of(
" \t\n",start);
1432 std::string
button = code.substr(start,end-start);
1433 start = code.find_first_not_of(
" \t\n",end);
1435 end = code.find_first_of(
" \t\n",start);
1436 std::string
remote = code.substr(start,end-start);
1444 int quit_happened=0;
1446 while(
scan!=
nullptr)
1449 if(exec_level > 0 &&
1450 (
scan->mode.empty() ||
1451 (!
scan->mode.empty() &&
1507 static std::array<char,LIRC_PACKET_SIZE> s_buf;
1508 size_t buf_len = s_buf.size();
1512 s_buf.data(), &buf_len, &success);
1517 return s_buf.data();
1523 return config->current_mode;
1530 static std::array<char,LIRC_PACKET_SIZE> s_buf {};
1532 size_t buf_len = s_buf.size();
1540 s_buf.data(), &buf_len, &success);
1545 return s_buf.data();
1553 return config->current_mode;
1559 static std::array<char,LIRC_PACKET_SIZE+1> s_buffer;
1560 char *end =
nullptr;
1561 static size_t s_head=0;
1562 static size_t s_tail=0;
1566 struct timeval tv {};
1568 auto cleanup_fn = [&](
int *) {
1572 std::unique_ptr<int,
decltype(cleanup_fn)>
cleanup { &ret, cleanup_fn };
1576 memmove(s_buffer.data(),s_buffer.data()+s_head,s_tail-s_head+1);
1579 end=strchr(s_buffer.data(),
'\n');
1585 if(strlen(s_buffer.data())!=s_tail)
1603 ret=select(fd+1,&fds,
nullptr,
nullptr,&tv);
1604 while(ret==-1 && errno==EINTR)
1605 ret=select(fd+1,&fds,
nullptr,
nullptr,&tv);
1625 s_buffer[s_tail+n]=0;
1627 end=strchr(s_buffer.data(),
'\n');
1631 s_head=strlen(s_buffer.data())+1;
1633 return(s_buffer.data());
1639 unsigned long n = 0;
1640 unsigned long data_n=0;
1645 if(buf_len!=
nullptr)
1649 size_t todo=command.size();
1650 const char *data=command.data();
1651 lirc_printf(lstate,
"sending command: %s", command.data());
1654 ssize_t done=
write(sockfd,(
const void *) data,todo);
1668 bool good_packet =
false;
1669 bool bad_packet =
false;
1672 while(!good_packet && !bad_packet)
1676 if(
string==
nullptr)
return(-1);
1677 lirc_printf(lstate,
"read response: %s\n",
string);
1681 if(strcasecmp(
string,
"BEGIN")!=0)
1688 if(strncasecmp(
string,command.data(),strlen(
string))!=0 ||
1689 strlen(
string)+1!=command.size())
1697 if(strcasecmp(
string,
"SUCCESS")==0)
1701 else if(strcasecmp(
string,
"END")==0)
1707 else if(strcasecmp(
string,
"ERROR")==0)
1721 if(strcasecmp(
string,
"END")==0)
1726 else if(strcasecmp(
string,
"DATA")==0)
1736 data_n=std::stoul(
string,&end,0);
1738 catch (std::invalid_argument& ) { fail =
true; }
1739 catch (std::out_of_range& ) { fail =
true; }
1740 if(fail || (end == 0) || (
string[end] != 0))
1756 if(buf!=
nullptr && written+len+1<max)
1758 memcpy(buf+written,
string, len+1);
1762 if(n==data_n) state=
P_END;
1765 if(strcasecmp(
string,
"END")==0)
1781 if(ret_status!=
nullptr)
1785 if(buf_len!=
nullptr)
1789 return (
int) data_n;
1794 std::string command;
size_t lirc_getsocketname(const std::string &filename, char *buf, size_t size)
std::string lirc_getmode(const struct lirc_state *state, struct lirc_config *config)
static int lirc_iscode(struct lirc_config_entry *scan, std::string &remote, std::string &button, unsigned int rep)
static void lirc_perror(const struct lirc_state *)
static constexpr size_t LIRC_READ
static unsigned int lirc_flags(const struct lirc_state *state, const std::string &string)
int lirc_readconfig(const struct lirc_state *state, const std::string &file, struct lirc_config **config, int(check)(std::string &s))
static constexpr int8_t MAX_INCLUDES
static FILE * lirc_open(const struct lirc_state *state, const std::string &file, const std::string ¤t_file, std::string &full_name)
int lirc_deinit(struct lirc_state *state)
static void lirc_clearmode(struct lirc_config *config)
static void lirc_parse_include(std::string &s, const std::string &name, int line)
static std::string lirc_getfilename(const struct lirc_state *state, const std::string &file, const std::string ¤t_file)
static int lirc_identify(const struct lirc_state *state, int sockfd)
static struct filestack_t * stack_push(const struct lirc_state *state, struct filestack_t *parent)
void lirc_freeconfig(struct lirc_config *config)
static std::string lirc_trim(const std::string &s)
static const char * lirc_read_string(const struct lirc_state *state, int fd)
static std::string lirc_execute(const struct lirc_state *state, struct lirc_config *config, struct lirc_config_entry *scan)
static void lirc_parse_string(const struct lirc_state *state, std::string &s, const std::string &name, int line)
std::string lirc_setmode(const struct lirc_state *state, struct lirc_config *config, const std::string &mode)
static int sstrcasecmp(std::string s1, std::string s2)
static int lirc_mode(const struct lirc_state *state, const std::string &token, const std::string &token2, std::string &mode, struct lirc_config_entry **new_config, struct lirc_config_entry **first_config, struct lirc_config_entry **last_config, int(check)(std::string &s), const std::string &name, int line)
static std::string parse_token(const std::string &string, size_t &next)
static int lirc_send_command(const struct lirc_state *state, int sockfd, const std::string &command, char *buf, size_t *buf_len, int *ret_status)
static void lirc_printf(const struct lirc_state *, const char *format_str,...)
static int lirc_readconfig_only_internal(const struct lirc_state *state, const std::string &file, struct lirc_config **config, int(check)(std::string &s), std::string &full_name, std::string &sha_bang)
static void stack_free(struct filestack_t *entry)
static constexpr size_t LIRC_PACKET_SIZE
int lirc_readconfig_only(const struct lirc_state *state, const std::string &file, struct lirc_config **config, int(check)(std::string &s))
static int lirc_code2char_internal(const struct lirc_state *state, struct lirc_config *config, const std::string &code, std::string &string, std::string &prog)
int lirc_code2char(const struct lirc_state *state, struct lirc_config *config, const std::string &code, std::string &string)
static struct filestack_t * stack_pop(struct filestack_t *entry)
static int lirc_readline(const struct lirc_state *state, std::string &line, FILE *f)
static void lirc_freeconfigentries(struct lirc_config_entry *first)
struct lirc_state * lirc_init(const char *lircrc_root_file, const char *lircrc_user_file, const char *prog, const char *lircd, int verbose)
static std::string lirc_startupmode(const struct lirc_state *state, struct lirc_config_entry *first)
static void lirc_parse_escape(const struct lirc_state *state, std::string &s, size_t bs, const std::string &name, int line)
static constexpr int8_t LIRC_TIMEOUT
def read(device=None, features=[])
def scan(profile, smoonURL, gate)
def write(text, progress=True)
static QString cleanup(const QString &str)
struct filestack_t * m_parent
struct lirc_list * config
struct lirc_list * next_config
struct lirc_code * next_code
struct lirc_config_entry * next
std::string lircrc_root_file
std::string lircrc_user_file