#include #include "../global.h" #include "shared_survey_bar_graph.h" #include "shared_survey_string.h" #include "shared_survey_util.h" #include "shared_survey_xml_parser.h" #include "shared_record_parser.h" static int contains_empty_response(RESULT *one_result) { VALUE_COUNT *ptr; for(ptr = one_result->value_head; ptr; ptr = ptr->next) if(atoi(ptr->value) == -1) return 1; return 0; } static void nl_to_space(char *string) { char *ptr; for(ptr=string; *ptr; ptr++) if( (*ptr==10) || (*ptr == 13) || *ptr == '\'' || *ptr == '\"') *ptr = ' '; } void replace_quotes(char *str) { int i, len; len = strlen(str); for(i = 0; icaption); snprintf(name, MAX_TMP_NAME, "survey.question.%d.title", bar_graph_count); cs_set_value(name, data->caption); snprintf(name, MAX_TMP_NAME, "survey.question.%d.question_number", bar_graph_count); cs_set_int_value(name, question_number); #undef MAX_TMP_NAME } static void set_likert_values(SURVEY_DATA *likert, RESULT *one_result, int question_number, int bar_graph_count) { #define MAX_TMP_NAME 50 int i; int steps; char name[MAX_TMP_NAME]; char tmp_value[MAX_TMP_NAME]; int has_empty_responses = contains_empty_response(one_result); steps = atoi(likert->steps_bgcolor); set_likert_choice_common_values(likert, question_number, steps, "likert", bar_graph_count); one_result->value_current = one_result->value_head; if(has_empty_responses) one_result->value_current = one_result->value_current->next; for(i =1; i<=steps; i++) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1); if(one_result->value_current && atoi(one_result->value_current->value)==i) { snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", (float)one_result->value_current->count/(float)one_result->count*100.0); cs_set_value(name, tmp_value); one_result->value_current = one_result->value_current->next; } else { snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", 0.0); cs_set_value(name, tmp_value); } } if(has_empty_responses) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1); one_result->value_current = one_result->value_head; snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", (float)one_result->value_current->count/(float)one_result->count*100.0); cs_set_value(name, tmp_value); } snprintf(name, MAX_TMP_NAME, "survey.question.%d.number_choices", bar_graph_count); cs_set_int_value(name, has_empty_responses ? i: i-1); for(i =1; i<=steps; i++) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1); cs_set_int_value(name, i); } if(has_empty_responses) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1); cs_set_int_value(name, -1); } for(i = 0; ileft_cols); cs_set_value(name, likert->left_cols); } else if(i == steps -1) { nl_to_space(likert->right_rows); cs_set_value(name, likert->right_rows); } else { cs_set_value(name, " "); } } if(has_empty_responses) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.noanswer", bar_graph_count); cs_set_int_value(name, 1); } one_result->value_current = one_result->value_head; if(has_empty_responses) one_result->value_current = one_result->value_current->next; for(i =1; i<=steps; i++) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1); if(one_result->value_current && atoi(one_result->value_current->value)==i) { cs_set_int_value(name, one_result->value_current->count); one_result->value_current = one_result->value_current->next; } else cs_set_int_value(name, 0); } if(has_empty_responses) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1); one_result->value_current = one_result->value_head; cs_set_int_value(name, one_result->value_current->count); } #undef MAX_TMP_NAME } static int get_choice_count(SURVEY_DATA *choice) { int i = 0; choice->current = choice->head; while(choice->current) { i++; choice->current = choice->current->next; } return i; } static void set_choice_values(SURVEY_DATA *choice, RESULT *one_result, int question_number, int bar_graph_count ) { #define MAX_TMP_NAME 100 int i =1; int has_empty_responses = contains_empty_response(one_result); int flag = get_choice_count(choice); char name[MAX_TMP_NAME]; char tmp_value[MAX_TMP_NAME]; if(strcmp(choice->steps_bgcolor, "yes") ==0) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.multi", bar_graph_count); cs_set_int_value(name, 1); } set_likert_choice_common_values(choice, question_number, flag, "multi_choice", bar_graph_count); one_result->value_current = one_result->value_head; if(has_empty_responses) one_result->value_current = one_result->value_current->next; choice->current = choice->head; while(choice->current ) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1); if(one_result->value_current && (atoi(one_result->value_current->value) == i)) { snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", ((float)one_result->value_current->count/(float)one_result->count) * 100.0); cs_set_value(name, tmp_value); one_result->value_current = one_result->value_current->next; } else { snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", 0.0); cs_set_value(name, tmp_value); } i++; choice->current = choice->current->next; } if(has_empty_responses) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1); one_result->value_current = one_result->value_head; snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", ((float)one_result->value_current->count/(float)one_result->count) * 100.0); cs_set_value(name, tmp_value); } snprintf(name, MAX_TMP_NAME, "survey.question.%d.number_choices", bar_graph_count); cs_set_int_value(name, has_empty_responses ? i: i-1); for(i =1; i<=flag; i++) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1); cs_set_int_value(name, i); } if(has_empty_responses) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1); cs_set_int_value(name, -1); } i = 1; choice->current = choice->head; while(choice->current ) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.legend.%d", bar_graph_count, i-1); nl_to_space(choice->current->choice); cs_set_value(name, choice->current->choice); i++; choice->current = choice->current->next; } if(has_empty_responses) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.noanswer", bar_graph_count); cs_set_int_value(name, 1); } one_result->value_current = one_result->value_head; if(has_empty_responses) one_result->value_current = one_result->value_current->next; choice->current = choice->head; i =1; while(choice->current ) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1); if(one_result->value_current && atoi(one_result->value_current->value) == i) { cs_set_int_value(name, one_result->value_current->count); one_result->value_current = one_result->value_current->next; } else cs_set_int_value(name, 0); i++; choice->current = choice->current->next; } if(has_empty_responses) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1); one_result->value_current = one_result->value_head; cs_set_int_value(name, one_result->value_current->count); } #undef MAX_TMP_NAME } static void set_memo_values(SURVEY_DATA *memo, RESULT *one_result, int question_number, char *question_type, int element_number) { #define MAX_TMP_NAME 50 char name[MAX_TMP_NAME]; int i =0; snprintf(name, MAX_TMP_NAME, "survey.question.%d.type", element_number); cs_set_value(name, question_type ); snprintf(name, MAX_TMP_NAME, "survey.question.%d.title", element_number); cs_set_value(name, memo->caption); snprintf(name, MAX_TMP_NAME, "survey.question.%d.question_number", element_number); cs_set_int_value(name, question_number); one_result->value_current = one_result->value_head; while(one_result->value_current) { if(strcmp(one_result->value_current->value, "-1") == 0) { snprintf(name, MAX_TMP_NAME, "survey.question.%d.no_count", element_number); cs_set_int_value(name, one_result->value_current->count); } else { snprintf(name, MAX_TMP_NAME, "survey.question.%d.answer.%d", element_number, i); cs_set_value(name, one_result->value_current->value); snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", element_number, i); cs_set_int_value(name, one_result->value_current->count); i++; } one_result->value_current = one_result->value_current->next; } #undef MAX_TMP_NAME } static RESULT * get_one_result(RECORD *list, int id) { RESULT *ptr; ptr = list->head; while(ptr) { if(ptr->id == id ) return ptr; ptr = ptr->next; } return 0; } static int value_cmp(const char *a, const char *b) { int value_a, value_b; if(!strcmp(a,b)) return 0; if(!strcmp(a, "-1")) return -1; if(!strcmp(b,"-1")) return 1; value_a = atoi(a); value_b = atoi(b); if(value_a >value_b) return 1; return -1; } static RESULT * sort_one_result(RESULT *one) { VALUE_COUNT *q, *tail, *p, *r; if (one->value_head != NULL) { tail = one->value_head; while (tail->next) { q = tail->next; if (value_cmp (q->value, one->value_head->value) < 0) { tail->next = q->next; q->next = one->value_head; one->value_head = q; } else { r = one->value_head; p = r->next; while (value_cmp (q->value, p->value) > 0) { r = p; p = r->next; } if (q == p) tail = q; else { tail->next = q->next; q->next = p; r->next = q; } } } } return one; } static RECORD * sort_value_list(RECORD * list) { list->current = list->head; while(list->current) { list->current = sort_one_result(list->current); list->current = list->current->next; } return list; } static void set_response_rate_title(SURVEY_DATA *data, RECORD *list, int number_takers) { float response_rate; char tmp_value[MAX_PATH +1]; char server_string[MAX_PATH +1]; list->current = list->head; get_server_string(server_string, MAX_PATH); cs_set_value("survey.server_string", server_string); cs_set_int_value("survey.num_response", list->current->count); /* print number of people who could have taken the survey */ if(number_takers == -1) { cs_set_int_value("survey.num_expect_takers", list->expect_takers); response_rate = (float) list->current->count/list->expect_takers; } else if(number_takers > 0) { cs_set_int_value("survey.num_expect_takers", number_takers); response_rate = (float)list->current->count/number_takers; } snprintf(tmp_value, MAX_PATH +1, "%.1f%%", response_rate * 100.0); cs_set_value("survey.rate", tmp_value); cs_set_value("survey.title", data->caption); } static void set_title_element(SURVEY_LIST *list, RECORD *record_list, int number_takers) { int found = 0; for(list->current = list->head; list->current && !found; list->current=list->current->next) { found = !strcmp(list->current->tag_name, "title"); if(found) set_response_rate_title(list->current, record_list, number_takers); } } static void set_bar_graphs(SURVEY_LIST *list, RECORD *record_list, int *bar_graph_count) { int question_number = 0; RESULT *ptr; *bar_graph_count = 0; for(list->current = list->head; list->current; list->current=list->current->next) { if(strcmp(list->current->tag_name, "title") !=0 && strcmp(list->current->tag_name, "custom") != 0) question_number++; /** is_likert_tag() is in shared_survey_util.c ***/ if(is_likert_tag(list->current->tag_name) || !strcmp(list->current->tag_name, "choice") ) { ptr = get_one_result(record_list, list->current->id); if(ptr) { if(is_likert_tag(list->current->tag_name)) set_likert_values(list->current, ptr, question_number, *bar_graph_count); else set_choice_values(list->current, ptr, question_number, *bar_graph_count); (*bar_graph_count)++; } } } } static void set_text_responses(SURVEY_LIST *list, RECORD *record_list, int bar_graph_count) { int question_number = 0; RESULT *ptr; int element_number; element_number = bar_graph_count; for(list->current = list->head; list->current; list->current=list->current->next) { if(strcmp(list->current->tag_name, "title") != 0 && strcmp(list->current->tag_name, "custom") != 0) question_number++; if(!strcmp(list->current->tag_name, "memo") || !strcmp(list->current->tag_name, "text") ) { ptr = get_one_result(record_list, list->current->id); if(ptr) { set_memo_values(list->current, ptr, question_number, !strcmp(list->current->tag_name, "memo")?"memo":"short-answer", element_number); element_number++; } } } } static int find_value_in_list(VALUE_COUNT *v_head, char *temp, int count) { VALUE_COUNT *ptr; for(ptr = v_head; ptr; ptr = ptr->next) { if(strcmp(ptr->value, temp) ==0) { ptr->count = ptr->count +count; return 1; } } return 0; } static VALUE_COUNT *add_node(char *new_value, VALUE_COUNT *head, int count) { VALUE_COUNT *ptr, *current; ptr = (VALUE_COUNT *)malloc(sizeof(VALUE_COUNT)); if(!ptr) cs_critical_error(ERR_MALLOC_FAILED, "shared_survey_bar_graph"); ptr->value = malloc_str(new_value); ptr->count = count; ptr->next =0; if(!head) head = ptr; else { current = head; while(current->next) { current = current->next; } current->next = ptr; } return head; } static void parse_value(char *temp, char *new_value) { char *ptr; ptr = strchr(temp, '|'); if(!ptr) cs_critical_error(ERR_SURVEY_PARSE_DATA_FAILED, "Shared_survey_bar_graph"); *ptr = '\0'; strncpy(new_value, temp, MAX_PATH +1); ptr++; strncpy(temp, ptr, MAX_PATH +1); } static int get_number_data_fields(char *temp) { int count =0, len =0, i; len = strlen(temp); for(i =0; inext; if(head->value) free(head->value); free(head); head = ptr; } } static VALUE_COUNT *get_new_value_list(VALUE_COUNT *old) { VALUE_COUNT *v_head =0, *v_ptr; char temp[MAX_PATH +1]; char new_value[MAX_PATH +1]; int count =0, found =0, i; for(v_ptr = old; v_ptr; v_ptr = v_ptr->next) { strncpy(temp, v_ptr->value, MAX_PATH +1); count = get_number_data_fields(temp); if(count > 1) { for(i = 0; icount); if(!found) v_head = add_node(new_value, v_head, v_ptr->count); } found =0; temp[strlen(temp) -1] = '\0'; if(v_head) found = find_value_in_list(v_head, temp, v_ptr->count); if(!found) v_head = add_node(temp, v_head, v_ptr->count); } else { found = 0; temp[strlen(temp)-1] = '\0'; if(v_head) found = find_value_in_list(v_head, temp, v_ptr->count); if(!found) v_head = add_node(temp, v_head, v_ptr->count); } } return v_head; } RECORD * parse_multi_select_data(RECORD *re_list, int id) { RESULT *ptr; VALUE_COUNT *v_head =0; for(ptr = re_list->head; ptr; ptr = ptr->next) { if(id == ptr->id) { v_head = get_new_value_list(ptr->value_head); if(v_head) { free_value_count(ptr->value_head); ptr->value_head = v_head; } } } return re_list; } static void check_multi_choice_answers(SURVEY_LIST *list, RECORD *re_list) { SURVEY_DATA *ptr; for(ptr = list->head; ptr;ptr = ptr->next) { if(strcmp(ptr->tag_name, "choice") ==0 && strcmp(ptr->steps_bgcolor, "yes") ==0) { re_list = parse_multi_select_data(re_list, ptr->id); } } } int set_survey_graph_results( char *survey_fname, char *survey_result_fname, int number_takers) { SURVEY_LIST *list; RECORD *record_list; int results_found = 0; int bar_graph_count = 0; list = survey_data_parser(survey_fname); /* shared_survey_xml_parser.c */ record_list = record_parser(survey_result_fname); /* shared_record_parser.c */ if(record_list->head) { check_multi_choice_answers(list, record_list); record_list = sort_value_list(record_list); set_title_element(list, record_list, number_takers); set_bar_graphs(list,record_list, &bar_graph_count); set_text_responses(list,record_list, bar_graph_count); results_found = 1; } free_record_list(record_list); free_survey_data_list(list); return results_found; }