]> Shamusworld >> Repos - ardour-manual-diverged/blob - implode.cpp
Sync with master branch.
[ardour-manual-diverged] / implode.cpp
1 //
2 // Small program to 'implode' the master document automagically from separate
3 // files in the include/ directory.
4 //
5 // by James Hammons
6 // (C) 2017 Underground Software
7 //
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/stat.h>           // For mkdir()
13 #include <sys/types.h>
14
15
16 // Global variable (OMG YOU EVIL BASTARD!!)
17 char buffer[1024000], keyword[1024], token[1024];
18 char title[1024], shortTitle[1024], inclFile[1024], style[1024];
19 int level = 0, lastLevel = -1;
20 int lineCount = 0, startLine, sectionLineCount, fileCount = 0;
21 int part = 0, chapter = 0, subchapter = 0;
22 bool first = true;
23 bool nomove = false;
24 FILE * newFile = NULL;
25 char level1File[1024], level2File[1024], level3File[1024], temp[1024];
26 char partFN[1024], chapterFN[1024], scLink[4096];
27
28
29 void MakeFilename(char * fn)
30 {
31         int l = strlen(fn);
32
33         for(int i=0; i<l; i++)
34         {
35                 if (fn[i] == ' ')
36                         fn[i] = '-';
37                 else if (fn[i] >= 'A' && fn[i] <= 'Z')
38                         fn[i] |= 0x20;
39                 else if (fn[i] >= 'a' && fn[i] <= 'z')
40                         ;
41                 else if (fn[i] >= '0' && fn[i] <= '9')
42                         ;
43                 else
44                         fn[i] = '_';
45         }
46 }
47
48
49 long SkipHeader(FILE * file)
50 {
51         long length = 0;
52
53         while (true)
54         {
55                 // If we hit the EOF before finishing, something went horribly wrong
56                 if (feof(file))
57                         break;
58
59                 fgets(buffer, 1023999, file);
60                 length += strlen(buffer) + 1;
61
62                 // If we're seeing the end of header sentinel, return; we're done.
63                 if (strncmp(buffer, "---", 3) == 0)
64                         break;
65         }
66
67         while (true)
68         {
69                 // If we hit the EOF before finishing, something went horribly wrong
70                 if (feof(file))
71                         break;
72
73                 fgets(buffer, 1023999, file);
74                 length += strlen(buffer) + 1;
75
76                 // If we're seeing the end of header sentinel, return; we're done.
77                 if (strncmp(buffer, "---", 3) == 0)
78                         break;
79         }
80
81         return length;
82 }
83
84
85 void CopyFileToStream(char * from, FILE * toFile)
86 {
87         FILE * fromFile = fopen(from, "r");
88
89         if (fromFile == NULL)
90         {
91                 printf("\n\nCould not open file '%s' for reading! Aborting!!\n", from);
92                 exit(1);
93         }
94
95         fseek(fromFile, 0, SEEK_END);
96         long length = ftell(fromFile);
97         rewind(fromFile);
98         SkipHeader(fromFile);
99         long skipped = ftell(fromFile) - 1;
100
101         for(long i=skipped; i<length; i++)
102                 fputc(fgetc(fromFile), toFile);
103
104         fclose(fromFile);
105 }
106
107
108 bool ParseHeader(FILE * file)
109 {
110         while (true)
111         {
112                 // If we hit the EOF before finishing, something went horribly wrong
113                 if (feof(file))
114                         break;
115
116                 fgets(buffer, 1023999, file);
117                 lineCount++;
118
119                 // If we're seeing the end of header sentinel, return; we're done.
120                 if (strncmp(buffer, "---", 3) == 0)
121                         return true;
122
123                 sscanf(buffer, "%[^:]: %[^\n]", keyword, token);
124
125                 if (strcmp(keyword, "title") == 0)
126                 {
127                         strcpy(title, token);
128                 }
129                 else if (strcmp(keyword, "part") == 0)
130                 {
131                         lastLevel = level;
132                         int len = strlen(token);
133
134                         if (len == 4)
135                                 level = 0, part++;
136                         else if (len == 7)
137                                 level = 1, chapter++, subchapter = 0;
138                         else if (len == 10)
139                                 level = 2, subchapter++;
140                         else
141                                 level = -1;  // Something went wrong
142                 }
143                 else if (strcmp(keyword, "include") == 0)
144                 {
145                         strcpy(inclFile, token);
146                 }
147                 else if (strcmp(keyword, "menu_title") == 0)
148                 {
149                         strcpy(shortTitle, token);
150                 }
151                 else if (strcmp(keyword, "style") == 0)
152                 {
153                         strcpy(style, token);
154                 }
155                 else if (strcmp(keyword, "exclude") == 0)
156                 {
157                         // Don't care about the token, just the keyword
158                         nomove = true;
159                 }
160                 else
161                         printf("Unknown keyword '%s' (token: %s)\n", keyword, token);
162         }
163
164         // If we end up here, something went horribly wrong...
165         return false;
166 }
167
168
169 int main(int argc, char * argv[])
170 {
171         // First, check to see if this has been run here already.
172         FILE * fp = fopen("master-doc.txt", "r");
173         fgets(buffer, 1023999, fp);
174         fclose(fp);
175
176         if (strncmp(buffer, "<!-- imploded -->", 17) == 0)
177         {
178                 printf("Master file has already been imploded.\n");
179                 return 0;
180         }
181
182         // First, rename the master document
183         rename("master-doc.txt", "master-doc.bak");
184
185         // Then open the .bak file
186         FILE * master = fopen("master-doc.bak", "r");
187
188         if (master == NULL)
189         {
190                 printf("Could not open master doc (master-doc.txt) file!\n");
191                 return -1;
192         }
193
194         // Create new master document
195         FILE * exp = fopen("master-doc.txt", "w");
196
197         if (exp == NULL)
198         {
199                 printf("Could not open 'master-doc.txt' file!\n");
200                 fclose(master);
201                 return -1;
202         }
203
204         fprintf(exp, "<!-- imploded -->\n");
205
206         while (!feof(master))
207         {
208                 fgets(buffer, 1023999, master);
209                 lineCount++;
210
211                 // Look for start of file marker
212                 if (strncmp(buffer, "---", 3) == 0)
213                 {
214                         // Reset the "short" title, include file & style
215                         shortTitle[0] = 0;
216                         inclFile[0] = 0;
217                         style[0] = 0;
218                         nomove = false;
219
220                         if (!ParseHeader(master))
221                         {
222                                 printf("Something went horribly wrong with the header parsing! Aborting!\n");
223                                 break;
224                         }
225
226                         // Close any previously opened files...
227                         if (newFile != NULL)
228                         {
229                                 fclose(newFile);
230                                 newFile = NULL;
231                         }
232
233                         // We finished parsing our keyword block, now do something about
234                         // it... :-P
235                         if (level == 0)
236                         {
237                                 // Parts don't have any content...
238
239                                 // Set up the "part" level of TOC link
240                                 sprintf(partFN, "%s", temp);
241
242                                 // Set up content for the imploded part level
243                                 fprintf(exp, "\n---\n");
244                                 fprintf(exp, "title: %s\n", title);
245
246                                 if (strlen(shortTitle) > 0)
247                                         fprintf(exp, "menu_title: %s\n", shortTitle);
248
249                                 fprintf(exp, "part: part\n");
250                                 fprintf(exp, "---\n\n\n");
251                         }
252                         else if (level == 1)
253                         {
254                                 // Make a filename from the title (not short title!)
255                                 strcpy(chapterFN, title);
256                                 MakeFilename(chapterFN);
257
258                                 // Set up content for the imploded chapter level
259                                 fprintf(exp, "---\n");
260                                 fprintf(exp, "title: %s\n", title);
261
262                                 if (strlen(shortTitle) > 0)
263                                         fprintf(exp, "menu_title: %s\n", shortTitle);
264
265                                 // If it was already an include file, mark it to stay in include/
266                                 if (nomove)
267                                 {
268                                         fprintf(exp, "include: %s\n", inclFile);
269                                         fprintf(exp, "exclude: yes\n");
270                                 }
271
272                                 fprintf(exp, "part: chapter\n");
273                                 fprintf(exp, "---\n");
274
275                                 // Make the file expected at this level (but only if not
276                                 // included)...
277                                 if (nomove == false)
278                                 {
279                                         fileCount++;
280                                         sprintf(temp, "include/%s.html", chapterFN);
281                                         CopyFileToStream(temp, exp);
282                                         remove(temp);
283                                 }
284                                 else
285                                         fprintf(exp, "\n");
286                         }
287                         else if (level == 2)
288                         {
289                                 strcpy(scLink, title);
290                                 MakeFilename(scLink);
291
292                                 // Set up content for the exploded subchapter level
293                                 fprintf(exp, "---\n");
294                                 fprintf(exp, "title: %s\n", title);
295
296                                 if (strlen(shortTitle) > 0)
297                                         fprintf(exp, "menu_title: %s\n", shortTitle);
298
299                                 // If it was already an include file, mark it to stay in include/
300                                 if (nomove)
301                                 {
302                                         fprintf(exp, "include: %s\n", inclFile);
303                                         fprintf(exp, "exclude: yes\n");
304                                 }
305
306                                 fprintf(exp, "part: subchapter\n");
307                                 fprintf(exp, "---\n");
308
309                                 if (nomove == false)
310                                 {
311                                         fileCount++;
312                                         sprintf(temp, "include/%s.html", scLink);
313                                         CopyFileToStream(temp, exp);
314                                         remove(temp);
315                                 }
316                                 else
317                                         fprintf(exp, "\n");
318                         }
319                 }
320
321                 // Kill the buffer to prevent false positives...
322                 buffer[0] = 0;
323         }
324
325         printf("\nProcessed %i lines.\n", lineCount);
326         printf("Imploded master document from %i files.\n", fileCount);
327
328         fclose(master);
329         fclose(exp);
330
331         if (newFile)
332                 fclose(newFile);
333
334         // Finally, remove the .bak file:
335         remove("master-doc.bak");
336
337         return 0;
338 }
339