/* * Generate a file with API status information from a list * of files in a directory. * Casper S. Hornstrup */ #include #include #include #include #include #ifdef WIN32 #include #include #include int __cdecl strcasecmp (const char * __sz1, const char * __sz2) {return _stricmp (__sz1, __sz2);} #else #if !defined(__FreeBSD__) && !defined(__APPLE__) #include #endif #include #include #include #include #endif #include #ifndef WIN32 #ifndef MAX_PATH #define MAX_PATH 260 #endif #define DIR_SEPARATOR_CHAR '/' #define DIR_SEPARATOR_STRING "/" #else #define DIR_SEPARATOR_CHAR '\\' #define DIR_SEPARATOR_STRING "\\" #endif #define TAG_UNKNOWN -1 #define TAG_IMPLEMENTED 0 #define TAG_UNIMPLEMENTED 1 typedef struct _API_INFO { struct _API_INFO *next; int tag_id; char name[100]; char filename[MAX_PATH]; } API_INFO, *PAPI_INFO; PAPI_INFO sort_linked_list(PAPI_INFO, unsigned, int (*)(PAPI_INFO, PAPI_INFO)); static FILE *in; static FILE *out; static FILE *file_handle = NULL; static char *file_buffer = NULL; static unsigned int file_size = 0; static unsigned int file_pointer = 0; static char tagname[200]; static PAPI_INFO api_info_list = NULL; static char* convert_path(char* origpath) { char* newpath; int i; newpath = strdup(origpath); i = 0; while (newpath[i] != 0) { #ifndef WIN32 if (newpath[i] == '\\') { newpath[i] = '/'; } #else #ifdef WIN32 if (newpath[i] == '/') { newpath[i] = '\\'; } #endif #endif i++; } return(newpath); } static char* path_to_url(char* path) { int i; i = 0; while (path[i] != 0) { if (path[i] == '\\') { path[i] = '/'; } i++; } return(path); } static void write_line(char *line) { char buf[200]; memset(buf, 0, sizeof(buf)); strcpy(buf, line); /* Terminate the line */ buf[strlen(buf)] = '\r'; buf[strlen(buf)] = '\n'; (void)fwrite(&buf[0], 1, strlen(buf), out); } static void read_file(char *filename) { file_handle = fopen(filename, "rb"); if (file_handle == NULL) { printf("Can't open %s\n", filename); exit(1); } // Get the size of the file fseek(file_handle, 0, SEEK_END); file_size = ftell(file_handle); // Load it all into memory file_buffer = malloc(file_size); if (file_buffer == NULL) { fclose(file_handle); printf("Out of memory\n"); exit(1); } fseek(file_handle, 0, SEEK_SET); if (file_size > 0) { if (fread (file_buffer, 1, file_size, file_handle) < 1) { fclose(file_handle); printf("Read error in file %s\n", filename); exit(1); } } file_pointer = 0; } static void close_file() { free(file_buffer); file_buffer = NULL; fclose(file_handle); file_handle = NULL; file_pointer = 0; } static int is_whitespace(char ch) { if (ch == ' ') { return 1; } if (ch == '\t') { return 1; } return 0; } static int is_eol_char(char ch) { if (ch == '\r') { return 1; } if (ch == '\n') { return 1; } return 0; } static int is_end_of_tag(char ch) { if ((ch >= 'a') && (ch <= 'z')) { return 0; } if ((ch >= 'A') && (ch <= 'Z')) { return 0; } if ((ch >= '0') && (ch <= '9')) { return 0; } if (ch == '_') { return 0; } return 1; } static int is_end_of_name(char ch) { /* Currently the same as is_end_of_tag() */ return is_end_of_tag(ch); } static int is_valid_file(char *filename) { char ext[MAX_PATH]; int i; i = strlen(filename); while (i > 0 && filename[i] != '.') { i--; } if (i > 0) { memset(ext, 0, sizeof(ext)); strncpy(&ext[0], &filename[i], strlen(&filename[i])); if ((strncmp(ext, ".c", 2) == 0) || (strncmp(ext, ".C", 2) == 0)) { return 1; } } return 0; } static int get_tag_id(char *tag) { if (strcasecmp(tag, "implemented") == 0) { return TAG_IMPLEMENTED; } if (strcasecmp(tag, "unimplemented") == 0) { return TAG_UNIMPLEMENTED; } return TAG_UNKNOWN; } static int skip_to_next_tag() { unsigned int start; int end_of_tag; int found_tag = 0; int tag_id; int len; tagname[0] = 0; while ((file_pointer < file_size) && (!found_tag)) { if (file_buffer[file_pointer] == '@') { file_pointer++; start = file_pointer; end_of_tag = 0; while ((file_pointer < file_size) && (!end_of_tag)) { end_of_tag = is_end_of_tag(file_buffer[file_pointer]); file_pointer++; } len = file_pointer > start ? file_pointer - start - 1 : 0; strncpy(tagname, &file_buffer[start], len); tagname[len] = 0; tag_id = get_tag_id(tagname); if (tag_id != TAG_UNKNOWN) { return tag_id; } } file_pointer++; } return TAG_UNKNOWN; } static void skip_line() { while ((file_pointer < file_size) && (!is_eol_char(file_buffer[file_pointer]))) { file_pointer++; } if ((file_pointer < file_size) && (file_buffer[file_pointer] == '\n')) { file_pointer++; } } static void skip_comments() { while ((file_pointer < file_size)) { if (file_buffer[file_pointer] == '*') { if ((file_pointer + 1 < file_size)) { if (file_buffer[file_pointer + 1] == '/') { skip_line(); return; } } } file_pointer++; } } static int get_previous_identifier(unsigned int end, char *name) { unsigned int my_file_pointer = end; int len; name[0] = 0; while ((my_file_pointer > 0) && (is_whitespace(file_buffer[my_file_pointer]) || is_eol_char(file_buffer[my_file_pointer]))) { my_file_pointer--; } /* Skip any comments between function name and it's parameters */ if ((my_file_pointer > 0) && (file_buffer[my_file_pointer] == '/')) { if ((my_file_pointer > 0) && (file_buffer[my_file_pointer - 1] == '*')) { my_file_pointer--; while ((my_file_pointer > 0) && !((file_buffer[my_file_pointer] == '*') && (file_buffer[my_file_pointer - 1] == '/'))) { my_file_pointer--; } my_file_pointer -= 2; } } /* Skip any remaining whitespace */ while ((my_file_pointer > 0) && (is_whitespace(file_buffer[my_file_pointer]))) { my_file_pointer--; } end = my_file_pointer; while ((my_file_pointer > 0)) { if (is_end_of_name(file_buffer[my_file_pointer])) { len = end - my_file_pointer; strncpy(name, &file_buffer[my_file_pointer + 1], len); name[len] = 0; return 1; } my_file_pointer--; } return 0; } static int skip_to_next_name(char *name) { while ((file_pointer < file_size)) { if (file_buffer[file_pointer] == '(') { return get_previous_identifier(file_pointer - 1, name); } file_pointer++; } return 0; } // Build a path and filename so it is of the format [module][directory][filename]. // Also convert all backslashes into forward slashes. static void get_filename(char *cvspath, char *filename, char *result) { strcpy(result, cvspath); strcat(result, filename); path_to_url(result); } static void parse_file(char *fullname, char *cvspath, char *filename) { PAPI_INFO api_info; char prev[200]; char name[200]; int tag_id; read_file(fullname); prev[0] = 0; do { tag_id = skip_to_next_tag(); if (tag_id == TAG_UNKNOWN) { break; } /* Skip rest of the comments between the tag and the function name */ skip_comments(); if (skip_to_next_name(name)) { if (strlen(name) == 0) { printf("Warning: empty function name in file %s. Previous function name was %s.\n", fullname, prev); } api_info = malloc(sizeof(API_INFO)); if (api_info == NULL) { printf("Out of memory\n"); exit(1); } api_info->tag_id = tag_id; strcpy(api_info->name, name); get_filename(cvspath, filename, api_info->filename); api_info->next = api_info_list; api_info_list = api_info; strcpy(prev, name); } } while (1); close_file(); } #ifdef WIN32 /* Win32 version */ static void process_directory (char *path, char *cvspath) { struct _finddata_t f; int findhandle; char searchbuf[MAX_PATH]; char buf[MAX_PATH]; char newcvspath[MAX_PATH]; strcpy(searchbuf, path); strcat(searchbuf, "*.*"); findhandle =_findfirst(searchbuf, &f); if (findhandle != -1) { do { if (f.attrib & _A_SUBDIR) { if (f.name[0] != '.') { strcpy(buf, path); strcat(buf, f.name); strcat(buf, DIR_SEPARATOR_STRING); strcpy(newcvspath, cvspath); strcat(newcvspath, f.name); strcat(newcvspath, "/"); process_directory(buf, newcvspath); } continue; } strcpy(buf, path); strcat(buf, f.name); /* Must be a .c file */ if (!is_valid_file(buf)) { continue; } parse_file(buf, cvspath, f.name); } while (_findnext(findhandle, &f) == 0); _findclose(findhandle); } else { printf("Cannot open directory '%s'", path); exit(1); } } #else /* Linux version */ static void process_directory (char *path, char *cvspath) { DIR *dirp; struct dirent *entry; struct stat stbuf; char buf[MAX_PATH]; char newcvspath[MAX_PATH]; #ifdef HAVE_D_TYPE dirp = opendir(path); if (dirp != NULL) { while ((entry = readdir(dirp)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; // skip self and parent if (entry->d_type == DT_REG) // normal file { // Check for an absolute path if (path[0] == DIR_SEPARATOR_CHAR) { strcpy(buf, path); strcat(buf, DIR_SEPARATOR_STRING); strcat(buf, entry->d_name); } else { if (!getcwd(buf, sizeof(buf))) { printf("Can't get CWD: %s\n", strerror(errno)); return; } strcat(buf, DIR_SEPARATOR_STRING); strcat(buf, path); strcat(buf, entry->d_name); } if (stat(buf, &stbuf) == -1) { printf("Can't access '%s' (%s)\n", buf, strerror(errno)); return; } if (S_ISDIR(stbuf.st_mode)) { strcpy(newcvspath, cvspath); strcat(newcvspath, f.name); strcat(newcvspath, "/"); process_directory(buf, newcvspath); continue; } /* Must be a .c file */ if (!is_valid_file(buf)) { continue; } parse_file(buf, cvspath, entry->d_name); } } closedir(dirp); } else { printf("Can't open %s\n", path); exit(1); } #else dirp = opendir(path); if (dirp != NULL) { while ((entry = readdir(dirp)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; // skip self and parent // Check for an absolute path if (path[0] == DIR_SEPARATOR_CHAR) { strcpy(buf, path); strcat(buf, DIR_SEPARATOR_STRING); strcat(buf, entry->d_name); } else { if (!getcwd(buf, sizeof(buf))) { printf("Can't get CWD: %s\n", strerror(errno)); return; } strcat(buf, DIR_SEPARATOR_STRING); strcat(buf, path); strcat(buf, entry->d_name); } if (stat(buf, &stbuf) == -1) { printf("Can't access '%s' (%s)\n", buf, strerror(errno)); return; } if (S_ISDIR(stbuf.st_mode)) { strcpy(newcvspath, cvspath); strcat(newcvspath, entry->d_name); strcat(newcvspath, "/"); process_directory(buf, newcvspath); continue; } /* Must be a .c file */ if (!is_valid_file(buf)) { continue; } parse_file(buf, cvspath, entry->d_name); } closedir(dirp); } else { printf("Can't open %s\n", path); exit(1); } #endif } #endif /* * This function compares two API entries. It returns a negative value if p is * before q, or a positive value if p is after q. */ static int compare_api_order(PAPI_INFO p, PAPI_INFO q) { return strcmp(p->name, q->name); } char * get_filename_without_base(char *component_base, char *filename) { return &filename[strlen(component_base)]; } static void generate_xml_for_component(char *component_name, char *component_base) { PAPI_INFO api_info; char canonical_base[MAX_PATH]; char buf[200]; int complete; int implemented_total; int unimplemented_total; // Sort list api_info_list = sort_linked_list(api_info_list, 0, compare_api_order); implemented_total = 0; unimplemented_total = 0; api_info = api_info_list; while (api_info != NULL) { if (api_info->tag_id == TAG_IMPLEMENTED) implemented_total ++; else if (api_info->tag_id == TAG_UNIMPLEMENTED) unimplemented_total ++; api_info = api_info->next; } if (implemented_total + unimplemented_total > 0) complete = ((implemented_total) * 100) / (implemented_total + unimplemented_total); else complete = 100; strcpy(canonical_base, component_base); path_to_url(canonical_base); sprintf(buf, "", component_name, canonical_base, complete, implemented_total, unimplemented_total); write_line(buf); if (api_info_list != NULL) { write_line(""); api_info = api_info_list; while (api_info != NULL) { sprintf(buf, "", api_info->name, api_info->tag_id == TAG_IMPLEMENTED ? "true" : "false", get_filename_without_base(component_base, api_info->filename)); write_line(buf); api_info = api_info->next; } write_line(""); } write_line(""); } static void read_input_file(char *input_file) { char component_name[MAX_PATH]; char component_path[MAX_PATH]; char *canonical_path; unsigned int index; unsigned int start; PAPI_INFO api_info; PAPI_INFO next_api_info; char *buffer; unsigned int size; int len; in = fopen(input_file, "rb"); if (in == NULL) { printf("Cannot open input file"); exit(1); } // Get the size of the file fseek(in, 0, SEEK_END); size = ftell(in); // Load it all into memory buffer = malloc(size); if (buffer == NULL) { fclose(in); printf("Out of memory\n"); exit(1); } fseek(in, 0, SEEK_SET); if (fread (buffer, 1, size, in) < 1) { fclose(in); printf("Read error in file %s\n", input_file); exit(1); } index = 0; write_line(""); write_line(""); write_line(""); write_line(""); while (1) { /* Free previous list */ for (api_info = api_info_list; api_info != NULL; api_info = next_api_info) { next_api_info = api_info->next; free(api_info); } api_info_list = NULL; /* Skip whitespace and eol characters */ while ((index < size) && (is_whitespace(buffer[index]) || (is_eol_char(buffer[index])))) index++; if ((file_pointer < size) && (buffer[index] == '\n')) index++; if (buffer[index] == ';') { /* Skip comments */ while ((index < size) && (!is_eol_char(buffer[index]))) index++; if ((index < size) && (buffer[index] == '\n')) index++; continue; } /* Get component name */ start = index; while ((index < size) && (!is_whitespace(buffer[index]))) index++; if (index >= size) break; len = index - start; strncpy(component_name, &buffer[start], len); component_name[len] = 0; /* Skip whitespace */ while ((index < size) && (is_whitespace(buffer[index]))) index++; if (index >= size) break; /* Get component path */ start = index; while ((index < size) && (!is_whitespace(buffer[index]) && !is_eol_char(buffer[index]))) index++; len = index - start; strncpy(component_path, &buffer[start], len); component_path[len] = 0; /* Append directory separator if needed */ if (component_path[strlen(component_path)] != DIR_SEPARATOR_CHAR) { int i = strlen(component_path); component_path[strlen(component_path)] = DIR_SEPARATOR_CHAR; component_path[i + 1] = 0; } /* Skip to end of line */ while ((index < size) && (!is_eol_char(buffer[index]))) index++; if ((index < size) && (buffer[index] == '\n')) index++; canonical_path = convert_path(component_path); if (canonical_path != NULL) { process_directory(canonical_path, canonical_path); free(canonical_path); generate_xml_for_component(component_name, component_path); } } write_line(""); } static char HELP[] = "RGENSTAT input-filename output-filename\n" "\n" " input-filename File containing list of components to process\n" " output-filename File to create\n"; int main(int argc, char **argv) { char *input_file; char *output_file; if (argc != 3) { puts(HELP); return 1; } input_file = convert_path(argv[1]); if (input_file[0] == 0) { free(input_file); printf("Missing input-filename\n"); return 1; } output_file = convert_path(argv[2]); if (output_file[0] == 0) { free(input_file); free(output_file); printf("Missing output-filename\n"); return 1; } out = fopen(output_file, "wb"); if (out == NULL) { free(input_file); free(output_file); printf("Cannot open output file"); return 1; } read_input_file(input_file); free(input_file); free(output_file); fclose(out); return 0; } /* EOF */