#if 0 ctime -begin ${0%.*}.ctm gcc -g -fsanitize=address $0 -o ${0%.*} hmml.a ctime -end ${0%.*}.ctm exit #endif #include #include #include "hmmlib.h" #ifndef bool typedef bool unsigned int; #endif #define TRUE 1 #define FALSE 0 typedef struct { char *Location; char *Ptr; int Size; } buffer; void ClaimBuffer(char *MemoryArena, int *ClaimedMemory, buffer *Buffer, int Size) { Buffer->Location = MemoryArena + *ClaimedMemory; Buffer->Size = Size; *ClaimedMemory += Buffer->Size; Buffer->Ptr = Buffer->Location; } int TimecodeToSeconds(char *Timecode) { int HMS[3] = { 0, 0, 0 }; // 0 == Seconds; 1 == Minutes; 2 == Hours int Colons = 0; while(*Timecode) { if((*Timecode < '0' || *Timecode > '9') && *Timecode != ':') { return FALSE; } if(*Timecode == ':') { ++Colons; if(Colons > 2) { return FALSE; } for(int i = 0; i < Colons; ++i) { HMS[Colons - i] = HMS[Colons - (i + 1)]; } HMS[0] = 0; } else { HMS[0] = HMS[0] * 10 + *Timecode - '0'; } ++Timecode; } if(HMS[0] > 59 || HMS[1] > 59 || Timecode[-1] == ':') { return FALSE; } return HMS[2] * 60 * 60 + HMS[1] * 60 + HMS[0]; } void CopyBuffer(buffer *Src, buffer *Dest) { Src->Ptr = Src->Location; while(*Src->Ptr) { *Dest->Ptr++ = *Src->Ptr++; } } void CopyStringToBuffer(char *Src, buffer *Dest) { while(*Src) { *Dest->Ptr++ = *Src++; } } int main(int ArgC, char **Args) { if(ArgC < 2) { fprintf(stderr, "Usage: %s filename(s)\n", Args[0]); return 1; } // NOTE(matt): Init MemoryArena char *MemoryArena; int ArenaSize = 1024 * 1024; if(!(MemoryArena = calloc(ArenaSize, 1))) { perror(Args[0]); return 1; } int ClaimedMemory = 0; // NOTE(matt): Setup buffers and ptrs char *InPtr; buffer Working; buffer Text; buffer Out; ClaimBuffer(MemoryArena, &ClaimedMemory, &Out, 1024 * 512); for(int FileIndex = 1; FileIndex < ArgC; ++FileIndex) { FILE *InFile; if(!(InFile = fopen(Args[FileIndex], "r"))) { perror(Args[0]); free(MemoryArena); return 1; } HMML_Output HMML = hmml_parse_file(InFile); fclose(InFile); if(HMML.well_formed) { ClaimBuffer(MemoryArena, &ClaimedMemory, &Working, 1024); sprintf(Working.Location, "\n" " \n" " \n" "\n" " \n" " \n" " \n" " \n" " \n" "
\n" " %s\n", HMML.metadata.title); Out.Ptr = Out.Location; CopyBuffer(&Working, &Out); int AnnotationIndex = 0; int ReferenceIndex = 1; while(AnnotationIndex < HMML.annotation_count) { if(HMML.annotations[AnnotationIndex].reference_count) { sprintf(Working.Location, "
\n" " References ▼\n" "
\n" "
\n"); CopyBuffer(&Working, &Out); while(AnnotationIndex < HMML.annotation_count) { for(int i = 0; i < HMML.annotations[AnnotationIndex].reference_count; ++i) { // NOTE(matt): Consider removing the ref_index class if it ain't needed sprintf(Working.Location, " \n" " \n" "
%s
\n" "
%s
\n" "
\n" // NOTE(matt): Fill the div class="ref_indices" with <= 3 span // class="ref_index" and ensure to put these <=3 spans on the same line without // a space between them "
\n" " [%d]%s\n" "
\n" "
\n", AnnotationIndex, HMML.annotations[AnnotationIndex].references[i].url, HMML.annotations[AnnotationIndex].references[i].site ? HMML.annotations[AnnotationIndex].references[i].site : HMML.annotations[AnnotationIndex].references[i].author, HMML.annotations[AnnotationIndex].references[i].page ? HMML.annotations[AnnotationIndex].references[i].page : HMML.annotations[AnnotationIndex].references[i].title, TimecodeToSeconds(HMML.annotations[AnnotationIndex].time), ReferenceIndex, HMML.annotations[AnnotationIndex].time); CopyBuffer(&Working, &Out); ++ReferenceIndex; } ++AnnotationIndex; } } ++AnnotationIndex; } sprintf(Working.Location, "
\n" "
\n" " Annotator: %s\n" "
\n" "
\n" "
\n" "
\n", HMML.metadata.annotator, HMML.metadata.id); CopyBuffer(&Working, &Out); int DataRef = 1; for(int AnnotationIndex = 0; AnnotationIndex < HMML.annotation_count; ++AnnotationIndex) { InPtr = HMML.annotations[AnnotationIndex].text; ClaimBuffer(MemoryArena, &ClaimedMemory, &Text, 256); if(HMML.annotations[AnnotationIndex].reference_count) // || HMML.annotations[AnnotationIndex].is_quote) { sprintf(Working.Location, "
\n", TimecodeToSeconds(HMML.annotations[AnnotationIndex].time), AnnotationIndex); for(int RefLocalIndex = 0; RefLocalIndex < HMML.annotations[AnnotationIndex].reference_count; ++RefLocalIndex) { while(InPtr - HMML.annotations[AnnotationIndex].text < HMML.annotations[AnnotationIndex].references[RefLocalIndex].offset) { *Text.Ptr++ = *InPtr++; } int Inc = 0; if(HMML.annotations[AnnotationIndex].references[RefLocalIndex].offset <= 2) { if(HMML.annotations[AnnotationIndex].references[RefLocalIndex].page) { Inc = sprintf(Text.Ptr, "%s", HMML.annotations[AnnotationIndex].references[RefLocalIndex].page); } else if(HMML.annotations[AnnotationIndex].references[RefLocalIndex].site) { Inc = sprintf(Text.Ptr, "%s", HMML.annotations[AnnotationIndex].references[RefLocalIndex].site); } else if(HMML.annotations[AnnotationIndex].references[RefLocalIndex].title) { Inc = sprintf(Text.Ptr, "%s", HMML.annotations[AnnotationIndex].references[RefLocalIndex].title); } else { fprintf(stderr, "%s: Potentially incomplete reference at %s:%d\n", Args[0], Args[FileIndex], HMML.annotations[AnnotationIndex].line); } Text.Ptr += Inc; } if(HMML.annotations[AnnotationIndex].references[RefLocalIndex].offset <= 2 && Text.Ptr[-1] == ' ') { --Text.Ptr; } Inc = sprintf(Text.Ptr, "%d", DataRef); Text.Ptr += Inc; ++DataRef; } CopyStringToBuffer(InPtr, &Text); } else { sprintf(Working.Location, "
\n", TimecodeToSeconds(HMML.annotations[AnnotationIndex].time)); CopyStringToBuffer(InPtr, &Text); } *Text.Ptr = '\0'; CopyBuffer(&Working, &Out); sprintf(Working.Location, "
%s%s
\n" "
\n" "
%s%s
\n" "
\n" "
\n" "
%s%s
\n" "
\n" "
\n", HMML.annotations[AnnotationIndex].time, Text.Location, HMML.annotations[AnnotationIndex].time, Text.Location, HMML.annotations[AnnotationIndex].time, Text.Location); ClaimedMemory -= Text.Size; CopyBuffer(&Working, &Out); } sprintf(Working.Location, "
\n" "
\n" " \n" " \n" "\n"); CopyBuffer(&Working, &Out); hmml_free(&HMML); FILE *OutFile; //char *OutFilename; //sprintf(OutFilename, "%s.html", Args[FileIndex]); if(!(OutFile = fopen("out.html", "w"))) { perror(Args[0]); return 1; } fwrite(Out.Location, Out.Ptr - Out.Location, 1, OutFile); fclose(OutFile); } } free(MemoryArena); }