Commit 0aa585a1 authored by Matt Mascarenhas's avatar Matt Mascarenhas

cinera: Allow custom output paths

Relative to the Base:
    -a sets the player location
    -n sets the index location

Tweak flags, and add -B to set Base URL (necessary if setting -a or -n)

New template tags:
    __CINERA_URL__
    __CINERA_VIDEO_ID__

Bump DB version: 2
    index_header now contains the Index and Player Locations
parent 7312de56
......@@ -14,10 +14,10 @@ typedef struct
version CINERA_APP_VERSION = {
.Major = 0,
.Minor = 5,
.Patch = 8
.Patch = 9
};
#define CINERA_DB_VERSION 1
#define CINERA_DB_VERSION 2
#define DEBUG 0
#define DEBUG_MEM 0
......@@ -102,11 +102,14 @@ typedef struct
bool ForceIntegration;
char *RootDir; // Absolute
char *RootURL;
char *ProjectID;
char *BaseDir; // Absolute
char *CSSDir; // Relative to RootDir and RootURL
char *ImagesDir; // Relative to RootDir and RootURL
char *JSDir; // Relative to RootDir and RootURL
char *ProjectID;
char *BaseDir; // Absolute
char *BaseURL;
char *IndexLocation; // Relative to BaseDir and BaseURL
char *PlayerLocation; // Relative to BaseDir and BaseURL
char *TemplateIndexLocation; // Relative to RootDir and RootURL
char *TemplatePlayerLocation; // Relative to RootDir and RootURL
char *Theme;
......@@ -115,7 +118,7 @@ typedef struct
char *OutLocation;
char *OutIntegratedLocation;
char *ProjectDir;
char *URLPrefix; /* NOTE(matt): This will become a full blown customisable output URL.
char *PlayerURLPrefix; /* NOTE(matt): This will become a full blown customisable output URL.
For now it simply replaces the ProjectID */
} config;
......@@ -160,7 +163,9 @@ enum
// Anywhere
TAG_PROJECT,
TAG_TITLE
TAG_TITLE,
TAG_URL,
TAG_VIDEO_ID,
} template_tags;
typedef struct
......@@ -177,6 +182,8 @@ tag Tags[] = {
{ TAG_SCRIPT, "__CINERA_SCRIPT__" },
{ TAG_PROJECT, "__CINERA_PROJECT__" },
{ TAG_TITLE, "__CINERA_TITLE__" },
{ TAG_URL, "__CINERA_URL__" },
{ TAG_VIDEO_ID, "__CINERA_VIDEO_ID__" },
};
typedef struct
......@@ -209,8 +216,11 @@ typedef struct
buffer Menus;
buffer Player;
buffer ScriptPlayer;
char Title[256];
char ProjectName[32];
char Title[256];
char URLIndex[2048];
char URLPlayer[2048];
char VideoID[16];
} buffers;
// TODO(matt): Consider putting the ref_info and quote_info into linked lists on the heap, just to avoid all the hardcoded sizes
......@@ -908,7 +918,7 @@ enum
void
ConstructURLPrefix(buffer *URLPrefix, int IncludeType, int PageType)
{
ClaimBuffer(URLPrefix, "URLPrefix", 1024);
RewindBuffer(URLPrefix);
if(StringsDiffer(Config.RootURL, ""))
{
URLPrefix->Ptr += CopyString(URLPrefix->Ptr, "%s/", Config.RootURL);
......@@ -1002,6 +1012,7 @@ SearchCredentials(buffer *CreditsMenu, bool *HasCreditsMenu, char *Person, char
if(*Credentials[CredentialIndex].SupportIcon && *Credentials[CredentialIndex].SupportURL)
{
buffer URLPrefix;
ClaimBuffer(&URLPrefix, "URLPrefix", 1024);
ConstructURLPrefix(&URLPrefix, INCLUDE_Images, PAGE_INDEX);
CopyStringToBuffer(CreditsMenu,
" <a class=\"support\" href=\"%s\" target=\"_blank\"><div class=\"support_icon\" style=\"background-image: url(%s%s);\"></div></a>\n",
......@@ -1650,39 +1661,49 @@ PrintUsage(char *BinaryLocation, config *DefaultConfig)
" Paths: \n"
" -r <root directory>\n"
" Override default root directory (\"%s\")\n"
" -u <root URL>\n"
" -R <root URL>\n"
" Override default root URL (\"%s\")\n"
" -b <base output directory>\n"
" Override project's default base output directory (\"%s\")\n"
" -c <CSS directory path>\n"
" Override default CSS directory (\"%s\"), relative to root\n"
" -i <images directory path>\n"
" Override default images directory (\"%s\"), relative to root\n"
" -j <JS directory path>\n"
" Override default JS directory (\"%s\"), relative to root\n"
"\n"
" -b <base output directory>\n"
" Override project's default base output directory (\"%s\")\n"
" -B <base URL>\n"
" Override default base URL (\"%s\")\n"
" NOTE: This must be set, if -n or -a are used\n"
" -n <index location>\n"
" Override default index location (\"%s\"), relative to base\n"
" -a <player location>\n"
" Override default player location (\"%s\"), relative to base\n"
"\n"
" -t <player template location>\n"
" Override default player template location (\"%s\"), relative to root\n"
" and automatically enable integration\n"
" Override default player template location (\"%s\"), either\n"
" absolute or relative to root, and enable integration\n"
" -x <index template location>\n"
" Override default index template location (\"%s\"), relative to root\n"
" and automatically enable integration\n"
" Override default index template location (\"%s\"), either\n"
" absolute or relative to root, and enable integration\n"
"\n"
" -o <output location>\n"
" Override default output player location for SINGLE_EDITION (\"%s\")\n"
" -d <project directory>\n"
" Override default project directory (\"%s\")\n"
" -o <output location>\n"
" Override default output player location for SINGLE_EDITION (\"%s\")\n"
"\n"
" -f\n"
" Force integration with an incomplete template\n"
" -p <project ID>\n"
" Set the project ID, corresponding to the \"project\" field in the HMML files\n"
" -s <style>\n"
" Set the style / theme, corresponding to a cinera__*.css file\n"
" This is equal to the \"project\" field in the HMML files by default\n"
" -l <n>\n"
" Override default log level (%d), where n is from 0 (terse) to 7 (verbose)\n"
" -m <default medium>\n"
" Override default default medium (\"%s\")\n"
" -f\n"
" Force integration with an incomplete template\n"
"\n"
" -l <n>\n"
" Override default log level (%d), where n is from 0 (terse) to 7 (verbose)\n"
" -U <seconds>\n"
" Override default update interval (\"%d\")\n"
//" -c config location\n"
......@@ -1698,22 +1719,29 @@ PrintUsage(char *BinaryLocation, config *DefaultConfig)
"\n"
"Template:\n"
" A complete index template shall contain exactly one each of the following tags:\n"
" <!-- __CINERA_INCLUDES__ --> - to put inside your own <head></head>\n"
" <!-- __CINERA_INCLUDES__ -->\n"
" to put inside your own <head></head>\n"
" <!-- __CINERA_INDEX__ -->\n"
"\n"
" A complete player template shall contain exactly one each of the following tags:\n"
" <!-- __CINERA_INCLUDES__ --> - to put inside your own <head></head>\n"
" <!-- __CINERA_INCLUDES__ -->\n"
" to put inside your own <head></head>\n"
" <!-- __CINERA_MENUS__ -->\n"
" <!-- __CINERA_PLAYER__ -->\n"
" <!-- __CINERA_SCRIPT__ --> (must come after <!-- __CINERA_PLAYER__ -->)\n"
" <!-- __CINERA_SCRIPT__ -->\n"
" must come after <!-- __CINERA_MENUS__ --> and <!-- __CINERA_PLAYER__ -->\n"
"\n"
" Other available tags:\n"
" <!-- __CINERA_PROJECT__ -->\n"
" <!-- __CINERA_TITLE__ -->\n"
" <!-- __CINERA_URL__ -->\n"
" Only really usable if Base URL is set (-B)\n"
" <!-- __CINERA_VIDEO_ID__ -->\n"
" Intended only for your player template\n"
"\n"
"HMML Specification:\n"
" https://git.handmade.network/Annotation-Pushers/Annotation-System/wikis/hmmlspec\n",
BinaryLocation, DefaultConfig->RootDir, DefaultConfig->RootURL, DefaultConfig->BaseDir, DefaultConfig->CSSDir, DefaultConfig->ImagesDir, DefaultConfig->JSDir, DefaultConfig->TemplatePlayerLocation, DefaultConfig->TemplateIndexLocation, DefaultConfig->OutLocation, DefaultConfig->ProjectDir, DefaultConfig->LogLevel, DefaultConfig->DefaultMedium, DefaultConfig->UpdateInterval);
BinaryLocation, DefaultConfig->RootDir, DefaultConfig->RootURL, DefaultConfig->CSSDir, DefaultConfig->ImagesDir, DefaultConfig->JSDir, DefaultConfig->BaseDir, DefaultConfig->BaseURL, DefaultConfig->IndexLocation, DefaultConfig->PlayerLocation, DefaultConfig->TemplatePlayerLocation, DefaultConfig->TemplateIndexLocation, DefaultConfig->ProjectDir, DefaultConfig->OutLocation, DefaultConfig->DefaultMedium, DefaultConfig->LogLevel, DefaultConfig->UpdateInterval);
}
void
......@@ -1852,6 +1880,20 @@ Here:
DepartComment(&(*Template)->Buffer);
Previous = (*Template)->Buffer.Ptr;
goto Here;
case TAG_URL:
(*Template)->Metadata.Tag[(*Template)->Metadata.TagCount].Offset = CommentStart - Previous;
(*Template)->Metadata.Tag[(*Template)->Metadata.TagCount].TagCode = TAG_URL;
(*Template)->Metadata.TagCount++;
DepartComment(&(*Template)->Buffer);
Previous = (*Template)->Buffer.Ptr;
goto Here;
case TAG_VIDEO_ID:
(*Template)->Metadata.Tag[(*Template)->Metadata.TagCount].Offset = CommentStart - Previous;
(*Template)->Metadata.Tag[(*Template)->Metadata.TagCount].TagCode = TAG_VIDEO_ID;
(*Template)->Metadata.TagCount++;
DepartComment(&(*Template)->Buffer);
Previous = (*Template)->Buffer.Ptr;
goto Here;
};
}
}
......@@ -1895,6 +1937,46 @@ Here:
return RC_SUCCESS;
}
void
ConstructIndexURL(buffer *IndexURL)
{
RewindBuffer(IndexURL);
if(StringsDiffer(Config.BaseURL, ""))
{
CopyStringToBuffer(IndexURL, "%s/", Config.BaseURL);
if(StringsDiffer(Config.IndexLocation, ""))
{
CopyStringToBuffer(IndexURL, "%s/", Config.IndexLocation);
}
}
}
void
ConstructPlayerURL(buffer *PlayerURL, char *BaseFilename)
{
RewindBuffer(PlayerURL);
if(StringsDiffer(Config.BaseURL, ""))
{
CopyStringToBuffer(PlayerURL, "%s/", Config.BaseURL);
if(StringsDiffer(Config.PlayerLocation, ""))
{
CopyStringToBuffer(PlayerURL, "%s/", Config.PlayerLocation);
}
}
if(StringsDiffer(BaseFilename, ""))
{
if(StringsDiffer(Config.PlayerURLPrefix, ""))
{
char *Ptr = BaseFilename + StringLength(Config.ProjectID);
CopyStringToBuffer(PlayerURL, "%s%s", Config.PlayerURLPrefix, Ptr);
}
else
{
CopyStringToBuffer(PlayerURL, "%s", BaseFilename);
}
}
}
int
HMMLToBuffers(buffers *CollationBuffers, char *Filename)
{
......@@ -1928,9 +2010,7 @@ HMMLToBuffers(buffers *CollationBuffers, char *Filename)
if(HMML.well_formed)
{
CopyString(CollationBuffers->Title, HMML.metadata.title);
int ProjectIndex;
for(ProjectIndex = 0; ProjectIndex < ArrayCount(ProjectInfo); ++ProjectIndex)
for(int ProjectIndex = 0; ProjectIndex < ArrayCount(ProjectInfo); ++ProjectIndex)
{
if(!StringsDiffer(ProjectInfo[ProjectIndex].ProjectID, Config.ProjectID))
{
......@@ -1938,6 +2018,20 @@ HMMLToBuffers(buffers *CollationBuffers, char *Filename)
break;
}
}
CopyString(CollationBuffers->Title, HMML.metadata.title);
buffer URLPlayer;
ClaimBuffer(&URLPlayer, "URLPlayer", 2048);
char *Ptr = Filename;
Ptr += (StringLength(Filename) - StringLength(".hmml"));
if(!(StringsDiffer(Ptr, ".hmml")))
{
*Ptr = '\0';
ConstructPlayerURL(&URLPlayer, Filename);
*Ptr = '.';
}
CopyString(CollationBuffers->URLPlayer, URLPlayer.Location);
CopyString(CollationBuffers->VideoID, HMML.metadata.id);
#if DEBUG
printf(
......@@ -2650,6 +2744,7 @@ AppendedIdentifier:
" </script>\n");
buffer URLPrefix;
ClaimBuffer(&URLPrefix, "URLPrefix", 1024);
ConstructURLPrefix(&URLPrefix, INCLUDE_Images, PAGE_INDEX);
CopyStringToBuffer(&FilterMenu,
" <div class=\"menu filter\">\n"
......@@ -3002,7 +3097,14 @@ AppendedIdentifier:
// TODO(matt): Maybe do something about indentation levels
buffer URLIndex;
ClaimBuffer(&URLIndex, "URLPlayer", 2048);
ConstructIndexURL(&URLIndex);
CopyString(CollationBuffers->URLIndex, URLIndex.Location);
DeclaimBuffer(&URLIndex);
buffer URLPrefix;
ClaimBuffer(&URLPrefix, "URLPrefix", 1024);
ConstructURLPrefix(&URLPrefix, INCLUDE_CSS, PAGE_INDEX);
CopyStringToBuffer(&CollationBuffers->IncludesIndex,
"<link rel=\"stylesheet\" type=\"text/css\" href=\"%scinera.css\">\n"
......@@ -3019,7 +3121,6 @@ AppendedIdentifier:
CINERA_APP_VERSION.Major,
CINERA_APP_VERSION.Minor,
CINERA_APP_VERSION.Patch);
DeclaimBuffer(&URLPrefix);
ConstructURLPrefix(&URLPrefix, INCLUDE_CSS, PAGE_PLAYER);
CopyStringToBuffer(&CollationBuffers->IncludesPlayer,
......@@ -3036,7 +3137,6 @@ AppendedIdentifier:
CINERA_APP_VERSION.Major,
CINERA_APP_VERSION.Minor,
CINERA_APP_VERSION.Patch);
DeclaimBuffer(&URLPrefix);
if(Topics.Count || Media.Count)
{
......@@ -3157,11 +3257,17 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i
switch(Template->Metadata.Tag[i].TagCode)
{
case TAG_PROJECT:
CopyStringToBuffer(&Output, CollationBuffers->ProjectName);
break;
case TAG_TITLE:
CopyStringToBuffer(&Output, CollationBuffers->Title);
break;
case TAG_PROJECT:
CopyStringToBuffer(&Output, CollationBuffers->ProjectName);
case TAG_URL:
CopyStringToBuffer(&Output, PageType == PAGE_PLAYER ? CollationBuffers->URLPlayer : CollationBuffers->URLIndex);
break;
case TAG_VIDEO_ID:
CopyStringToBuffer(&Output, CollationBuffers->VideoID);
break;
case TAG_INDEX:
CopyBuffer(&Output, &CollationBuffers->Index);
......@@ -3399,6 +3505,8 @@ typedef struct
version AppVersion;
version HMMLVersion;
unsigned int EntryCount;
char IndexLocation[32];
char PlayerLocation[32];
} index_header;
typedef struct
......@@ -3526,6 +3634,9 @@ InsertIntoIndex(buffers *CollationBuffers, char *BaseFilename)
Index.Header.HMMLVersion.Major = hmml_version.Major;
Index.Header.HMMLVersion.Minor = hmml_version.Minor;
Index.Header.HMMLVersion.Patch = hmml_version.Patch;
CopyString(Index.Header.IndexLocation, Config.IndexLocation);
CopyString(Index.Header.PlayerLocation, Config.PlayerLocation);
DIR *OutputDirectoryHandle;
if(!(OutputDirectoryHandle = opendir(Config.BaseDir)))
{
......@@ -3608,6 +3719,37 @@ InsertIntoIndex(buffers *CollationBuffers, char *BaseFilename)
return RC_SUCCESS;
}
void
ConstructDirectoryPath(buffer *DirectoryPath, int PageType, char *PageLocation, char *BaseFilename)
{
RewindBuffer(DirectoryPath);
CopyStringToBuffer(DirectoryPath, Config.BaseDir);
switch(PageType)
{
case PAGE_INDEX:
if(StringsDiffer(PageLocation, ""))
{
CopyStringToBuffer(DirectoryPath, "/%s", PageLocation);
}
break;
case PAGE_PLAYER:
if(StringsDiffer(PageLocation, ""))
{
CopyStringToBuffer(DirectoryPath, "/%s", PageLocation);
}
if(StringsDiffer(Config.PlayerURLPrefix, ""))
{
char *Ptr = BaseFilename + StringLength(Config.ProjectID);
CopyStringToBuffer(DirectoryPath, "/%s%s", Config.PlayerURLPrefix, Ptr);
}
else
{
CopyStringToBuffer(DirectoryPath, "/%s", BaseFilename);
}
break;
}
}
int
DeleteFromIndex(char *BaseFilename)
{
......@@ -3668,6 +3810,14 @@ DeleteFromIndex(char *BaseFilename)
{
if(Index.Header.EntryCount == 0)
{
buffer IndexDirectory;
ClaimBuffer(&IndexDirectory, "IndexDirectory", 1024);
ConstructDirectoryPath(&IndexDirectory, PAGE_INDEX, Config.IndexLocation, "");
char IndexPagePath[1024];
CopyString(IndexPagePath, "%s/index.html", IndexDirectory.Location);
remove(IndexPagePath);
remove(IndexDirectory.Location);
DeclaimBuffer(&IndexDirectory);
remove(Index.Metadata.Path);
remove(Index.File.Path);
}
......@@ -3756,17 +3906,26 @@ IndexToBuffer(buffers *CollationBuffers)
ClaimBuffer(&URLPrefix, "URLPrefix", 1024);
ConstructURLPrefix(&URLPrefix, INCLUDE_JS, PAGE_INDEX);
buffer PlayerURL;
ClaimBuffer(&PlayerURL, "PlayerURL", 4096);
ConstructPlayerURL(&PlayerURL, "");
char Script[512 + StringLength(URLPrefix.Location) + (StringLength(Config.ProjectID) * 2)];
CopyString(Script, " </dl>\n"
" <script type=\"text/javascript\">\n"
" var projectID = \"%s\";\n"
" var theme = \"%s\";\n"
" var baseURL = \"%s\";\n"
" var playerLocation = \"%s\";\n"
" var outputURLPrefix = \"%s\";\n"
// TODO(matt): PlayerURL
" </script>\n"
" <script type=\"text/javascript\" src=\"%scinera_search.js\"></script>\n",
Config.ProjectID,
StringsDiffer(Config.Theme, "") ? Config.Theme : Config.ProjectID,
StringsDiffer(Config.URLPrefix, "") ? Config.URLPrefix : Config.ProjectID,
Config.BaseURL,
Config.PlayerLocation,
StringsDiffer(Config.PlayerURLPrefix, "") ? Config.PlayerURLPrefix : Config.ProjectID,
URLPrefix.Location);
DeclaimBuffer(&URLPrefix);
......@@ -3802,22 +3961,13 @@ IndexToBuffer(buffers *CollationBuffers)
CopyStringNoFormatT(Title, Index.File.Buffer.Ptr, '\n');
Title[StringLength(Title) - 1] = '\0';
char BaseFilename[255];
if(StringsDiffer(Config.URLPrefix, ""))
{
char *Ptr = This.BaseFilename + StringLength(Config.ProjectID);
CopyString(BaseFilename, "%s%s", Config.URLPrefix, Ptr);
}
else
{
CopyString(BaseFilename, "%s", This.BaseFilename);
}
ConstructPlayerURL(&PlayerURL, This.BaseFilename);
if(StringsDiffer(ProjectInfo[ProjectIndex].Unit, ""))
{
CopyStringToBuffer(&CollationBuffers->Index,
" <dt>\n"
" <a href=\"%s\">", BaseFilename);
" <a href=\"%s\">", PlayerURL.Location);
char Text[1024]; // NOTE(matt): Surely this will be big enough
CopyString(Text, "%s %s: %s",
......@@ -3837,7 +3987,7 @@ IndexToBuffer(buffers *CollationBuffers)
" <dt>\n"
" <a href=\"%s\">%s</a>\n"
" </dt>\n",
BaseFilename,
PlayerURL.Location,
Title);
}
......@@ -3846,6 +3996,8 @@ IndexToBuffer(buffers *CollationBuffers)
Index.File.Buffer.Ptr = IndexEntryStart;
}
DeclaimBuffer(&PlayerURL);
CopyStringToBuffer(&CollationBuffers->Index, Script);
FreeBuffer(&Index.Metadata.Buffer);
......@@ -3857,34 +4009,60 @@ IndexToBuffer(buffers *CollationBuffers)
}
}
int
GeneratePlayerPage(buffers *CollationBuffers, template *PlayerTemplate, char *BaseFilename)
char *
StripTrailingSlash(char *String) // NOTE(matt): For absolute paths
{
char OutputDir[256];
if(StringsDiffer(Config.URLPrefix, ""))
int Length = StringLength(String);
while(Length > 0 && String[Length - 1] == '/')
{
char *Ptr = BaseFilename + StringLength(Config.ProjectID);
CopyString(OutputDir, "%s/%s%s", Config.BaseDir, Config.URLPrefix, Ptr);
String[Length - 1] = '\0';
--Length;
}
else
return String;
}
char *
StripSurroundingSlashes(char *String) // NOTE(matt): For relative paths
{
int Length = StringLength(String);
if(Length > 0)
{
CopyString(OutputDir, "%s/%s", Config.BaseDir, BaseFilename);
while((String[0]) == '/')
{
++String;
--Length;
}
while(String[Length - 1] == '/')
{
String[Length - 1] = '\0';
--Length;
}
}
char PlayerPagePath[256];
CopyString(PlayerPagePath, "%s/index.html", OutputDir);
return String;
}
int
GeneratePlayerPage(buffers *CollationBuffers, template *PlayerTemplate, char *BaseFilename)
{
buffer OutputDirectoryPath;
ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", 1024);
ConstructDirectoryPath(&OutputDirectoryPath, PAGE_PLAYER, Config.PlayerLocation, BaseFilename);
DIR *OutputDirectoryHandle;
if(!(OutputDirectoryHandle = opendir(OutputDir)))
if(!(OutputDirectoryHandle = opendir(OutputDirectoryPath.Location))) // TODO(matt): open()
{
if(MakeDir(OutputDir) == RC_ERROR_DIRECTORY)
if(MakeDir(OutputDirectoryPath.Location) == RC_ERROR_DIRECTORY)
{
LogError(LOG_ERROR, "Unable to create directory %s: %s", OutputDir, strerror(errno));
fprintf(stderr, "Unable to create directory %s: %s\n", OutputDir, strerror(errno));
LogError(LOG_ERROR, "Unable to create directory %s: %s", OutputDirectoryPath.Location, strerror(errno));
fprintf(stderr, "Unable to create directory %s: %s\n", OutputDirectoryPath.Location, strerror(errno));
return RC_ERROR_DIRECTORY;
};
}
closedir(OutputDirectoryHandle);
char PlayerPagePath[1024];
CopyString(PlayerPagePath, "%s/index.html", OutputDirectoryPath.Location);
DeclaimBuffer(&OutputDirectoryPath);
BuffersToHTML(CollationBuffers, PlayerTemplate, PlayerPagePath, PAGE_PLAYER);
return RC_SUCCESS;
}
......@@ -3892,8 +4070,25 @@ GeneratePlayerPage(buffers *CollationBuffers, template *PlayerTemplate, char *Ba
int
GenerateIndexPage(buffers *CollationBuffers, template *IndexTemplate)
{
char IndexPagePath[256];
CopyString(IndexPagePath, "%s/index.html", Config.BaseDir);
buffer OutputDirectoryPath;
ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", 1024);
ConstructDirectoryPath(&OutputDirectoryPath, PAGE_INDEX, Config.IndexLocation, 0);
DIR *OutputDirectoryHandle;
if(!(OutputDirectoryHandle = opendir(OutputDirectoryPath.Location))) // TODO(matt): open()
{
if(MakeDir(OutputDirectoryPath.Location) == RC_ERROR_DIRECTORY)
{
LogError(LOG_ERROR, "Unable to create directory %s: %s", OutputDirectoryPath.Location, strerror(errno));
fprintf(stderr, "Unable to create directory %s: %s\n", OutputDirectoryPath.Location, strerror(errno));
return RC_ERROR_DIRECTORY;
};
}
closedir(OutputDirectoryHandle);
char IndexPagePath[1024];
CopyString(IndexPagePath, "%s/index.html", OutputDirectoryPath.Location);
DeclaimBuffer(&OutputDirectoryPath);
IndexToBuffer(CollationBuffers);
BuffersToHTML(CollationBuffers, IndexTemplate, IndexPagePath, PAGE_INDEX);
FreeBuffer(&CollationBuffers->Index);
......@@ -3901,25 +4096,18 @@ GenerateIndexPage(buffers *CollationBuffers, template *IndexTemplate)
}
int
DeletePlayerPageFromFilesystem(char *BaseFilename)
DeletePlayerPageFromFilesystem(char *BaseFilename, char *PlayerLocation, bool Relocating)
{
// NOTE(matt): Once we have the notion of an output filename format, we'll need to use that here
char PlayerDirPath[256];
if(StringsDiffer(Config.URLPrefix, ""))
{
char *Ptr = BaseFilename + StringLength(Config.ProjectID);
CopyString(PlayerDirPath, "%s/%s%s", Config.BaseDir, Config.URLPrefix, Ptr);
}
else
{
CopyString(PlayerDirPath, "%s/%s", Config.BaseDir, BaseFilename);
}
buffer OutputDirectoryPath;
ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", 1024);
ConstructDirectoryPath(&OutputDirectoryPath, PAGE_PLAYER, PlayerLocation, BaseFilename);
DIR *PlayerDir;
if((PlayerDir = opendir(PlayerDirPath))) // There is a directory for the Player, which there probably should be if not for manual intervention
if((PlayerDir = opendir(OutputDirectoryPath.Location))) // There is a directory for the Player, which there probably should be if not for manual intervention
{
char PlayerPagePath[256];
CopyString(PlayerPagePath, "%s/index.html", PlayerDirPath);
CopyString(PlayerPagePath, "%s/index.html", OutputDirectoryPath.Location);
FILE *PlayerPage;
if((PlayerPage = fopen(PlayerPagePath, "r")))
{
......@@ -3928,17 +4116,22 @@ DeletePlayerPageFromFilesystem(char *BaseFilename)
}
closedir(PlayerDir);
if((remove(PlayerDirPath) == -1))
if((remove(OutputDirectoryPath.Location) == -1))
{
LogError(LOG_NOTICE, "Mostly deleted %s. Unable to remove directory %s: %s", BaseFilename, PlayerDirPath, strerror(errno));
fprintf(stderr, "\e[1;30mMostly deleted\e[0m %s. \e[1;31mUnable to remove directory\e[0m %s: %s", BaseFilename, PlayerDirPath, strerror(errno));
LogError(LOG_NOTICE, "Mostly deleted %s. Unable to remove directory %s: %s", BaseFilename, OutputDirectoryPath.Location, strerror(errno));
fprintf(stderr, "\e[1;30mMostly deleted\e[0m %s. \e[1;31mUnable to remove directory\e[0m %s: %s", BaseFilename, OutputDirectoryPath.Location, strerror(errno));
}
else
{
LogError(LOG_INFORMATIONAL, "Deleted %s", BaseFilename);
fprintf(stderr, "\e[1;30mDeleted\e[0m %s\n", BaseFilename);
if(!Relocating)
{
LogError(LOG_INFORMATIONAL, "Deleted %s", BaseFilename);
fprintf(stderr, "\e[1;30mDeleted\e[0m %s\n", BaseFilename);
}
}
}
DeclaimBuffer(&OutputDirectoryPath);
return RC_SUCCESS;
}
......@@ -3947,7 +4140,7 @@ DeleteEntry(char *BaseFilename)
{
if(DeleteFromIndex(BaseFilename) == RC_SUCCESS)
{
DeletePlayerPageFromFilesystem(BaseFilename);
DeletePlayerPageFromFilesystem(BaseFilename, Config.PlayerLocation, FALSE);
}
}
......@@ -4006,6 +4199,111 @@ MonitorDirectory(buffers *CollationBuffers, template *IndexTemplate, template *P
return RC_NOOP;
}
int
RemoveDirectory(char *Path)
{
if((remove(Path) == -1))
{
LogError(LOG_NOTICE, "Unable to remove directory %s: %s", Path, strerror(errno));
fprintf(stderr, "\e[1;30mUnable to remove directory\e[0m %s: %s", Path, strerror(errno));
return RC_ERROR_DIRECTORY;
}
else
{
LogError(LOG_INFORMATIONAL, "Deleted %s", Path);
//fprintf(stderr, "\e[1;30mDeleted\e[0m %s\n", Path);
return RC_SUCCESS;
}
}
int
RemoveDirectoryRecursively(char *Path)
{
if(RemoveDirectory(Path) == RC_ERROR_DIRECTORY) { return RC_ERROR_DIRECTORY; }
char *Ptr = Path + StringLength(Path) - 1;
while(Ptr > Path)
{
if(*Ptr == '/')
{
*Ptr = '\0';
if(RemoveDirectory(Path) == RC_ERROR_DIRECTORY) { return RC_ERROR_DIRECTORY; }
}
--Ptr;
}
return RC_SUCCESS;
}
void
Clear(char *String, int Size)
{
for(int i = 0; i < Size; ++i)
{
String[i] = 0;
}
}
int
UpgradeDB(index *Index)
{
int DBVersion = Index->Header.DBVersion;
switch(DBVersion)
{
case 1:
{
typedef struct
{
unsigned int DBVersion;
version AppVersion;
version HMMLVersion;
unsigned int EntryCount;
} index_header1;
typedef struct
{
int Size;
char BaseFilename[32];
} index_metadata1;
typedef struct
{
file_buffer File;
file_buffer Metadata;
index_header1 Header;
index_metadata1 Entry;
} index1;
index1 OldIndex = { 0 };
OldIndex.Header = *(index_header1 *)Index->Metadata.Buffer.Ptr;
Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(OldIndex.Header);
Index->Header.DBVersion = CINERA_DB_VERSION;
Index->Header.AppVersion = CINERA_APP_VERSION;