forb

Forb is static blog generator inspired by jekyll
git clone https://noulin.net/git/forb.git
Log | Files | Refs | README | LICENSE

preprocessor.c (7798B)


      1 
      2 #include "libsheepyObject.h"
      3 
      4 char *commentConfig = NULL;
      5 char *commentEndConfig = NULL;
      6 
      7 /* -------------------------------------------------------------------------------------
      8  * set comment config
      9  */
     10 internal void setCommentConfig(smallArrayt *input_lines) {
     11   forEachSmallArray(input_lines, L) {
     12     castS(l, L);
     13     if (hasG(l, "generator/pp comment config")) {
     14         smallStringt *lt = trimG(dupG(l));
     15         smallArrayt  *la = splitG(lt, ": generator/pp comment config");
     16         commentConfig    = getNDupG(la, rtChar, 0);
     17         commentEndConfig = trimG(getNDupG(la, rtChar, 1));
     18     }
     19     finishG(l);
     20   }
     21   if (not commentConfig) {
     22     commentConfig = strdup("#");
     23   }
     24 }
     25 
     26 internal smallArrayt *includePass(smallArrayt *input_lines, char *script_path) {
     27   createAllocateSmallArray(lines);
     28 
     29   char *include = catS(commentConfig, ":include");
     30 
     31   // Include files
     32   forEachSmallArray(input_lines, L) {
     33     castS(l, L);
     34     smallStringt *l2 = dupG(l);
     35     lowerG(l2);
     36     if (hasG(l2, include) and hasG(l2, "'")) {
     37       smallArrayt *a = splitG(l, "'");
     38       //putsG(l);
     39       //logVarG(a);
     40       char *file_to_include = catS(script_path, "/", getG(a, rtChar, 1));
     41       //logVarG(file_to_include);
     42       createAllocateSmallArray(file);
     43       readFileG(file, file_to_include);
     44       appendNSmashG(lines, file);
     45       terminateG(a);
     46     }
     47     else {
     48       pushG(lines, l);
     49     }
     50     terminateG(l2);
     51     finishG(l);
     52   }
     53   free(include);
     54   smashG(input_lines);
     55   return lines;
     56 }
     57 
     58 // Search and replace defines
     59 internal smallArrayt *definePass(smallArrayt *input_lines) {
     60   createAllocateSmallArray(lines);
     61 
     62   char *define = catS(commentConfig, ":define ");
     63   char *end    = catS(commentConfig, ":end");
     64   char *ppMark = catS(commentConfig, ":");
     65 
     66   // Assign values to defines
     67   createAllocateSmallDict(defines);
     68   char *status  = NULL;
     69   char *name = NULL;
     70   forEachSmallArray(input_lines, L) {
     71     castS(l, L);
     72     //logVarG(l);
     73     //logVarG(status);
     74     if (eqG(status, "define code")) {
     75       if (startsWithG(l, end)) {
     76         status = "no define";
     77       }
     78       else {
     79         smallArrayt *def = getG(defines, rtSmallArrayt, name);
     80         pushNFreeG(def, dupG(l));
     81         setPG(defines, name, def);
     82       }
     83     }
     84     if (hasG(l, define)) {
     85       smallArrayt *spl = splitG(l, define);
     86       free(name);
     87       name = getNDupG(spl, rtChar, 1);
     88       replaceG(&name, commentEndConfig, "", 1);
     89       terminateG(spl);
     90       createAllocateSmallArray(defineCode);
     91       setNFreeG(defines, name, defineCode);
     92       status = "define code";
     93     }
     94     finishG(l);
     95   }
     96   free(name);
     97   //logVarG(defines);
     98 
     99   // cg: replace define with value.
    100   char *statusDefine = "no define";
    101   forEachSmallArray(input_lines, L) {
    102     castS(l, L);
    103     //logVarG(l);
    104     //logVarG(status);
    105     //logVarG(statusDefine);
    106     if (not startsWithG(l, ppMark)) {
    107       pushG(lines, l);
    108     }
    109     else {
    110       if (eqG(l, ppMark)) {
    111         pushG(lines, l);
    112         finishG(l);
    113         continue;
    114       }
    115       status = "keep line";
    116       char *def = strdup(ssGet(l) + lenG(commentConfig) + 1);
    117       replaceG(&def, commentEndConfig, "", 1);
    118       trimG(&def);
    119       if (hasG(defines, def)) {
    120         status = "remove line";
    121       }
    122       if (not hasG(l, define) and ((not startsWithG(l, end)) or (startsWithG(l, end) and (eqG(statusDefine, "no define")))) and eqG(status, "keep line")) {
    123         pushG(lines, l);
    124       }
    125       if (hasG(defines, def)) {
    126         status = "remove line";
    127         smallArrayt *defCode = getNDupG(defines, rtSmallArrayt, def);
    128         //logVarG(def);
    129         //logVarG(defCode);
    130         appendNSmashG(lines, defCode);
    131       }
    132       if (startsWithG(l, end) and eqG(statusDefine, "define code")) {
    133         statusDefine = "no define";
    134       }
    135       if (startsWithG(l, define)) {
    136         statusDefine = "define code";
    137       }
    138     }
    139     finishG(l);
    140   }
    141   smashG(input_lines);
    142   terminateG(defines);
    143   freeManyS(define, end, ppMark);
    144   //logG(lines);
    145   return lines;
    146 }
    147 
    148 // Search tags
    149 // Process tags
    150 internal smallArrayt *tagPass(smallArrayt *input_lines) {
    151   createAllocateSmallArray(lines);
    152 
    153   char *ppMark = catS(commentConfig, ":");
    154 
    155   // Assign values to tags
    156   createAllocateSmallDict(tags);
    157   forEachSmallArray(input_lines, L) {
    158     castS(l, L);
    159     if (startsWithG(l, ppMark) and hasG(l, "=")) {
    160       smallStringt *l2 = dupG(l);
    161       replaceG(l2, commentEndConfig, "", 0);
    162       delG(l2, 0, lenG(commentConfig)+1);
    163       smallArrayt *spl = splitG(l2, "=");
    164       terminateG(l2);
    165       enumerateSmallArray(spl, T, i) {
    166         castS(t, T);
    167         setPG(spl, i, trimG(t));
    168         finishG(t);
    169       }
    170       char *s = getG(spl, rtChar, 1);
    171       setG(tags, getG(spl, rtChar, 0), s);
    172       terminateG(spl);
    173     }
    174     finishG(l);
    175   }
    176   //logVarG(tags);
    177 
    178   // cg: include or remove lines depending on tag value.
    179   char *status = "no tag";
    180   char *Yes, *No, *changeStatus;
    181   // support for inner tags in else closes
    182   createAllocateSmallArray(innerTags);
    183   forEachSmallArray(input_lines, L) {
    184     castS(l, L);
    185     //logVarG(status);
    186     //logVarG(innerTags);
    187     //logVarG(l);
    188     //put;
    189     if (startsWithG(l, ppMark) and (not hasG(l, "="))) {
    190       smallStringt *tag = dupG(l);
    191       delG(tag, 0, lenG(commentConfig)+1);
    192       replaceG(tag, commentEndConfig, "", 1);
    193       trimG(tag);
    194       if (eqG(tag, "end")) {
    195         delG(innerTags, -1, 0);
    196         status = "no tag";
    197       }
    198       else if (not hasG(l, "generator/pp comment config")) {
    199         if (eqG(tag, "else")) {
    200           if (eqG(status, "keep lines")) {
    201             status = "remove lines";
    202           }
    203           else {
    204             if (lenG(innerTags) > 1) {
    205               if (eqG(getG(innerTags, rtChar, 0), "remove lines")) {
    206                 status = "keep lines";
    207               }
    208             }
    209             else {
    210               status = "keep lines";
    211             }
    212           }
    213         }
    214         else {
    215           if (startsWithG(tag, "not ")) {
    216             delG(tag, 0, 4);
    217             Yes = "remove lines";
    218             No  = "keep lines";
    219           }
    220           else {
    221             Yes = "keep lines";
    222             No  = "remove lines";
    223           }
    224 
    225           if (lenG(innerTags) > 0) {
    226             if (eqG(getG(innerTags, rtChar, 0), "remove lines") and eqG(status, "keep lines")) {
    227                 changeStatus = "yes";
    228             }
    229             else {
    230                 changeStatus = "no";
    231             }
    232           }
    233           else {
    234             changeStatus = "yes";
    235           }
    236           if (eqG(changeStatus, "yes")) {
    237             if (hasG(tags, ssGet(tag))) {
    238               if (eqG(getG(tags, rtChar, ssGet(tag)), "0")) {
    239                 status = No;
    240               }
    241               else {
    242                 status = Yes;
    243               }
    244             }
    245             else {
    246               // tag doesnt exit, same as tag = 0
    247               status = No;
    248             }
    249           }
    250           pushG(innerTags, status);
    251         }
    252       }
    253     }
    254     if (not eqG(status, "remove lines") and not startsWithG(l, ppMark)) {
    255       pushG(lines, l);
    256     }
    257     finishG(l);
    258   }
    259   //logVarG(lines);
    260   terminateG(innerTags);
    261   smashG(input_lines);
    262   terminateG(tags);
    263   free(ppMark);
    264   return lines;
    265 }
    266 
    267 smallArrayt *preprocess(char *filename) {
    268   createAllocateSmallArray(lines);
    269 
    270   if (!fileExists(filename)) {
    271     printf("File not found: %s", filename);
    272   }
    273 
    274   char *dir = shDirnameG(filename);
    275   //logVarG(dir);
    276 
    277   readFileG(lines, filename);
    278 
    279   setCommentConfig(lines);
    280   //logVarG(commentConfig);
    281   //logVarG(commentEndConfig);
    282 
    283   lines = includePass(lines, dir);
    284   lines = definePass(lines);
    285   lines = tagPass(lines);
    286 
    287   free(dir);
    288   freen(commentConfig);
    289   freen(commentEndConfig);
    290   return lines;
    291 }
    292 
    293 bool checkLibsheepyVersionPreprocessor(const char *currentLibsheepyVersion) {
    294   return eqG(currentLibsheepyVersion, LIBSHEEPY_VERSION);
    295 }
    296