325 lines
10 KiB
C
325 lines
10 KiB
C
#if 0
|
|
ctime -begin ${0%.*}.ctm
|
|
clang -g -fsanitize=address $0 -o ${0%.*} hmml.a
|
|
ctime -end ${0%.*}.ctm
|
|
exit
|
|
#endif
|
|
|
|
#include "hmmlib.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifndef bool
|
|
typedef unsigned int bool;
|
|
#endif
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
typedef struct
|
|
{
|
|
char *Location;
|
|
char *Ptr;
|
|
int Size;
|
|
} buffer;
|
|
|
|
int
|
|
StringLength(char *String)
|
|
{
|
|
int i = 0;
|
|
while(String[i])
|
|
{
|
|
++i;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
bool
|
|
StringsDiffer(char A[], char B[])
|
|
{
|
|
char APtr, BPtr;
|
|
while(*A)
|
|
{
|
|
APtr = *A++;
|
|
BPtr = *B++;
|
|
if(APtr >= 'A' && APtr <= 'Z')
|
|
{
|
|
APtr += 32;
|
|
}
|
|
if(BPtr >= 'A' && BPtr <= 'Z')
|
|
{
|
|
BPtr += 32;
|
|
}
|
|
if(APtr != BPtr)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int
|
|
main(int ArgC, char **Args)
|
|
{
|
|
if(ArgC < 2)
|
|
{
|
|
fprintf(stderr, "Usage: %s filename(s)\n", Args[0]);
|
|
return 1;
|
|
}
|
|
|
|
FILE *InFile;
|
|
for(int FileIndex = 1; FileIndex < ArgC; ++FileIndex)
|
|
{
|
|
if(!(InFile = fopen(Args[FileIndex], "r")))
|
|
{
|
|
perror(Args[0]);
|
|
return 1;
|
|
}
|
|
|
|
// Init MemoryArena
|
|
int ArenaSize = 1024 * 32;
|
|
char *MemoryArena;
|
|
if(!(MemoryArena = calloc(ArenaSize, 1)))
|
|
{
|
|
perror(Args[0]);
|
|
return 1;
|
|
}
|
|
int ClaimedMemory = 0;
|
|
|
|
// 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]);
|
|
HMML_Output HMML = hmml_parse_file(InFile);
|
|
fclose(InFile);
|
|
|
|
if(HMML.well_formed)
|
|
{
|
|
Out.Location = MemoryArena + ClaimedMemory;
|
|
Out.Size = 1024*16;
|
|
ClaimedMemory += Out.Size;
|
|
|
|
bool WritingChat = TRUE;
|
|
|
|
char *Member = HMML.metadata.twitch ?
|
|
HMML.metadata.twitch :
|
|
HMML.metadata.member;
|
|
|
|
for(int BuildPass = 0; BuildPass < 2; ++BuildPass)
|
|
{
|
|
if(WritingChat == FALSE)
|
|
{
|
|
printf("%s: %ld characters over budget. Shrinking...\n", Args[FileIndex], (Out.Ptr - Out.Location) - 5000);
|
|
}
|
|
|
|
Out.Ptr = Out.Location;
|
|
for(int AnnotationIndex = 0; AnnotationIndex < HMML.annotation_count; ++AnnotationIndex)
|
|
{
|
|
if(HMML.annotations[AnnotationIndex].author && !WritingChat)
|
|
{
|
|
goto skip;
|
|
}
|
|
|
|
InPtr = HMML.annotations[AnnotationIndex].time;
|
|
|
|
while(*InPtr)
|
|
{
|
|
*Out.Ptr++ = *InPtr++;
|
|
}
|
|
*Out.Ptr++ = ' ';
|
|
|
|
InPtr = HMML.annotations[AnnotationIndex].text;
|
|
|
|
|
|
// TODO(matt): Get this logic correct
|
|
if(HMML.annotations[AnnotationIndex].author)
|
|
{
|
|
Temp.Location = "Chat comment: \"";
|
|
Temp.Ptr = Temp.Location;
|
|
while(*Temp.Ptr)
|
|
{
|
|
*Out.Ptr++ = *Temp.Ptr++;
|
|
}
|
|
|
|
if(*HMML.annotations[AnnotationIndex].text)
|
|
{
|
|
InPtr = HMML.annotations[AnnotationIndex].text;
|
|
if(!StringsDiffer(Member, InPtr))
|
|
{
|
|
InPtr += StringLength(Member);
|
|
|
|
while(*InPtr &&
|
|
!(*InPtr >= '0' && *InPtr <= '9') &&
|
|
!(*InPtr >= 'A' && *InPtr <= 'Z') &&
|
|
!(*InPtr >= 'a' && *InPtr <= 'z'))
|
|
{
|
|
++InPtr;
|
|
}
|
|
|
|
if(*InPtr && *InPtr >= 'a' && *InPtr <= 'z')
|
|
{
|
|
*InPtr -= 32;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(HMML.annotations[AnnotationIndex].reference_count)
|
|
{
|
|
for(int RefIndex = 0; RefIndex < HMML.annotations[AnnotationIndex].reference_count; ++RefIndex)
|
|
{
|
|
while(InPtr - HMML.annotations[AnnotationIndex].text < HMML.annotations[AnnotationIndex].references[RefIndex].offset)
|
|
{
|
|
*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)
|
|
{
|
|
*Out.Ptr++ = *Temp.Ptr++;
|
|
}
|
|
}
|
|
|
|
if(HMML.annotations[AnnotationIndex].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(Out.Ptr[-1] != ' ')
|
|
{
|
|
*Out.Ptr++ = ' ';
|
|
}
|
|
*Out.Ptr++ = '-';
|
|
*Out.Ptr++ = ' ';
|
|
while(*Temp.Ptr)
|
|
{
|
|
*Out.Ptr++ = *Temp.Ptr++;
|
|
}
|
|
*Out.Ptr++ = ' ';
|
|
*Out.Ptr++ = '-';
|
|
}
|
|
else
|
|
{
|
|
if(Out.Ptr[-1] == ' ')
|
|
{
|
|
--Out.Ptr;
|
|
}
|
|
if(InPtr[-3] != ':')
|
|
{
|
|
*Out.Ptr++ = ':';
|
|
*Out.Ptr++ = ' ';
|
|
}
|
|
while(*Temp.Ptr)
|
|
{
|
|
*Out.Ptr++ = *Temp.Ptr++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
while(*InPtr)
|
|
{
|
|
*Out.Ptr++ = *InPtr++;
|
|
}
|
|
|
|
if(HMML.annotations[AnnotationIndex].author &&
|
|
WritingChat == TRUE)
|
|
{
|
|
*Out.Ptr++ = '\"';
|
|
}
|
|
|
|
*Out.Ptr++ = '\n';
|
|
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",
|
|
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;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(Out.Ptr - Out.Location > 5000)
|
|
{
|
|
fprintf(stderr, "%s: %ld characters over budget. Requires manual shrinking!\n", Args[FileIndex], (Out.Ptr - Out.Location) - 5000);
|
|
}
|
|
|
|
// NOTE(matt): At this point we should have filled a buffer with the stuff
|
|
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);
|
|
FILE *OutFile;
|
|
if(!(OutFile = fopen(Temp.Location, "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);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "%s:%d: %s\n", Args[FileIndex], HMML.error.line, HMML.error.message);
|
|
hmml_free(&HMML);
|
|
}
|
|
|
|
free(MemoryArena);
|
|
}
|
|
|
|
return 0;
|
|
}
|