835 lines
25 KiB
C++
835 lines
25 KiB
C++
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
|
|
#include <scriptpp/scrvar.hpp>
|
|
#include <scriptpp/scrvect.hpp>
|
|
#include <scriptpp/cmd.hpp>
|
|
|
|
#include "database.hpp"
|
|
#include "forumgen.hpp"
|
|
#include "arrindex.hpp"
|
|
#include "errlist.hpp"
|
|
#include "fileops.hpp"
|
|
#include "fpublish.hpp"
|
|
|
|
#include "generate.hpp"
|
|
|
|
// * architecture decision *
|
|
// PLEASE REMEMBER!!!
|
|
// all substitutions must (yes, MUST) be done within the database object,
|
|
// because (!) variable names are a part of the database format!
|
|
|
|
|
|
|
|
|
|
static FILE* start_file(const ScriptVariable &fname,
|
|
int chmod_val,
|
|
const ScriptVariable &diag_id,
|
|
ErrorList **err)
|
|
{
|
|
make_directory_path(fname.c_str(), 1);
|
|
FILE* f = fopen(fname.c_str(), "w");
|
|
if(!f) {
|
|
ScriptVariable s(63, "Can't create file %s for %s [%s], skipping",
|
|
fname.c_str(), diag_id.c_str(), strerror(errno));
|
|
ErrorList::AddError(err, s);
|
|
return 0;
|
|
}
|
|
if(chmod_val)
|
|
fchmod(fileno(f), chmod_val);
|
|
return f;
|
|
}
|
|
|
|
static bool output_file(const ScriptVariable &fname,
|
|
int chmod_val,
|
|
const ScriptVariable &diag_id,
|
|
ErrorList **err,
|
|
const char *s1, const char *s2 = 0, const char *s3 = 0)
|
|
{
|
|
FILE *f = start_file(fname, chmod_val, diag_id, err);
|
|
if(!f)
|
|
return false;
|
|
fputs(s1, f);
|
|
if(s2)
|
|
fputs(s2, f);
|
|
if(s3)
|
|
fputs(s3, f);
|
|
fclose(f);
|
|
return true;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Genfiles
|
|
// defined by ''genfile'' ini section, generated outside of the doctree
|
|
//
|
|
|
|
void generate_genfile(const ScriptVariable &id, Database& database,
|
|
ErrorList **err)
|
|
{
|
|
ScriptVariable path, content;
|
|
int chmod_val;
|
|
if(!database.BuildGenericFile(id, path, chmod_val, content)) {
|
|
ScriptVariable s(63, "Skipping generic file %s, check configs",
|
|
id.c_str());
|
|
ErrorList::AddError(err, s);
|
|
return;
|
|
}
|
|
ScriptVariable diag_id("-");
|
|
output_file(path, chmod_val, diag_id, err, content.c_str());
|
|
}
|
|
|
|
void generate_all_genfiles(Database& database, ErrorList **err)
|
|
{
|
|
ScriptVector gfnames;
|
|
database.GetGenfiles(gfnames);
|
|
int i;
|
|
for(i = 0; i < gfnames.Length(); i++) {
|
|
generate_genfile(gfnames[i], database, err);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Pages
|
|
// defined by ''page'' ini section, which includes all needed data
|
|
//
|
|
// pages can NOT provide a comment forum
|
|
//
|
|
|
|
bool generate_page(const ScriptVariable& id, Database& database,
|
|
ErrorList **err)
|
|
{
|
|
ScriptVariable page_filename;
|
|
page_filename = database.GetPageFilename(id);
|
|
if(page_filename.IsInvalid() || page_filename == "")
|
|
return true; /* suppressed, but it's not an error */
|
|
ScriptVariable s = database.BuildPage(id);
|
|
if(s.IsInvalid()) {
|
|
ScriptVariable s(63, "Page %s not configured", id.c_str());
|
|
ErrorList::AddError(err, s);
|
|
return false;
|
|
}
|
|
int chmod_val = database.GetPageChmod(id);
|
|
ScriptVariable diag_id("page ");
|
|
diag_id += id;
|
|
|
|
return output_file(page_filename, chmod_val, diag_id, err, s.c_str());
|
|
}
|
|
|
|
void generate_all_pages(Database& database, ErrorList **errlst)
|
|
{
|
|
ScriptVector pagenames;
|
|
database.GetPages(pagenames);
|
|
int i;
|
|
for(i = 0; i < pagenames.Length(); i++) {
|
|
generate_page(pagenames[i], database, errlst);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Lists
|
|
// defined by ''list'' ini section,
|
|
// represented by ini section group named within the pagelist section
|
|
//
|
|
|
|
static void output_list_head(FILE *listf,
|
|
const ListData &listdata,
|
|
Database &database,
|
|
ErrorList **err)
|
|
{
|
|
ScriptVariable s = database.BuildListHead(listdata);
|
|
fputs(s.c_str(), listf);
|
|
}
|
|
|
|
static void output_list_tail(FILE *listf, const ListData &listdata,
|
|
Database &database,
|
|
ErrorList **err)
|
|
{
|
|
ScriptVariable s = database.BuildListTail(listdata);
|
|
fputs(s.c_str(), listf);
|
|
}
|
|
|
|
static void output_list_item(FILE *listf,
|
|
const ListData &listdata,
|
|
const ListItemData &itemdata,
|
|
Database &database,
|
|
ErrorList **err)
|
|
{
|
|
ScriptVariable s = database.BuildListItem(listdata, itemdata);
|
|
fputs(s.c_str(), listf);
|
|
}
|
|
|
|
static void generate_list_item_page(const ListData &listdata,
|
|
const ListItemData &itemdata,
|
|
Database &database,
|
|
ErrorList **err)
|
|
{
|
|
ScriptVariable diag_id = listdata.id + "::" + itemdata.item_id;
|
|
|
|
ScriptVariable mainpg, tail;
|
|
ForumGenerator *fg;
|
|
database.BuildListItemPage(listdata, itemdata, mainpg, tail, &fg);
|
|
|
|
int pgcnt;
|
|
bool reverse;
|
|
bool multipage_by_comments = false;
|
|
if(fg) {
|
|
bool ok = fg->GetArrayInfo(pgcnt, reverse);
|
|
if(ok && pgcnt > 1)
|
|
multipage_by_comments = true;
|
|
}
|
|
|
|
if(!multipage_by_comments) {
|
|
// very simple case
|
|
ArrayData *save = database.InstallArrayData(0);
|
|
ScriptVariable fname =
|
|
database.GetListItemFilename(listdata.id, itemdata.item_id, 0);
|
|
ScriptVariable cmts("");
|
|
if(fg)
|
|
cmts = fg->Build();
|
|
output_file(fname, 0, diag_id, err,
|
|
mainpg.c_str(), cmts.c_str(), tail.c_str());
|
|
database.InstallArrayData(save);
|
|
if(fg)
|
|
delete fg;
|
|
return;
|
|
}
|
|
|
|
ScriptVariable href_main =
|
|
database.GetListItemHref(listdata.id, itemdata.item_id, 0);
|
|
|
|
////////////////////////////
|
|
ArrayData arrayd;
|
|
arrayd.page_count = pgcnt;
|
|
arrayd.reverse = reverse;
|
|
arrayd.href_array[0] = href_main;
|
|
int i;
|
|
for(i = 1; i <= pgcnt; i++) {
|
|
int idxval = fg->GetPageIdxValue(i);
|
|
arrayd.href_array[i] =
|
|
database.GetListItemHref(listdata.id, itemdata.item_id, idxval);
|
|
}
|
|
if(reverse) {
|
|
arrayd.href_last = href_main;
|
|
} else {
|
|
arrayd.href_first = href_main;
|
|
arrayd.href_array[1] = href_main;
|
|
}
|
|
arrayd.current_page = -1;
|
|
ArrayData *ad_save = database.InstallArrayData(&arrayd);
|
|
////////////////////////////
|
|
|
|
fg->SetMainHref(href_main);
|
|
|
|
bool ok;
|
|
do {
|
|
int idxf, idx_array;
|
|
fg->GetIndices(idxf, idx_array);
|
|
if(idx_array < 0 || idx_array > pgcnt)
|
|
idx_array = 0;
|
|
arrayd.current_page = idx_array;
|
|
fg->SetHref(arrayd.href_array[idx_array]);
|
|
ScriptVariable compage = fg->Build();
|
|
ScriptVariable fname =
|
|
database.GetListItemFilename(listdata.id, itemdata.item_id, idxf);
|
|
output_file(fname, 0, diag_id, err,
|
|
mainpg.c_str(), compage.c_str(), tail.c_str());
|
|
ok = fg->Next();
|
|
} while(ok);
|
|
|
|
ScriptVariable cmap = fg->MakeCommentMap();
|
|
delete fg;
|
|
|
|
database.InstallArrayData(ad_save);
|
|
|
|
if(cmap.IsValid() && cmap != "") {
|
|
ScriptVariable cmap_fname =
|
|
database.GetListItemCommentmapFname(listdata.id, itemdata.item_id);
|
|
if(cmap_fname.IsValid())
|
|
output_file(cmap_fname, 0, diag_id, err, cmap.c_str());
|
|
}
|
|
}
|
|
|
|
static void generate_all_list_item_pages(const ListData &list_data,
|
|
Database& database, ErrorList **err)
|
|
{
|
|
int max = list_data.items.Length();
|
|
int i;
|
|
for(i = 0; i < max; i++) {
|
|
ListItemData itemdata;
|
|
if(!database.GetListItemData(list_data, i, itemdata)) {
|
|
ErrorList::AddError(err, ScriptVariable("No data for ") +
|
|
list_data.id + "/" + list_data.items[i]);
|
|
continue;
|
|
}
|
|
database.SetMacroData(&list_data, &itemdata);
|
|
generate_list_item_page(list_data, itemdata, database, err);
|
|
database.ForgetMacroData();
|
|
}
|
|
}
|
|
|
|
void generate_single_list_item_page(const ScriptVariable &list_id,
|
|
const ScriptVariable &item_id,
|
|
Database &database,
|
|
ErrorList **err)
|
|
{
|
|
ListData list_data;
|
|
if(!database.GetListData(list_id, list_data)) {
|
|
ScriptVariable s(63, "Config. error for list %s\n", list_id.c_str());
|
|
ErrorList::AddError(err, s);
|
|
return;
|
|
}
|
|
if(!list_data.pages) {
|
|
ScriptVariable s(63, "List %s has no item pages\n", list_id.c_str());
|
|
ErrorList::AddError(err, s);
|
|
return;
|
|
}
|
|
|
|
int idx = -1;
|
|
int max = list_data.items.Length();
|
|
int i;
|
|
for(i = 0; i < max; i++) {
|
|
if(list_data.items[i] == item_id) {
|
|
idx = i;
|
|
break;
|
|
}
|
|
}
|
|
if(idx == -1) {
|
|
ScriptVariable s(63, "Item %s not found in list %s\n",
|
|
item_id.c_str(), list_id.c_str());
|
|
ErrorList::AddError(err, s);
|
|
return;
|
|
}
|
|
|
|
ListItemData itemdata;
|
|
bool ok = database.GetListItemData(list_data, idx, itemdata);
|
|
if(!ok) {
|
|
ErrorList::AddError(err, ScriptVariable("No data for ") +
|
|
list_data.id + "/" + list_data.items[i]);
|
|
return;
|
|
}
|
|
database.SetMacroData(&list_data, &itemdata);
|
|
generate_list_item_page(list_data, itemdata, database, err);
|
|
database.ForgetMacroData();
|
|
}
|
|
|
|
static void generate_empty_list(const ListData &list_data,
|
|
const ScriptVariable &filename,
|
|
const ScriptVariable &diag_id,
|
|
Database& database, ErrorList **err)
|
|
{
|
|
FILE *listf = start_file(filename, 0, diag_id, err);
|
|
if(!listf)
|
|
return;
|
|
|
|
database.SetMacroData(&list_data, 0);
|
|
output_list_head(listf, list_data, database, err);
|
|
output_list_tail(listf, list_data, database, err);
|
|
database.ForgetMacroData();
|
|
|
|
fclose(listf);
|
|
}
|
|
|
|
static void generate_list_segment(const ListData &list_data,
|
|
const ScriptVariable &filename,
|
|
int pgnum, int startidx, int endidx,
|
|
const ScriptVariable &diag_id,
|
|
Database& database, ErrorList **err)
|
|
{
|
|
FILE *listf = start_file(filename, 0, diag_id, err);
|
|
if(!listf)
|
|
return;
|
|
|
|
database.SetMacroData(&list_data, 0);
|
|
output_list_head(listf, list_data, database, err);
|
|
|
|
int order = startidx < endidx ? 1 : -1;
|
|
int i;
|
|
for(i = startidx; (order==1) ? (i<=endidx) : (i>=endidx); i += order) {
|
|
ListItemData itemdata;
|
|
bool ok;
|
|
|
|
if(list_data.srctype == listsrc_ini) {
|
|
ok = database.GetListItemData(list_data, i, itemdata);
|
|
} else {
|
|
ok = database.GetSetItemDataById(list_data.srcname,
|
|
list_data.items[i],
|
|
&itemdata);
|
|
}
|
|
if(!ok) {
|
|
ErrorList::AddError(err, ScriptVariable("No data for ") +
|
|
list_data.id + "/" + list_data.items[i]
|
|
+ " [ " + itemdata.title + " ]");
|
|
continue;
|
|
}
|
|
if(itemdata.HasFlag("hidden"))
|
|
continue;
|
|
database.SetMacroData(&list_data, &itemdata);
|
|
output_list_item(listf, list_data, itemdata, database, err);
|
|
database.SetMacroData(&list_data, 0);
|
|
}
|
|
|
|
output_list_tail(listf, list_data, database, err);
|
|
database.ForgetMacroData();
|
|
|
|
fclose(listf);
|
|
}
|
|
|
|
static int start_num_for_main_list_page(int itemcnt, int perpage)
|
|
{
|
|
if(perpage == 0)
|
|
return 0;
|
|
if(itemcnt < 2 * perpage)
|
|
return 0;
|
|
// return itemcnt - (itemcnt % perpage + perpage);
|
|
return itemcnt - perpage;
|
|
}
|
|
|
|
template <class T>
|
|
void swapvars(T &a, T&b)
|
|
{
|
|
T c = a;
|
|
a = b;
|
|
b = c;
|
|
}
|
|
|
|
#if 0
|
|
static ScriptVariable make_uri(ScriptVariable &base, const ScriptVariable &u)
|
|
{
|
|
bool need_slash = base.Range(-1, 1)[0] != '/' && u[0] != '/';
|
|
const char *sep = need_slash ? "/" : "";
|
|
return base + sep + u;
|
|
}
|
|
#endif
|
|
|
|
void generate_list(const ScriptVariable& id, Database& database,
|
|
ErrorList **err)
|
|
{
|
|
int i;
|
|
ListData list_data;
|
|
if(!database.GetListData(id, list_data)) {
|
|
ScriptVariable s(63, "Configuration error for list %s\n", id.c_str());
|
|
ErrorList::AddError(err, s);
|
|
return;
|
|
}
|
|
if(list_data.pages)
|
|
generate_all_list_item_pages(list_data, database, err);
|
|
|
|
if(list_data.embedded)
|
|
return;
|
|
|
|
ScriptVariable diag_id = "list ";
|
|
diag_id += id;
|
|
|
|
bool rev = list_data.reverse;
|
|
int perpage = list_data.items_per_listpage;
|
|
int itemcnt = list_data.items.Length();
|
|
int pagecnt = perpage <= 0 ? 1 : (itemcnt ? (itemcnt-1)/perpage+1 : 0);
|
|
////////////////////////////////
|
|
ArrayData array_data;
|
|
array_data.page_count = pagecnt;
|
|
array_data.reverse = rev;
|
|
for(i = 0; i <= pagecnt; i++)
|
|
array_data.href_array[i] = database.GetListHref(id, i);
|
|
if(rev)
|
|
array_data.href_last = array_data.href_array[0];
|
|
else
|
|
array_data.href_first = array_data.href_array[0];
|
|
array_data.current_page = rev ? -1 : 1;
|
|
////////////////////////////////
|
|
ArrayData *ad_save = database.InstallArrayData(&array_data);
|
|
|
|
ScriptVariable filename;
|
|
filename = database.GetListFilename(id, -1);
|
|
|
|
if(itemcnt < 1) {
|
|
// this case is special because parameters of
|
|
// generate_list_segment don't allow to specify
|
|
// zero-length segment
|
|
generate_empty_list(list_data, filename, diag_id, database, err);
|
|
} else {
|
|
int start_num = rev ? itemcnt - 1 : 0;
|
|
int end_num =
|
|
rev ?
|
|
start_num_for_main_list_page(itemcnt, perpage) :
|
|
(perpage > 0 ? perpage-1 : itemcnt-1);
|
|
generate_list_segment(list_data, filename, 0, start_num, end_num,
|
|
diag_id, database, err);
|
|
if(pagecnt > 1 || (pagecnt == 1 && perpage > 0 && rev)) {
|
|
// reverse multipage with only one page is special case
|
|
// to make the ``permanent links'' work
|
|
// otherwise, we're already done
|
|
for(i = rev ? 1 : 2; i <= pagecnt; i++) {
|
|
array_data.current_page = i;
|
|
start_num = (i - 1) * perpage;
|
|
end_num = i * perpage - 1;
|
|
if(end_num >= itemcnt)
|
|
end_num = itemcnt - 1;
|
|
if(rev)
|
|
swapvars(start_num, end_num);
|
|
filename = database.GetListFilename(id, i);
|
|
generate_list_segment(list_data, filename, i,
|
|
start_num, end_num,
|
|
diag_id, database, err);
|
|
}
|
|
}
|
|
}
|
|
database.InstallArrayData(ad_save);
|
|
}
|
|
|
|
void generate_all_lists(Database& database, ErrorList **errlst)
|
|
{
|
|
ScriptVector listnames;
|
|
database.GetLists(listnames);
|
|
int i;
|
|
for(i = 0; i < listnames.Length(); i++)
|
|
generate_list(listnames[i], database, errlst);
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Sets
|
|
// defined by 'pageset' section
|
|
// represented with a directory containing files and/or subdirs, one per page
|
|
|
|
|
|
static void build_set_page(const PageSetData &data, int idx,
|
|
Database& database, ErrorList **err)
|
|
{
|
|
ScriptVariable whatfor = data.id + "::" + data.page_ids[idx];
|
|
|
|
ListItemData lid;
|
|
if(!database.GetSetItemData(data, idx, &lid)) {
|
|
ScriptVariable s(63, "Can't get set page data %s, skipping",
|
|
whatfor.c_str());
|
|
ErrorList::AddError(err, s);
|
|
return;
|
|
}
|
|
|
|
if(lid.HasFlag("hidden"))
|
|
return;
|
|
|
|
database.SetMacroData(0, &lid);
|
|
|
|
bool separ_dir;
|
|
switch(data.make_subdirs) {
|
|
case pageset_subdir_always:
|
|
separ_dir = true;
|
|
break;
|
|
case pageset_subdir_never:
|
|
separ_dir = false;
|
|
break;
|
|
case pageset_subdir_bysource:
|
|
default:
|
|
separ_dir = lid.make_separate_directory;
|
|
}
|
|
|
|
ScriptVariable destdir, destidx, main_href, cmapfname;
|
|
database.GetSetItemFilenames(data, separ_dir,
|
|
destdir, destidx, main_href, cmapfname);
|
|
|
|
if(!provide_dest_dir(destdir, whatfor, err))
|
|
return;
|
|
|
|
ScriptVariable mainpg, tail;
|
|
ForumGenerator *fg;
|
|
database.BuildSetItemPage(data, lid, mainpg, tail, &fg);
|
|
|
|
int pgcnt;
|
|
bool reverse;
|
|
bool multipage_by_comments = false;
|
|
if(fg) {
|
|
bool ok = fg->GetArrayInfo(pgcnt, reverse);
|
|
if(ok && pgcnt > 1)
|
|
multipage_by_comments = true;
|
|
}
|
|
|
|
if(!multipage_by_comments) {
|
|
// very simple case
|
|
ArrayData *save = database.InstallArrayData(0);
|
|
ScriptVariable cmts("");
|
|
if(fg)
|
|
cmts = fg->Build();
|
|
output_file(destidx, 0, whatfor, err,
|
|
mainpg.c_str(), cmts.c_str(), tail.c_str());
|
|
database.InstallArrayData(save);
|
|
} else {
|
|
////////////////////////////
|
|
ArrayData arrayd;
|
|
arrayd.page_count = pgcnt;
|
|
arrayd.reverse = reverse;
|
|
arrayd.href_array[0] = main_href;
|
|
|
|
ScriptVector sub_filename;
|
|
sub_filename[0] = destidx;
|
|
|
|
int i;
|
|
for(i = 1; i <= pgcnt; i++) {
|
|
int idxval = fg->GetPageIdxValue(i);
|
|
ScriptVariable sfn, hrf;
|
|
database.GetSetSubitemFilename(data, separ_dir, idxval, sfn, hrf);
|
|
sub_filename[i] = sfn;
|
|
arrayd.href_array[i] = hrf;
|
|
}
|
|
if(reverse)
|
|
arrayd.href_last = main_href;
|
|
else
|
|
arrayd.href_first = main_href;
|
|
arrayd.current_page = -1;
|
|
ArrayData *ad_save = database.InstallArrayData(&arrayd);
|
|
////////////////////////////
|
|
|
|
fg->SetMainHref(main_href);
|
|
|
|
bool ok;
|
|
do {
|
|
int idxf, idx_array;
|
|
fg->GetIndices(idxf, idx_array);
|
|
if(idx_array < 0 || idx_array > pgcnt)
|
|
idx_array = 0;
|
|
arrayd.current_page = idx_array;
|
|
fg->SetHref(arrayd.href_array[idx_array]);
|
|
ScriptVariable compage = fg->Build();
|
|
output_file(sub_filename[idx_array], 0, whatfor, err,
|
|
mainpg.c_str(), compage.c_str(), tail.c_str());
|
|
ok = fg->Next();
|
|
} while(ok);
|
|
|
|
database.InstallArrayData(ad_save);
|
|
|
|
ScriptVariable cmap = fg->MakeCommentMap();
|
|
if(cmap.IsValid() && cmap != "" && cmapfname.IsValid())
|
|
output_file(cmapfname, 0, whatfor, err, cmap.c_str());
|
|
}
|
|
if(fg)
|
|
delete fg;
|
|
|
|
publish_files(data.source_dir + "/" + data.page_ids[idx], destdir,
|
|
lid.files, data.publish_method, whatfor, err);
|
|
|
|
database.ForgetMacroData();
|
|
}
|
|
|
|
void generate_single_set_page(const ScriptVariable& set_id,
|
|
const ScriptVariable& page_id,
|
|
Database& database,
|
|
ErrorList **err)
|
|
{
|
|
PageSetData data;
|
|
if(!database.GetSetData(set_id, data)) {
|
|
ErrorList::AddError(err, ScriptVariable("No data for ") + set_id);
|
|
return;
|
|
}
|
|
data.page_ids[0] = page_id;
|
|
build_set_page(data, 0, database, err);
|
|
}
|
|
|
|
void generate_set(const ScriptVariable& id, Database& database,
|
|
ErrorList **err)
|
|
{
|
|
PageSetData data;
|
|
if(!database.GetSetData(id, data)) {
|
|
ErrorList::AddError(err, ScriptVariable("No data for ") + id);
|
|
return;
|
|
}
|
|
database.ScanSetDirectory(data);
|
|
int pgcount = data.page_ids.Length();
|
|
int i;
|
|
for(i = 0; i < pgcount; i++)
|
|
build_set_page(data, i, database, err);
|
|
}
|
|
|
|
|
|
void generate_all_sets(Database& database, ErrorList **errlst)
|
|
{
|
|
ScriptVector setnames;
|
|
database.GetSets(setnames);
|
|
int i;
|
|
for(i = 0; i < setnames.Length(); i++) {
|
|
generate_set(setnames[i], database, errlst);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Collections
|
|
// Defined by [collection id] sections
|
|
// Generally, it is just a directory with files
|
|
|
|
void publish_collection(const ScriptVariable& id,
|
|
Database& database, ErrorList **err)
|
|
{
|
|
ScriptVariable srcdir, dstdir;
|
|
int method;
|
|
|
|
database.GetCollectionData(id, srcdir, dstdir, method);
|
|
publish_dir(srcdir, dstdir, method, id, err);
|
|
}
|
|
|
|
void publish_all_collections(Database& database, ErrorList **errlst)
|
|
{
|
|
ScriptVector collnames;
|
|
database.GetCollections(collnames);
|
|
int i;
|
|
for(i = 0; i < collnames.Length(); i++) {
|
|
publish_collection(collnames[i], database, errlst);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Binaries
|
|
// Defined by [binary name] sections
|
|
// It is a single file (not necessarily binary) of arbitrary nature
|
|
|
|
void publish_binary(const ScriptVariable& id, Database& database,
|
|
ErrorList **err)
|
|
{
|
|
ScriptVariable src, dst;
|
|
int method;
|
|
|
|
database.GetBinaryData(id, src, dst, method);
|
|
|
|
ScriptVariable whatfor("binary ");
|
|
whatfor += id;
|
|
|
|
if(src.IsInvalid() || src == "")
|
|
src = id;
|
|
else
|
|
if(src.Range(-1, 1)[0] == '/')
|
|
src += id;
|
|
else {
|
|
FileStat fs(src.c_str());
|
|
if(!fs.Exists()) {
|
|
ScriptVariable s(63, "Source %s doesn't exist [%s]",
|
|
src.c_str(), whatfor.c_str());
|
|
ErrorList::AddError(err, s);
|
|
return;
|
|
}
|
|
if(fs.IsDir()) {
|
|
src += '/';
|
|
src += id;
|
|
}
|
|
}
|
|
publish_given_file(src, dst, method, whatfor, err);
|
|
}
|
|
|
|
void publish_all_binaries(Database& database, ErrorList **errlst)
|
|
{
|
|
ScriptVector binnames;
|
|
database.GetBinaries(binnames);
|
|
int i;
|
|
for(i = 0; i < binnames.Length(); i++) {
|
|
publish_binary(binnames[i], database, errlst);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Alias sections
|
|
// Defined by [aliases id] sections
|
|
// In the present version, these are implemented as symlinks, except for
|
|
// the directories explicitly listed, which are implemented using a
|
|
// file (either .htaccess, or index.html that causes redirect)
|
|
//
|
|
|
|
static void generate_single_alias(const ScriptVariable &alias,
|
|
const ScriptVariable &original,
|
|
const ScriptVariable &whatfor,
|
|
Database& database,
|
|
ErrorList **err)
|
|
{
|
|
int r = make_symlink(original, alias);
|
|
if(r == -1) {
|
|
ScriptVariable s(127, "couldn't alias %s to %s [%s]",
|
|
alias.c_str(), original.c_str(), whatfor.c_str());
|
|
ErrorList::AddError(err, s);
|
|
}
|
|
}
|
|
|
|
static void form_aliased_directory(const ScriptVariable &dirpath,
|
|
const ScriptVariable &target_uri,
|
|
const ScriptVariable §_id,
|
|
Database& database,
|
|
ErrorList **err)
|
|
{
|
|
make_directory_path(dirpath.c_str(), 0);
|
|
ScriptVariable fname = database.GetAliasDirFilename(sect_id);
|
|
ScriptVariable body = database.BuildAliasDirFile(sect_id, target_uri);
|
|
output_file(dirpath + "/" + fname, 0, sect_id, err, body.c_str());
|
|
}
|
|
|
|
static bool svec_has_elem(const ScriptVector &v, const ScriptVariable &el)
|
|
{
|
|
int i;
|
|
for(i = 0; i < v.Length(); i++) {
|
|
if(v[i] == el)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void generate_aliases(const ScriptVariable& id, Database& database,
|
|
ErrorList **err)
|
|
{
|
|
ScriptVariable fbase = database.GetFilePrefix();
|
|
ScriptVector aliasvec, forced_dirs;
|
|
database.GetAliases(id, aliasvec);
|
|
database.GetAliasDirs(id, forced_dirs);
|
|
int i;
|
|
int n = aliasvec.Length();
|
|
for(i = 0; i < n - 1; i+=2) {
|
|
ScriptVariable src = aliasvec[i];
|
|
ScriptVariable dst = aliasvec[i+1];
|
|
if(svec_has_elem(forced_dirs, src)) {
|
|
form_aliased_directory(fbase + src, dst, id, database, err);
|
|
} else {
|
|
generate_single_alias(fbase + src, fbase + dst, id, database, err);
|
|
}
|
|
}
|
|
}
|
|
|
|
void generate_all_alias_sections(Database& database, ErrorList **errlst)
|
|
{
|
|
ScriptVector names;
|
|
database.GetAliasSections(names);
|
|
int i;
|
|
for(i = 0; i < names.Length(); i++) {
|
|
generate_aliases(names[i], database, errlst);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// database isn't const, 'cause generate_list affects the object
|
|
ErrorList* generate_everything(Database& database)
|
|
{
|
|
ErrorList *errls = 0;
|
|
|
|
make_directory_path(database.GetFilePrefix().c_str(), 0);
|
|
|
|
generate_all_genfiles(database, &errls);
|
|
generate_all_pages(database, &errls);
|
|
publish_all_collections(database, &errls);
|
|
publish_all_binaries(database, &errls);
|
|
|
|
generate_all_lists(database, &errls);
|
|
generate_all_sets(database, &errls);
|
|
/* _sets should be after _lists to have access to some list info */
|
|
|
|
generate_all_alias_sections(database, &errls);
|
|
|
|
return errls;
|
|
}
|