3 * This file is part of LCDd, the lcdproc server.
5 * This file is released under the GNU General Public License. Refer to the
6 * COPYING file distributed with this package.
8 * Copyright (c) 1999, William Ferrell, Scott Scriven
11 * Handles input commands from clients, by splitting strings into tokens
12 * and passing arguments to the appropriate handler.
14 * It works much like a command line. Only the first token is used to
15 * determine what function to call.
23 #include "shared/LL.h"
24 #include "shared/sockets.h"
25 #include "shared/report.h"
27 #include "commands/command_list.h"
31 #define MAX_ARGUMENTS 40
34 static inline int is_whitespace(char x
) {
35 return ((x
== ' ') || (x
== '\t') || (x
== '\r'));
38 static inline int is_final(char x
) {
39 return ((x
== '\n') || (x
== '\0'));
42 static inline int is_opening_quote(char x
, char q
) {
43 return ((q
== '\0') && ((x
== '\"') || (x
== '{')));
46 static inline int is_closing_quote(char x
, char q
) {
47 return (((q
== '{') && (x
== '}')) || ((q
== '\"') && (x
== '\"')));
51 static int parse_message(const char *str
, Client
*c
)
53 typedef enum { ST_INITIAL
, ST_WHITESPACE
, ST_ARGUMENT
, ST_FINAL
} State
;
54 State state
= ST_INITIAL
;
57 char quote
= '\0'; /* The quote used to open a quote string */
61 char *argv
[MAX_ARGUMENTS
];
63 CommandFunc function
= NULL
;
65 debug(RPT_DEBUG
, "%s(str=\"%.120s\", client=[%d])", __FUNCTION__
, str
, c
->sock
);
67 /* We will create a list of strings that is shorter or equally long as
68 * the original string str.
70 arg_space
= malloc(strlen(str
)+1);
71 if (arg_space
== NULL
) {
72 report(RPT_ERR
, "%s: Could not allocate memory", __FUNCTION__
);
73 sock_send_error(c
->sock
, "error allocating memory!\n");
78 while ((state
!= ST_FINAL
) && !error
) {
84 if (is_whitespace(ch
))
90 /* otherwise fall through */
96 if (argc
>= MAX_ARGUMENTS
-1) {
100 argv
[argc
][argpos
] = '\0';
101 argv
[argc
+1] = argv
[argc
] + argpos
+ 1;
107 else if (ch
== '\\') {
109 /* We solve quoted chars here right away */
110 const char escape_chars
[] = "nrt";
111 const char escape_trans
[] = "\n\r\t";
112 char *p
= strchr(escape_chars
, str
[pos
]);
114 /* Is it wise to have the characters \n, \r & \t expanded ?
115 * Can the displays deal with them ?
118 /* Insert a replacement for the code */
119 argv
[argc
][argpos
++] = escape_trans
[p
- escape_chars
];
122 /* Copy char literally */
123 argv
[argc
][argpos
++] = str
[pos
];
129 /* alternative: argv[argc][argpos++] = ch; */
130 if (argc
>= MAX_ARGUMENTS
-1) {
134 argv
[argc
][argpos
] = '\0';
135 argv
[argc
+1] = argv
[argc
] + argpos
+ 1;
142 else if (is_opening_quote(ch
, quote
)) {
145 else if (is_closing_quote(ch
, quote
)) {
147 if (argc
>= MAX_ARGUMENTS
-1) {
151 argv
[argc
][argpos
] = '\0';
152 argv
[argc
+1] = argv
[argc
] + argpos
+ 1;
156 state
= ST_WHITESPACE
;
158 else if (is_whitespace(ch
) && (quote
== '\0')) {
159 if (argc
>= MAX_ARGUMENTS
-1) {
163 argv
[argc
][argpos
] = '\0';
164 argv
[argc
+1] = argv
[argc
] + argpos
+ 1;
168 state
= ST_WHITESPACE
;
171 argv
[argc
][argpos
++] = ch
;
175 /* This will never be reached */
179 if (argc
< MAX_ARGUMENTS
)
185 sock_send_error(c
->sock
, "Could not parse command\n");
190 #if 0 /* show what we have parsed */
192 for (i
= 0; i
< argc
; i
++) {
193 printf("%s%c", argv
[i
], (i
== argc
-1) ? '\n' : ' ');
197 /* Now find and call the appropriate function...*/
198 function
= get_command_function(argv
[0]);
200 if (function
!= NULL
) {
201 error
= function(c
, argc
, argv
);
203 sock_printf_error(c
->sock
, "Function returned error \"%.40s\"\n", argv
[0]);
204 report(RPT_WARNING
, "Command function returned an error after command from client on socket %d: %.40s", c
->sock
, str
);
208 sock_printf_error(c
->sock
, "Invalid command \"%.40s\"\n", argv
[0]);
209 report(RPT_WARNING
, "Invalid command from client on socket %d: %.40s", c
->sock
, str
);
218 parse_all_client_messages(void)
222 debug(RPT_DEBUG
, "%s()", __FUNCTION__
);
224 for (c
= clients_getfirst(); c
!= NULL
; c
= clients_getnext()) {
227 /* And parse all its messages...*/
228 /*debug(RPT_DEBUG, "parse: Getting messages...");*/
229 for (str
= client_get_message(c
); str
!= NULL
; str
= client_get_message(c
)) {
230 parse_message(str
, c
);