diff --git a/hmml_to_youtube/hmml_to_youtube.c b/hmml_to_youtube/hmml_to_youtube.c index ab09e9f..4e9c5ff 100644 --- a/hmml_to_youtube/hmml_to_youtube.c +++ b/hmml_to_youtube/hmml_to_youtube.c @@ -1,6 +1,6 @@ #if 0 ctime -begin ${0%.*}.ctm -clang -g -fsanitize=address $0 -o ${0%.*} hmml.a +gcc -g -fsanitize=address $0 -o ${0%.*} hmml.a ctime -end ${0%.*}.ctm exit #endif @@ -8,6 +8,7 @@ exit #include "hmmlib.h" #include #include +#include #ifndef bool typedef unsigned int bool; @@ -34,28 +35,36 @@ StringLength(char *String) return i; } -bool -StringsDiffer(char A[], char B[]) +char +ToLower(char Char) { - char APtr, BPtr; - while(*A) + if(Char >= 'A' && Char <= 'Z') { - APtr = *A++; - BPtr = *B++; - if(APtr >= 'A' && APtr <= 'Z') - { - APtr += 32; - } - if(BPtr >= 'A' && BPtr <= 'Z') - { - BPtr += 32; - } - if(APtr != BPtr) - { - return TRUE; - } + Char += 'a' - 'A'; } - return FALSE; + return Char; +} + +int +StringsDiffer(char *A, char *B) +{ + while(*A && *B && ToLower(*A) == ToLower(*B)) + { + ++A, ++B; + } + return *A - *B; +} + + +__attribute__ ((format (printf, 2, 3))) +void +CopyStringToBuffer(buffer *Dest, char *Format, ...) +{ + va_list Args; + va_start(Args, Format); + int Length = vsprintf(Dest->Ptr, Format, Args); + va_end(Args); + Dest->Ptr += Length; } int @@ -88,7 +97,6 @@ main(int ArgC, char **Args) // Buffers and Pointers char *InPtr; // Associated buffer is allocated by hmml_parse_file() - buffer Temp; // Temp.Ptr may be used independently of Temp.Location buffer Out; //printf("Reading %s\n", Args[FileIndex]); @@ -101,12 +109,12 @@ main(int ArgC, char **Args) Out.Size = 1024*16; ClaimedMemory += Out.Size; - bool WritingChat = TRUE; - char *Member = HMML.metadata.twitch ? HMML.metadata.twitch : HMML.metadata.member; + bool WritingChat = TRUE; + for(int BuildPass = 0; BuildPass < 2; ++BuildPass) { if(WritingChat == FALSE) @@ -115,111 +123,90 @@ main(int ArgC, char **Args) } Out.Ptr = Out.Location; + HMML_Annotation *Anno; for(int AnnotationIndex = 0; AnnotationIndex < HMML.annotation_count; ++AnnotationIndex) { - if(HMML.annotations[AnnotationIndex].author && !WritingChat) + Anno = HMML.annotations + AnnotationIndex; + + if(Anno->author && !WritingChat) { goto skip; } - InPtr = HMML.annotations[AnnotationIndex].time; + CopyStringToBuffer(&Out, "%s ", Anno->time); - while(*InPtr) + InPtr = Anno->text; + + if(Anno->author) { - *Out.Ptr++ = *InPtr++; + CopyStringToBuffer(&Out, "Chat comment: \""); } - *Out.Ptr++ = ' '; - InPtr = HMML.annotations[AnnotationIndex].text; + int MarkerIndex = 0, RefIndex = 0, InOffset = 0; - - // TODO(matt): Get this logic correct - if(HMML.annotations[AnnotationIndex].author) + while(*InPtr || RefIndex < Anno->reference_count) { - Temp.Location = "Chat comment: \""; - Temp.Ptr = Temp.Location; - while(*Temp.Ptr) + if(MarkerIndex < Anno->marker_count && + InPtr - Anno->text == Anno->markers[MarkerIndex].offset) { - *Out.Ptr++ = *Temp.Ptr++; - } - - if(*HMML.annotations[AnnotationIndex].text) - { - InPtr = HMML.annotations[AnnotationIndex].text; - if(!StringsDiffer(Member, InPtr)) + char *Readable = Anno->markers[MarkerIndex].parameter + ? Anno->markers[MarkerIndex].parameter + : Anno->markers[MarkerIndex].marker; + if(Anno->markers[MarkerIndex].type == HMML_MEMBER && (!StringsDiffer(Anno->markers[MarkerIndex].marker, Member))) { - InPtr += StringLength(Member); - + InPtr += StringLength(Readable); while(*InPtr && - !(*InPtr >= '0' && *InPtr <= '9') && - !(*InPtr >= 'A' && *InPtr <= 'Z') && - !(*InPtr >= 'a' && *InPtr <= 'z')) + ( *InPtr == ',' + || *InPtr == ':' + || *InPtr == ' ' + ) + ) { ++InPtr; } - - if(*InPtr && *InPtr >= 'a' && *InPtr <= 'z') + if(InPtr - Anno->text > 0 && !InOffset) { - *InPtr -= 32; + InOffset = InPtr - Anno->text; } } + ++MarkerIndex; } - } - if(HMML.annotations[AnnotationIndex].reference_count) - { - for(int RefIndex = 0; RefIndex < HMML.annotations[AnnotationIndex].reference_count; ++RefIndex) + if(RefIndex < Anno->reference_count && + InPtr - Anno->text == Anno->references[RefIndex].offset) { - while(InPtr - HMML.annotations[AnnotationIndex].text < HMML.annotations[AnnotationIndex].references[RefIndex].offset) + if(Anno->references[RefIndex].offset == InOffset) { - *Out.Ptr++ = *InPtr++; - } - - if(HMML.annotations[AnnotationIndex].references[RefIndex].offset == 0) - { - if(HMML.annotations[AnnotationIndex].references[RefIndex].page) - { - Temp.Ptr = HMML.annotations[AnnotationIndex].references[RefIndex].page; - } - else if(HMML.annotations[AnnotationIndex].references[RefIndex].site) - { - Temp.Ptr = HMML.annotations[AnnotationIndex].references[RefIndex].site; - } - else if(HMML.annotations[AnnotationIndex].references[RefIndex].title) - { - Temp.Ptr = HMML.annotations[AnnotationIndex].references[RefIndex].title; - } - if(Out.Ptr[-1] != '"' && Out.Ptr[-1] != ' ') { *Out.Ptr++ = ' '; } - while(*Temp.Ptr) + if(Anno->references[RefIndex].page) { - *Out.Ptr++ = *Temp.Ptr++; + CopyStringToBuffer(&Out, "%s", Anno->references[RefIndex].page); + } + else if(Anno->references[RefIndex].site) + { + CopyStringToBuffer(&Out, "%s", Anno->references[RefIndex].site); + } + else if(Anno->references[RefIndex].title) + { + CopyStringToBuffer(&Out, "%s", Anno->references[RefIndex].title); } } - if(HMML.annotations[AnnotationIndex].references[RefIndex].url) + if(Anno->references[RefIndex].url) { - Temp.Ptr = HMML.annotations[AnnotationIndex].references[RefIndex].url; - - if(HMML.annotations[AnnotationIndex].references[RefIndex].offset < StringLength(HMML.annotations[AnnotationIndex].text) || - RefIndex < HMML.annotations[AnnotationIndex].reference_count-1) + if(Anno->references[RefIndex].offset < StringLength(Anno->text) || + RefIndex < Anno->reference_count-1) { if(Out.Ptr[-1] != ' ') { *Out.Ptr++ = ' '; } - *Out.Ptr++ = '-'; - *Out.Ptr++ = ' '; - while(*Temp.Ptr) - { - *Out.Ptr++ = *Temp.Ptr++; - } - *Out.Ptr++ = ' '; - *Out.Ptr++ = '-'; + + CopyStringToBuffer(&Out, "- %s -", Anno->references[RefIndex].url); } else { @@ -229,24 +216,36 @@ main(int ArgC, char **Args) } if(InPtr[-3] != ':') { - *Out.Ptr++ = ':'; - *Out.Ptr++ = ' '; - } - while(*Temp.Ptr) - { - *Out.Ptr++ = *Temp.Ptr++; + CopyStringToBuffer(&Out, ": "); } + CopyStringToBuffer(&Out, "%s", Anno->references[RefIndex].url); } } + ++RefIndex; } + + if(*InPtr) + { + switch(*InPtr) + { + case '<': + CopyStringToBuffer(&Out, "<"); + break; + case '>': + CopyStringToBuffer(&Out, ">"); + break; + case '#': + break; + default: + *Out.Ptr++ = *InPtr; + break; + } + ++InPtr; + } + } - while(*InPtr) - { - *Out.Ptr++ = *InPtr++; - } - - if(HMML.annotations[AnnotationIndex].author && + if(Anno->author && WritingChat == TRUE) { *Out.Ptr++ = '\"'; @@ -256,22 +255,9 @@ main(int ArgC, char **Args) skip: {}; } - Temp.Location = MemoryArena + ClaimedMemory; - Temp.Size = 256; - ClaimedMemory += Temp.Size; - Temp.Ptr = Temp.Location; - - sprintf(Temp.Location, "\nAnnotated by %s - https://handmade.network/m/%s\n", + CopyStringToBuffer(&Out, "\nAnnotated by %s - https://handmade.network/m/%s\n", HMML.metadata.annotator, HMML.metadata.annotator); - while(*Temp.Ptr) - { - *Out.Ptr++ = *Temp.Ptr++; - } - - *Temp.Location = '\0'; - ClaimedMemory -= Temp.Size; - if(Out.Ptr - Out.Location > 5000) { WritingChat = FALSE; @@ -291,23 +277,17 @@ skip: {}; hmml_free(&HMML); // NOTE(matt): Open a file for writing out to - Temp.Location = MemoryArena + ClaimedMemory; - Temp.Size = StringLength(Args[FileIndex]) + 5; - ClaimedMemory += Temp.Size; - - sprintf(Temp.Location, "%s.txt", Args[FileIndex]); - //printf("Writing to %s\n", Temp.Location); + char Filename[StringLength(Args[FileIndex]) + 5]; + sprintf(Filename, "%s.txt", Args[FileIndex]); + //printf("Writing to %s\n", Filename); FILE *OutFile; - if(!(OutFile = fopen(Temp.Location, "w"))) + if(!(OutFile = fopen(Filename, "w"))) { perror(Args[0]); free(MemoryArena); return 1; } - *Temp.Location = '\0'; - ClaimedMemory -= Temp.Size; - fwrite(Out.Location, Out.Ptr - Out.Location, 1, OutFile); fclose(OutFile); } diff --git a/hmml_to_youtube/hmmlib.h b/hmml_to_youtube/hmmlib.h new file mode 100644 index 0000000..acf637a --- /dev/null +++ b/hmml_to_youtube/hmmlib.h @@ -0,0 +1,88 @@ +#ifndef HMML_H_ +#define HMML_H_ +#include +#include +#include +#include + +// Data structures + +typedef struct { + char* member; + char* twitch; + char* project; + char* title; + char* platform; + char* id; + char* annotator; +} HMML_VideoMetaData; + +typedef struct { + char* site; + char* page; + char* url; + char* title; + char* article; + char* author; + char* editor; + char* publisher; + char* isbn; + int offset; +} HMML_Reference; + +typedef enum { + HMML_CATEGORY, + HMML_MEMBER, + HMML_PROJECT, + + HMML_MARKER_COUNT, +} HMML_MarkerType; + +typedef struct { + HMML_MarkerType type; + char* marker; + char* parameter; + int offset; +} HMML_Marker; + +typedef struct { + int id; + char* author; +} HMML_Quote; + +typedef struct { + int line; + char* time; + char* text; + char* author; + + HMML_Reference* references; + size_t reference_count; + + HMML_Marker* markers; + size_t marker_count; + + HMML_Quote quote; + bool is_quote; +} HMML_Annotation; + +typedef struct { + int line; + char* message; +} HMML_Error; + +typedef struct { + bool well_formed; + HMML_VideoMetaData metadata; + HMML_Annotation* annotations; + size_t annotation_count; + HMML_Error error; +} HMML_Output; + +// Functions + +HMML_Output hmml_parse_file (FILE* file); +void hmml_dump (HMML_Output* output); +void hmml_free (HMML_Output* output); + +#endif