aboutsummaryrefslogtreecommitdiff
path: root/Converter/src/compiler.c
blob: 04e97e70369e36f0879741620b6ea83dbb830d27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#include "../includes/compiler.h"
#include "../includes/array.h"
#include <string.h>

int find_string(string src, string query, size_t sz_src, size_t sz_query)
{
  int j = 0;
  while ((j < (sz_src - sz_query)) && (strncmp(query, src + j, sz_query))) ++j;
  return j;
}

bool is_token(char c)
{
  bool token_check = false;
  for (int i = 0; i < N_TOKENS; ++i)
    if (c == TOKENS[i])
    {
      token_check = true;
      break;
    }
  return token_check;
}

void compile_inner_text(string dest, string src, size_t sz_src,
                        string line_or_source)
{
  /* cursor is the current index on the dest pointer
   * lower represents the last tag character before content
   * upper represents the first tag character after content
   *
   * size_of_content is self explanatory (size of content delimited by tags)
   * tag_size is the compiled size of a tag
   * md_tag_size is the precompiled size of a tag
   *
   * tag is the string for the open HTML tag
   * close_tag is the string for the close HTML tag
   *
   * i and j are iterator variables
   */
  int cursor, lower, upper;
  size_t size_of_content, tag_size, md_tag_size;
  string md_tag, tag, close_tag;
  int i, j;

  lower = 0;
  upper = 0;
  cursor = 0;

  for (i = 0; i < sz_src; ++i)
  {
    if (is_token(src[i]))
    {
      // Information for each tag
      // NOTE: Here's where you add new text tags
      switch (src[i])
      {
      case '*': {
        // Twin asterisks
        if (src[i + 1] == '*')
        {
          md_tag = "**";
          tag = "<strong>";
          close_tag = "</strong>";
          tag_size = 8;
          md_tag_size = 2;
        }
        // one asterisk
        else
        {
          md_tag = "*";
          tag = "<i>";
          close_tag = "</i>";
          tag_size = 3;
          md_tag_size = 1;
        }
        break;
      }
      case '_': {
        tag = "<u>";
        close_tag = "</u>";
        md_tag = "_";
        tag_size = 3;
        md_tag_size = 1;
        break;
      }
      case '~': {
        tag = "<s>";
        close_tag = "</s>";
        md_tag = "~";
        tag_size = 3;
        md_tag_size = 1;
        break;
      }
      default:
        break;
      }

      if (src[i + md_tag_size] == '\0')
      {
        strncpy(dest, src + i, md_tag_size);
        break;
      }
      // find the corresponding markdown tag, and report errors
      j = find_string(src + i + md_tag_size, md_tag, sz_src - i - md_tag_size,
                      md_tag_size);
      j += i + md_tag_size;

      // error checking the token
      if (src[j] == md_tag[0])
      {
        lower = i + md_tag_size - 1;
        upper = j;
      }
      else
      {
        // error, no matching asterisk
        fprintf(stderr, "No corresponding %s for %s:%lu\n", md_tag,
                line_or_source, i + md_tag_size);
        exit(0);
      }

      size_of_content = upper - lower - 1;
      strncpy(dest + cursor, tag, tag_size);
      strncpy(dest + cursor + tag_size, src + lower + 1, size_of_content);
      strncpy(dest + cursor + tag_size + size_of_content, close_tag,
              tag_size + 1);
      cursor +=
          tag_size + size_of_content + tag_size + 1; // shift after operation
      i += size_of_content + (2 * md_tag_size) - 1;
    }
    else
    {
      strncpy(dest + cursor, &src[i], 1);
      cursor += 1;
    }
  }
}

string compile_line(string line, size_t size_of_line, string line_or_source)
{
  string compiled_line;
  size_t size_of_content;

  if (line[0] == '#' || line[0] == '-') // Compile a header or list item
  {
    const int tag_size = 4;
    int start_of_content;
    string tag, close_tag;
    if (line[0] == '#')
    {
      // Get the level of header (h1, h2, etc)
      int depth;
      for (depth = 1; line[depth] == '#'; ++depth) continue;
      start_of_content = depth;
      size_of_content = size_of_line - depth; // remove hashes

      // Generate the header tags based on depth
      tag = malloc(sizeof(*tag) * 5);
      close_tag = malloc(sizeof(*close_tag) * 6);
      sprintf(tag, "<h%d>", depth);
      sprintf(close_tag, "</h%d>", depth);
    }
    else
    {
      tag = "<li>";
      close_tag = "</li>";
      size_of_content = size_of_line - 1;
      start_of_content = 1;
    }

    // allocate buffer with space for content and opposing tags
    compiled_line =
        malloc(sizeof(*compiled_line) * (size_of_content + (2 * tag_size) + 2));
    // write start tag to compiled_line
    strncpy(compiled_line, tag, tag_size);
    // write the rest of the line to the compiled_line
    strncpy(compiled_line + tag_size, line + start_of_content, size_of_line);
    // write the end tags
    strncpy(compiled_line + size_of_content + tag_size, close_tag,
            tag_size + 1);
    // write the terminator
    compiled_line[size_of_content + (2 * tag_size) + 1] = '\0';
  }
  else // Compile a standard piece of text
  {
    compiled_line = malloc(sizeof(*compiled_line) * size_of_line * 2);
    compile_inner_text(compiled_line, line, size_of_line, line_or_source);
  }

  return compiled_line;
}

int nlines(FILE *fp)
{
  fseek(fp, 0, SEEK_SET);
  int line_number = 0;
  char ch;

  while (!feof(fp))
  {
    if (ch == '\n')
      ++line_number;
    ch = fgetc(fp);
  }
  return line_number;
}

string *compile_file(FILE *fp, string filename, int nlines)
{
  fseek(fp, 0, SEEK_SET);
  string current_header, compiled_line, line, *lines;
  int i, line_num;
  size_t sz_filename;

  current_header = malloc(sizeof(*current_header) * sz_filename);
  strcpy(current_header, filename);

  sz_filename = strlen(filename);
  lines = malloc(sizeof(*lines) * nlines);

  for (line_num = 1; (line_num - 1) < nlines; ++line_num)
  {
    line = malloc(sizeof(*line) * 1024);
    fgets(line, 1024, fp);

    // Null terminate line
    for (i = 0; line[i] != '\n' && line[i] != '\0'; ++i)
      ;
    line[i] = '\0';
    sprintf(current_header + sz_filename, ":%d", line_num);

    // Compile and append line
    compiled_line = compile_line(line, strlen(line), current_header);
    lines[line_num - 1] = compiled_line;
  }

  return lines;
}