senc.c (3528B)
1 #include <ctype.h> 2 #include <errno.h> 3 #include <limits.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <unistd.h> 8 9 // IDEA: Color results based on match level 10 // or even better, color matching characters 11 12 #define MAX_RESULTS 50 13 #define MAX_PATH_LENGTH 256 14 15 /** 16 * Search match level 17 * FUZZY example: search 'his ring' will match on 'this string' 18 */ 19 enum {NONE, FUZZY, NOCASE, EXACT}; 20 21 FILE * fp; 22 typedef struct { 23 char * filename; 24 int matchlvl; 25 } match; 26 27 int 28 search(char * search_string, char * filename) { 29 int search_len = strlen(search_string); 30 int filename_len = strlen(filename); 31 if (search_len > filename_len) { 32 return NONE; 33 } 34 // Exact matches 35 int mchars = 0; 36 for (int i = 0; i < filename_len; i++) { 37 if (search_string[mchars] == filename[i]) { 38 mchars++; 39 } else { 40 mchars = 0; 41 } 42 if (mchars == search_len) { 43 return EXACT; 44 } 45 } 46 // Case insensitive matches 47 mchars = 0; 48 for (int i = 0; i < filename_len; i++) { 49 if (tolower(search_string[mchars]) == tolower(filename[i])) { 50 mchars++; 51 } else { 52 mchars = 0; 53 } 54 if (mchars == search_len) { 55 return NOCASE; 56 } 57 } 58 // Weak matches 59 mchars = 0; 60 for (int i = 0; i < filename_len; i++) { 61 if (tolower(search_string[mchars]) == tolower(filename[i])) { 62 mchars++; 63 } 64 if (mchars == search_len) { 65 return FUZZY; 66 } 67 } 68 return NONE; 69 } 70 71 72 /** 73 * Searches favorite paths and stores matches in given matches variable 74 */ 75 int 76 search_favs(match * matches, char * search_string) { 77 char buf[LINE_MAX]; 78 int line_match; 79 int read_chars; 80 int match_i = 0; 81 // TODO: Find out if getline is the preferred way 82 while (fgets(buf, LINE_MAX, fp)) { 83 line_match = search(search_string, buf); 84 int len = strlen(buf); 85 if (buf[len - 1] == '\n') { 86 buf[len - 1] = '\0'; 87 } 88 if (line_match == NONE) { 89 continue; 90 } 91 // Have to copy string, because setting 92 // filename = buf, will just make all filenames point to 93 // the same memory location and overwrite each other. 94 strcpy(matches[match_i].filename, buf); 95 matches[match_i].matchlvl = line_match; 96 match_i++; 97 if (match_i == MAX_RESULTS) { 98 break; 99 } 100 } 101 return match_i; 102 } 103 104 int 105 add_entry(char * new) { 106 char *line = NULL; 107 size_t len = 0; 108 ssize_t nread; 109 110 /* 111 const char * str = "Hello yy'aaalll\n"; 112 fwrite(str, sizeof(char), strlen(str), f); 113 if (errno) { 114 printf("errno = %d\n", errno); 115 } 116 */ 117 return 0; 118 } 119 120 /** 121 * Sort matches by matchlvl 122 */ 123 int 124 compare_matches(const void * e1, const void * e2) { 125 match m1 = *((match*) e1); 126 match m2 = *((match*) e2); 127 return m2.matchlvl - m1.matchlvl; 128 } 129 130 char * 131 matchlvl_to_string(int match_level) { 132 switch (match_level) { 133 case FUZZY: return "fuzzy"; 134 case NOCASE: return "case ignored"; 135 case EXACT: return "exact"; 136 } 137 } 138 139 int 140 main(int nargs, char ** args) { 141 char * favs_file; 142 char * term; 143 int i; 144 if (nargs < 2) { 145 printf( 146 "Usage: senc [favorites file] <search term>\n" 147 ); 148 exit(EXIT_FAILURE); 149 } else if (nargs < 3) { 150 favs_file = strcat(getenv("HOME"), "/.sencs"); 151 term = args[1]; 152 } else { 153 favs_file = args[1]; 154 term = args[2]; 155 } 156 if ((fp = fopen(favs_file, "a+")) == NULL) { 157 perror("fopen"); 158 exit(EXIT_FAILURE); 159 } 160 161 match matches[MAX_RESULTS]; 162 for (i = 0; i < MAX_RESULTS; i++) { 163 matches[i].filename = malloc(LINE_MAX); 164 } 165 int match_i = search_favs(matches, term); 166 qsort(matches, match_i, sizeof(match), compare_matches); 167 for (i = 0; i < match_i; i++) { 168 printf("%s\t \e[1m%s\e[0m \n", matches[i].filename, 169 matchlvl_to_string(matches[i].matchlvl)); 170 } 171 fclose(fp); 172 }