AT: Added AT response data processing and parsing
authorPaul Kocialkowski <contact@paulk.fr>
Mon, 30 Jul 2012 22:30:02 +0000 (00:30 +0200)
committerPaul Kocialkowski <contact@paulk.fr>
Mon, 30 Jul 2012 22:30:02 +0000 (00:30 +0200)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
at.c
at.h

diff --git a/at.c b/at.c
index 5a60fa8..e77d9f9 100644 (file)
--- a/at.c
+++ b/at.c
@@ -281,7 +281,7 @@ int at_responses_process_line(struct at_response ***responses_p, int responses_c
                        *responses_p = malloc(sizeof(struct at_response *) * count);
 
                        // Copy and free previous data
-                       if(responses != NULL) {
+                       if(responses != NULL && responses_count > 0) {
                                memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
                                free(responses);
                        }
@@ -325,7 +325,7 @@ int at_responses_process_line(struct at_response ***responses_p, int responses_c
                        *responses_p = malloc(sizeof(struct at_response *) * count);
 
                        // Copy and free previous data
-                       if(responses != NULL) {
+                       if(responses != NULL && responses_count > 0) {
                                memcpy(*responses_p, responses, sizeof(struct at_response *) * responses_count);
                                free(responses);
                        }
@@ -461,6 +461,221 @@ void at_response_free(struct at_response *response)
 }
 
 /*
+ * Response data parsing
+ */
+
+char *at_response_data_parse_string(char *data, int length)
+{
+       char *string = NULL;
+       int string_length = 0;
+       int mark = 0;
+       int quote = 0;
+       int i;
+
+       for(i=0 ; i < length ; i++) {
+               if(data[i] == '"') {
+                       if(quote & AT_PARSE_DOUBLE_QUOTE) {
+                               if(i - mark > 0) {
+                                       data[i] = '\0';
+
+                                       string_length = i - mark + 1;
+                                       string = strndup(data + mark, string_length);
+
+                                       if(!isprint(string[0])) {
+                                               free(string);
+                                               return NULL;
+                                       }
+                                       else {
+                                               return string;
+                                       }
+                               } else if(i - mark == 0) {
+                                       return strdup("");
+                               }
+                       } else {
+                               quote |= AT_PARSE_DOUBLE_QUOTE;
+                               mark = i + 1;
+                       }
+               }
+       }
+
+       // Only return the first string between a pair of "
+
+       return NULL;
+}
+
+int at_response_data_parse_numeric(char *data, int length)
+{
+       int i;
+
+       for(i=0 ; i < length ; i++) {
+               if(isdigit(data[i])) {
+                       return atoi(data + i);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Response data processing
+ */
+
+int at_response_data_process_value(struct at_response_data ***response_data_p, int response_data_count, char *data, int length)
+{
+       struct at_response_data **response_data = NULL;
+       char *response_data_string = NULL;
+       int response_data_numeric = 0;
+
+       int index = -1;
+       int count = 0;
+
+       if(response_data_p == NULL || data == NULL || length < 0) {
+               LOGE("Failed to process AT response data value: wrong arguments!");
+               return 0;
+       }
+
+       response_data = *response_data_p;
+
+       // Parse string
+       response_data_string = at_response_data_parse_string(data, length);
+       if(response_data_string != NULL) {
+               // Index is the response data index in the response data array
+               index = response_data_count;
+               // Count is the total count of response data in the array
+               count = index + 1;
+
+               // Alloc the array with the new size
+               *response_data_p = malloc(sizeof(struct at_response_data *) * count);
+
+               // Copy and free previous data
+               if(response_data != NULL && response_data_count > 0) {
+                       memcpy(*response_data_p, response_data, sizeof(struct at_response_data *) * response_data_count);
+                       free(response_data);
+               }
+
+               response_data = *response_data_p;
+
+               // Alloc new structure and copy obtained data
+               response_data[index] = calloc(1, sizeof(struct at_response_data));
+               response_data[index]->type = AT_RESPONSE_DATA_STRING;
+               response_data[index]->value.s = response_data_string;
+
+       } else {
+               response_data_numeric = at_response_data_parse_numeric(data, length);
+
+               // Index is the response data index in the response data array
+               index = response_data_count;
+               // Count is the total count of response data in the array
+               count = index + 1;
+
+               // Alloc the array with the new size
+               *response_data_p = malloc(sizeof(struct at_response_data *) * count);
+
+               // Copy and free previous data
+               if(response_data != NULL && response_data_count > 0) {
+                       memcpy(*response_data_p, response_data, sizeof(struct at_response_data *) * response_data_count);
+                       free(response_data);
+               }
+
+               response_data = *response_data_p;
+
+               // Alloc new structure and copy obtained data
+               response_data[index] = calloc(1, sizeof(struct at_response_data));
+               response_data[index]->type = AT_RESPONSE_DATA_NUMERIC;
+               response_data[index]->value.n = response_data_numeric;
+       }
+
+       return count > response_data_count ? count : response_data_count;
+}
+
+int at_response_data_process(struct at_response_data ***response_data_p, char *data, int length)
+{
+       int response_data_count = 0;
+       int count = 0;
+
+       char *string = NULL;
+       int string_length = 0;
+       int mark = 0;
+       int i;
+
+       if(response_data_p == NULL || data == NULL || length < 0) {
+               LOGE("Failed to process AT response data: wrong arguments!");
+               return 0;
+       }
+
+       for(i=0 ; i < length ; i++) {
+               if(data[i] == ',') {
+                       if(i - mark > 0) {
+                               data[i] = '\0';
+
+                               string_length = i - mark + 1;
+                               string = strndup(data + mark, string_length);
+
+                               if(!isprint(string[0])) {
+                                       free(string);
+                               }
+                               else {
+                                       count = at_response_data_process_value(response_data_p, response_data_count, string, string_length);
+                                       if(count > response_data_count)
+                                               response_data_count = count;
+
+                                       free(string);
+                               }
+
+                               mark = i + 1;
+                       }
+
+                       while(isspace(data[i+1])) {
+                               mark = i + 2;
+                               i++;
+                       }
+               }
+       }
+
+       if(length - mark > 0) {
+               for(i=mark ; i < length ; i++)
+                       if(!isprint(data[i]))
+                               break;
+
+               if(i - mark > 0) {
+                       string_length = i - mark + 1;
+                       string = calloc(1, string_length);
+
+                       memcpy(string, data + mark, string_length - 1);
+                       string[string_length - 1] = '\0';
+
+                       count = at_response_data_process_value(response_data_p, response_data_count, string, string_length);
+                       if(count > response_data_count)
+                               response_data_count = count;
+
+                       free(string);
+               }
+       }
+
+       return response_data_count;
+}
+
+void at_response_data_free(struct at_response_data **response_data, int response_data_count)
+{
+       int i;
+
+       if(response_data == NULL || response_data_count <= 0)
+               return;
+
+       for(i=0 ; i < response_data_count ; i++) {
+               if(response_data[i] != NULL) {
+                       if(response_data[i]->type == AT_RESPONSE_DATA_STRING && response_data[i]->value.s != NULL) {
+                               free(response_data[i]->value.s);
+                       }
+
+                       memset(response_data[i], 0, sizeof(struct at_response_data));
+               }
+       }
+
+       free(response_data);
+}
+
+/*
  * Handling
  */
 
diff --git a/at.h b/at.h
index 8651340..4df2dba 100644 (file)
--- a/at.h
+++ b/at.h
@@ -210,6 +210,21 @@ struct at_handling {
        struct at_async_requests_queue async_requests_queue;
 };
 
+enum {
+       AT_RESPONSE_DATA_NUMERIC,
+       AT_RESPONSE_DATA_STRING,
+};
+
+union at_response_data_value {
+       int n;
+       char *s;
+};
+
+struct at_response_data {
+       union at_response_data_value value;
+       int type;
+};
+
 /*
  * Functions
  */