root/magic.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_indent
  2. count_chr
  3. i_strrstr
  4. hdr_is_c_or_cpp
  5. unsure_guess
  6. unsure_override

   1 #include <stdio.h>
   2 #include <string.h>
   3 #include <stddef.h>
   4 #include <stdlib.h>
   5 #include "magic.h"
   6 #include "nav.h"
   7 
   8 #define O_EQUALS(b, hint) if (strcmp(b, hint) == 0)
   9 
  10 static bool is_indent(const char *line, size_t limit) {
  11         size_t pos = 0;
  12 
  13         while (*line != '\0' && pos++ < limit) {
  14                 if (*line != ' ' && *line != '\t') return false;
  15 
  16                 line++;
  17         }
  18 
  19         return true;
  20 }
  21 
  22 static size_t count_chr(const char *line, size_t limit, int chr) {
  23         size_t cnt = 0;
  24         const char *ol = line;
  25 
  26         while ((line = memchr(line, chr, limit - (line - ol)))) {
  27                 line++; cnt++;
  28         }
  29 
  30         return cnt;
  31 }
  32 
  33 static const char *i_strrstr(const char *haystack, const char *needle) {
  34         const char *laststack = NULL;
  35         while ((haystack = strstr(haystack, needle))) {
  36                 laststack = haystack;
  37                 haystack += strlen(needle);
  38         }
  39         return laststack;
  40 }
  41 
  42 static const char *hdr_is_c_or_cpp(const char *path) {
  43         FILE *fptr;
  44 
  45         if ((fptr = fopen(path, "r")) == NULL) return NULL;
  46 
  47         const char *lang = "C";
  48         const char *finder;
  49         
  50         char *line = NULL;
  51         size_t len = 0;
  52         bool in_comment = false;
  53         
  54         while (getline(&line, &len, fptr) != -1) {
  55                 /* TODO: Treat semicolon & newline as delims? */
  56                 if ((finder = i_strrstr(line, "/*")))
  57                         if ((count_chr(line, finder - line, '"') & 1) == 0) {
  58                                 in_comment = true; finder += 2;
  59                         }
  60                 if (in_comment && strstr(finder ? finder : line, "*/"))
  61                         in_comment = false;
  62 #define FIND_CPP(sym) (finder = strstr(line, sym " "))
  63                 if (in_comment || !(FIND_CPP("class") || FIND_CPP("namespace")))
  64                         continue;
  65                 if (finder == line || is_indent(line, finder - line)) {
  66                         lang = "C++";
  67                         break;
  68                 }
  69         }
  70 
  71         fclose(fptr);
  72         free(line);
  73         return lang;
  74 }
  75 
  76 const char *unsure_guess(const char *path) {
  77         const char *bname = get_bname(path);
  78 
  79 #define G_EQUALS(hint) O_EQUALS(bname, hint)
  80 
  81         G_EQUALS("Makefile") return "Makefile";
  82         G_EQUALS("Doxyfile") return "Doxygen";
  83         G_EQUALS("makefile") return "Makefile"; /* This sometimes happens */
  84 
  85         FILE *fptr;
  86         if ((fptr = fopen(path, "r")) == NULL) return NULL;
  87 
  88         #define G_BUFMAX 64
  89         char buffer[G_BUFMAX] = {};
  90         size_t reads = 0;
  91         int c = 0;
  92         do {
  93                 c = fgetc(fptr);
  94                 if (feof(fptr) || reads >= G_BUFMAX || c == '\n' || c == '\r') break;
  95                 buffer[reads] = c;
  96                 reads++;
  97         } while (1);
  98 
  99         fclose(fptr);
 100 
 101         if (strlen(buffer) < 1) return NULL;
 102 
 103 #define G_CONTAINS(hint) if (strstr(buffer, hint))
 104 
 105         /* Check if a shebang exists at all, do non-shebang checks if not */
 106         if (strstr(buffer, "#!/") != buffer) {
 107                 G_CONTAINS("# Doxyfile") return "Doxygen";
 108                 G_CONTAINS("# vim")
 109                         G_CONTAINS("perl") return "Perl";
 110 
 111                 return NULL;
 112         }
 113 
 114         G_CONTAINS("python") return "Python";
 115         G_CONTAINS("perl")   return "Perl";
 116 
 117         G_CONTAINS("sh") {
 118                 G_CONTAINS("pwsh") return "PowerShell";
 119                 G_CONTAINS("fish") return "Fish";
 120 
 121                 return "Shell";
 122         }
 123 
 124         return NULL;
 125 }
 126 
 127 const char *unsure_override(const char *path, const char *ext) {
 128         O_EQUALS(ext, "h") return hdr_is_c_or_cpp(path);
 129 
 130         return NULL;
 131 }

/* [previous][next][first][last][top][bottom][index][help] */