/src/rels.c

https://github.com/Tatsh/cmdpack · C · 211 lines · 162 code · 20 blank · 29 comment · 45 complexity · b9403487d52195cc7582d0781bac3104 MD5 · raw file

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. #define TITLE "rels - Relative Searcher"
  4. #define COPYR "Copyright (C) 2002,2010 Neill Corlett"
  5. //
  6. // This program is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // This program is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. //
  19. ////////////////////////////////////////////////////////////////////////////////
  20. #include "common.h"
  21. #include "banner.h"
  22. ////////////////////////////////////////////////////////////////////////////////
  23. void report(
  24. off_t filepos,
  25. const uint8_t* src,
  26. size_t len,
  27. const char* type
  28. ) {
  29. fprinthex(stdout, filepos, 8);
  30. printf(": ");
  31. while(len--) {
  32. uint8_t c = *src++;
  33. printf("%02X ", c);
  34. }
  35. printf("(%s)\n", type);
  36. }
  37. ////////////////////////////////////////////////////////////////////////////////
  38. int matchtest(
  39. const uint8_t* string,
  40. const uint8_t* buffer,
  41. size_t increment,
  42. int shift
  43. ) {
  44. int16_t stringstart;
  45. int16_t bufferstart;
  46. for(;;) {
  47. uint8_t c = *string;
  48. if(!c) { return 1; }
  49. if(c != '.') {
  50. stringstart = ((int16_t)( c )) & 0xFF;
  51. bufferstart = ((int16_t)(*buffer)) & 0xFF;
  52. break;
  53. }
  54. string++;
  55. buffer += increment;
  56. }
  57. for(;;) {
  58. uint8_t c = *string;
  59. if(!c) { break; }
  60. if(c != '.') {
  61. int16_t stringnow = ((int16_t)( c )) & 0xFF;
  62. int16_t buffernow = ((int16_t)(*buffer)) & 0xFF;
  63. stringnow -= stringstart;
  64. buffernow -= bufferstart;
  65. stringnow <<= shift;
  66. if(stringnow != buffernow) { return 0; }
  67. }
  68. string++;
  69. buffer += increment;
  70. }
  71. return 1;
  72. }
  73. ////////////////////////////////////////////////////////////////////////////////
  74. off_t relsearch(
  75. const uint8_t* string,
  76. const char* filename
  77. ) {
  78. FILE* f = NULL;
  79. uint8_t* buffer = NULL;
  80. size_t stringlen;
  81. size_t buffersize;
  82. off_t matchesfound = 0;
  83. off_t bufferbase;
  84. size_t bufferpos;
  85. size_t bufferlen;
  86. //
  87. // Examine length of search string
  88. //
  89. stringlen = strlen((const char*)string);
  90. // Avoid overflow
  91. if(stringlen > (((size_t)(-1)) / 2)) {
  92. printf("String is too long\n"); // very rare case
  93. goto done; // very rare case
  94. }
  95. //
  96. // Allocate buffer
  97. //
  98. buffersize = 2 * stringlen - 1;
  99. if(buffersize < 4096) {
  100. buffersize = 4096;
  101. }
  102. buffer = malloc(buffersize);
  103. if(!buffer) {
  104. printf("Out of memory\n");
  105. goto done;
  106. }
  107. f = fopen(filename, "rb");
  108. if(!f) { goto error_f; }
  109. printf("%s: ", filename);
  110. bufferbase = 0;
  111. bufferpos = 0;
  112. bufferlen = 0;
  113. for(;;) {
  114. size_t readsize;
  115. if(bufferlen && ((buffersize - bufferpos) < (2 * stringlen - 1))) {
  116. memmove(buffer, buffer + bufferpos, bufferlen);
  117. bufferbase += bufferpos;
  118. bufferpos = 0;
  119. }
  120. readsize = buffersize - (bufferpos + bufferlen);
  121. if((readsize > 0) && (!feof(f))) {
  122. readsize = fread(buffer + (bufferpos + bufferlen), 1, readsize, f);
  123. bufferlen += readsize;
  124. }
  125. if(bufferlen < stringlen) break;
  126. if(matchtest(string, buffer + bufferpos, 1, 0)) { if(matchesfound < 1) printf("\n"); matchesfound++; report(bufferbase + bufferpos, buffer + bufferpos, stringlen, "normal"); }
  127. else if(matchtest(string, buffer + bufferpos, 1, 1)) { if(matchesfound < 1) printf("\n"); matchesfound++; report(bufferbase + bufferpos, buffer + bufferpos, stringlen, "double"); }
  128. if(bufferlen >= (2 * stringlen - 1)) {
  129. if(matchtest(string, buffer + bufferpos, 2, 0)) { if(matchesfound < 1) printf("\n"); matchesfound++; report(bufferbase + bufferpos, buffer + bufferpos, 2 * stringlen - 1, "wide"); }
  130. else if(matchtest(string, buffer + bufferpos, 2, 1)) { if(matchesfound < 1) printf("\n"); matchesfound++; report(bufferbase + bufferpos, buffer + bufferpos, 2 * stringlen - 1, "wide double"); }
  131. }
  132. bufferpos++;
  133. bufferlen--;
  134. }
  135. printf(
  136. "%lu match%s found\n",
  137. (unsigned long)matchesfound,
  138. (matchesfound == 1) ? "" : "es"
  139. );
  140. goto done;
  141. error_f:
  142. printfileerror(f, filename);
  143. done:
  144. if(f != NULL) { fclose(f); }
  145. if(buffer != NULL) { free(buffer); }
  146. return matchesfound;
  147. }
  148. ////////////////////////////////////////////////////////////////////////////////
  149. int main(int argc, char **argv) {
  150. const uint8_t* string;
  151. int i;
  152. off_t total = 0;
  153. normalize_argv0(argv[0]);
  154. if(argc < 3) {
  155. banner();
  156. printf(
  157. "Usage: %s string files\n"
  158. "\n"
  159. "Search string may include '.' characters as wildcards, but must include at\n"
  160. "least two non-wildcard characters.\n",
  161. argv[0]
  162. );
  163. return 1;
  164. }
  165. string = (const uint8_t*)(argv[1]);
  166. { size_t nwc = 0;
  167. const uint8_t* s = string;
  168. for(;;) {
  169. uint8_t c = *s++;
  170. if(!c) { break; }
  171. if(c != '.') { nwc++; }
  172. }
  173. if(nwc < 2) {
  174. printf(
  175. "Search string must contain at least two non-wildcard characters\n"
  176. );
  177. return 1;
  178. }
  179. }
  180. printf("Searching for \"%s\":\n", string);
  181. for(i = 2; i < argc; i++) {
  182. total += relsearch(string, argv[i]);
  183. }
  184. printf(
  185. "Total: %lu %s found\n",
  186. (unsigned long)total,
  187. (total == 1) ? "match" : "matches"
  188. );
  189. return 0;
  190. }
  191. ////////////////////////////////////////////////////////////////////////////////