Fixed a lot.

This commit is contained in:
Neil Edelman 2017-03-26 04:47:35 -04:00
parent 2b2daae97a
commit 7613e60e86
11 changed files with 640 additions and 190 deletions

View File

@ -1,37 +0,0 @@
# Windows port cross-compiling with MacOSX MinGW 4.3.0
# (good luck)
PROJ := MakeIndex
VA := 0
VB := 8
FILES := Recursor Parser Widget Files
BDIR := win
BACK := backup
EXE := $(PROJ).exe
INST := $(PROJ)-$(VA)_$(VB)
OBJS := $(patsubst %,$(BDIR)/%.o,$(FILES))
SRCS := $(patsubst %,%.c,$(FILES))
H := $(patsubst %,%.h,$(FILES))
CC := /usr/local/i386-mingw32-4.3.0/bin/i386-mingw32-gcc
CF := -Wall -O3 -fasm -fomit-frame-pointer -ffast-math -funroll-loops -pedantic -ansi
default: $(BDIR)/$(EXE)
$(BDIR)/$(EXE): $(OBJS)
$(CC) $(CF) -o $@ $^
$(BDIR)/%.o: %.c
@mkdir -p $(BDIR)
$(CC) $(CF) -c $? -o $@
.PHONY: clean backup
clean:
-rm $(OBJS)
setup: $(BDIR)/$(EXE)
@mkdir -p $(INST)
cp $(BDIR)/$(EXE) readme.txt gpl.txt copying.txt $(INST)
cp -a bin/example $(INST)
zip $(BDIR)/$(INST)-Win32-`date +%Y-%m-%dT%H%M%S` $(INST)/$(EXE) -r $(INST)
rm -R $(INST)

View File

@ -49,14 +49,14 @@ Copyright 2008, 2012 Neil Edelman, distributed under the terms of the
a relation to other Files by 'parent' and 'favourite' (@(pwd) uses this.) a relation to other Files by 'parent' and 'favourite' (@(pwd) uses this.)
</p> </p>
<dl> <dl>
<dt>author:</dt> <dt>minimum standard</dt>
<dd>C89/90</dd>
<dt>author</dt>
<dd>Neil</dd> <dd>Neil</dd>
<dt>version:</dt> <dt>version</dt>
<dd>0.9; 2017-03 fixed pedantic warnings</dd> <dd>1.1; 2017-03 fixed pedantic warnings; took out arg</dd>
<dt>since:</dt> <dt>since</dt>
<dd>0.8; 2013-07 case-insensitive sort <dd>0.6; 2008-03-24</dd>
0.7; 2012 sth.dsth.d handled properly
0.6; 2008-03-24</dd>
</dl> </dl>
@ -200,12 +200,8 @@ After FilesSetFarourite, this enumerates them.
<div><a name = "FilesName"><!-- --></a> <div><a name = "FilesName"><!-- --></a>
<h3>FilesName</h3> <h3>FilesName</h3>
<pre>char * <b>FilesName</b> (const struct Files *files)</pre> <pre>char * <b>FilesName</b> (const struct Files *files)</pre>
<p>
</p>
<p>
</p>
<dl> <dl>
<dt>return:</dt> <dt>return</dt>
<dd>The file name of the selected file.</dd> <dd>The file name of the selected file.</dd>
</dl> </dl>
</div> </div>
@ -213,12 +209,8 @@ After FilesSetFarourite, this enumerates them.
<div><a name = "FilesSize"><!-- --></a> <div><a name = "FilesSize"><!-- --></a>
<h3>FilesSize</h3> <h3>FilesSize</h3>
<pre>int <b>FilesSize</b> (const struct Files *files)</pre> <pre>int <b>FilesSize</b> (const struct Files *files)</pre>
<p>
</p>
<p>
</p>
<dl> <dl>
<dt>return:</dt> <dt>return</dt>
<dd>File size of the selected file.</dd> <dd>File size of the selected file.</dd>
</dl> </dl>
</div> </div>
@ -226,12 +218,8 @@ After FilesSetFarourite, this enumerates them.
<div><a name = "FilesIsDir"><!-- --></a> <div><a name = "FilesIsDir"><!-- --></a>
<h3>FilesIsDir</h3> <h3>FilesIsDir</h3>
<pre>int <b>FilesIsDir</b> (const struct Files *files)</pre> <pre>int <b>FilesIsDir</b> (const struct Files *files)</pre>
<p>
</p>
<p>
</p>
<dl> <dl>
<dt>return:</dt> <dt>return</dt>
<dd>Whether the file is a directory.</dd> <dd>Whether the file is a directory.</dd>
</dl> </dl>
</div> </div>

View File

@ -45,31 +45,90 @@
<a name = "_declarations"><!-- --></a><h2>Declarations</h2> <a name = "_declarations"><!-- --></a><h2>Declarations</h2>
<div><a name = "struct Parser"><!-- --></a>
<h3>struct Parser</h3>
<pre><b>struct Parser</b></pre>
<p>
See <a href = "#Parser">Parser</a>.
</p>
<dl>
</dl>
</div>
<div><a name = "struct Files"><!-- --></a>
<h3>struct Files</h3>
<pre><b>struct Files</b></pre>
<p>
Dependancy on <em>Files</em>
</p>
<dl>
</dl>
</div>
<div><a name = "typedef int (*ParserWidget)(const struct Files *, FILE *fp)"><!-- --></a>
<h3>typedef int (*ParserWidget)(const struct Files *, FILE *fp)</h3>
<pre><b>typedef int (*ParserWidget)(const struct Files *, FILE *fp)</b></pre>
<p>
All <em>ParserWidget</em>s are in <em>Widget.c</em>
</p>
<dl>
</dl>
</div>
<a name = "_summary"><!-- --></a><h2>Function Summary</h2> <a name = "_summary"><!-- --></a><h2>Function Summary</h2>
<table> <table>
<tr><th>Return Type</th><th>Function Name</th><th>Argument List</th></tr> <tr><th>Return Type</th><th>Function Name</th><th>Argument List</th></tr>
<tr> <tr>
<td>const struct Symbol *</td> <td>struct Parser *</td>
<td><a href = "#match">match</a></td> <td><a href = "#Parser">Parser</a></td>
<td>const char *str, const char *end</td> <td>const char *str</td>
</tr>
<tr>
<td>void</td>
<td><a href = "#Parser_">Parser_</a></td>
<td>struct Parser **const p_ptr</td>
</tr>
<tr>
<td>void</td>
<td><a href = "#ParserRewind">ParserRewind</a></td>
<td>struct Parser *p</td>
</tr> </tr>
<tr> <tr>
<td>int</td> <td>int</td>
<td><a href = "#ParserParse">ParserParse</a></td> <td><a href = "#ParserParse">ParserParse</a></td>
<td>struct Parser *p, const struct Files *f, int invisible, FILE *fp</td> <td>struct Parser *p, const struct Files *f, int invisible,
FILE *fp</td>
</tr> </tr>
</table> </table>
<a name = "_detail"><!-- --></a><h2>Function Detail</h2> <a name = "_detail"><!-- --></a><h2>Function Detail</h2>
<div><a name = "match"><!-- --></a> <div><a name = "Parser"><!-- --></a>
<h3>match</h3> <h3>Parser</h3>
<pre>const struct Symbol * <b>match</b> (const char *str, const char *end)</pre> <pre>struct Parser * <b>Parser</b> (const char *str)</pre>
<dl>
<dt>return</dt>
<dd>Creates a parser for the string, <em>str</em>.</dd>
</dl>
</div>
<div><a name = "Parser_"><!-- --></a>
<h3>Parser_</h3>
<pre>void <b>Parser_</b> (struct Parser **const p_ptr)</pre>
<dl>
<dt>parameter: p_ptr</dt>
<dd>A pointer to the <em>Parser</em> that's to be destucted.</dd>
</dl>
</div>
<div><a name = "ParserRewind"><!-- --></a>
<h3>ParserRewind</h3>
<pre>void <b>ParserRewind</b> (struct Parser *p)</pre>
<p> <p>
binary search Resets the parser, <em>p</em>.
</p> </p>
<dl> <dl>
</dl> </dl>
@ -77,11 +136,22 @@ binary search
<div><a name = "ParserParse"><!-- --></a> <div><a name = "ParserParse"><!-- --></a>
<h3>ParserParse</h3> <h3>ParserParse</h3>
<pre>int <b>ParserParse</b> (struct Parser *p, const struct Files *f, int invisible, FILE *fp)</pre> <pre>int <b>ParserParse</b> (struct Parser *p, const struct Files *f, int invisible,
FILE *fp)</pre>
<p> <p>
parse, called recusively (invisible, hack) fixme: this fn needs rewriting, messy Parse, called recursively.
</p> </p>
<dl> <dl>
<dt>parameter: f</dt>
<dd>Called in the handler to <em>ParserWidget</em>s.</dd>
<dt>parameter: invisible</dt>
<dd>No output.</dd>
<dt>parameter: fp</dt>
<dd>Output.</dd>
<dt>fixme</dt>
<dd>This fn needs rewriting; messy.</dd>
<dt>fixme</dt>
<dd>Invisible, hack.</dd>
</dl> </dl>
</div> </div>

View File

@ -25,13 +25,13 @@
padding: 4px; padding: 4px;
} }
</style> </style>
<title></title> <title>Parser</title>
</head> </head>
<body> <body>
<h1></h1> <h1>Parser</h1>
<ul> <ul>
<li><a href = "#_declarations">Declarations</a></li> <li><a href = "#_declarations">Declarations</a></li>
@ -44,15 +44,82 @@ Copyright 2008, 2012 Neil Edelman, distributed under the terms of the
GNU General Public License, see copying.txt GNU General Public License, see copying.txt
</p> </p>
<p> <p>
This is the main program. I didn't know what to call it. <em>MakeIndex</em> is a simple content management system that generates static
content, (mostly index.html,) on all the directories rooted at the directory
specified by the argument. It is based on a template file, ".index.html" and
".newsfeed.rss". Also included are files to summarise the directory structure
for a <em>xml</em> site map, compatible with Google, and any <em>.news</em> for an <em>rss</em>
feed. It takes one argument, &lt;directory&gt;, which is the root of the recursion.
</p>
<p>
There should be an &lt;example&gt; directory that has a bunch of files in it. Run
<em>bin/MakeIndex example/</em>; it should make a webpage out of the directory
structure and <em>.index.html</em>, open <em>example/index.html</em> after running to see.
</p>
<ul>
<li>
If the <em>.index.html</em> file exists in the &lt;directory&gt;, prints &lt;index.html&gt;
recursively; overwrites any <em>index.html</em> on all the directories rooted at
&lt;directory&gt;;
</li>
<li>
if the <em>.sitemap.xml</em> file exists in &lt;directory&gt;, prints (and overwrites) an
index called <em>sitemap.xml</em>;
</li>
<li>
if the <em>.newsfeed.rss</em> file exists in &lt;directory&gt;, prints (and overwrites)
to <em>newsfeed.rss</em> all the <em>.news</em> files (if there are any.)
</li>
</ul>
<ul>
<li>
Treats <em>.d</em> as a description of the file without the <em>.d</em>;
if this is an empty text-file or a zero-byte file, it skips over this file.
</li>
<li>
treats <em>index.d</em> as a description of the directory;
</li>
<li>
treats <em>content.d</em> as an in-depth description of the directory,
replacing &lt;index.d&gt; when in the directory;
</li>
<li>
treats <em>.d.jpg</em> as a image that will go with the description;
</li>
<li>
treats <em>.news</em> as a newsworthy item; the format of this file is ISO 8601
date (YYYY-MM-DD,) next line title;
</li>
<li>
treats <em>.link</em> as a link with the href in the file.
</li>
</ul>
<p>
<em>.index.html</em>, <em>.sitemap.xml</em>, <em>.newsfeed.rss</em>, see <em>Parser</em> for recognised
symbols. Assumes '..' is the parent directory, '.' is the current directory,
and '/' is the directory separator; works for UNIX, MacOS, Windows.
If this is not the case, the constants are in <em>Files.c</em>.
</p> </p>
<dl> <dl>
<dt>author:</dt> <dt>minimum standard</dt>
<dd>C89/90</dd>
<dt>author</dt>
<dd>Neil</dd> <dd>Neil</dd>
<dt>version:</dt> <dt>version</dt>
<dd>1.0; 2016-09-19 Added umask</dd> <dd>1.1; 2017-03 fixed pedantic warnings; took out arg</dd>
<dt>since:</dt> <dt>since</dt>
<dd>1.0; 2008-03-27</dd> <dd>1.0; 2016-09-19 Added umask
0.8; 2013-07 case-insensitive sort
0.7; 2012 sth.dsth.d handled properly
0.6; 2008-03-27</dd>
<dt>fixme</dt>
<dd>Don't have &lt;directory&gt; be an argument; just do it in the current.</dd>
<dt>fixme</dt>
<dd>Have a subset of LaTeX converted into html for the .d files?</dd>
<dt>fixme</dt>
<dd>Encoding is an issue; especially the newsfeed, 7bit.</dd>
<dt>fixme</dt>
<dd>It's not robust; eg @(files)<em>@(files){Don't do this.}</em>.</dd>
</dl> </dl>

View File

@ -50,11 +50,221 @@
<table> <table>
<tr><th>Return Type</th><th>Function Name</th><th>Argument List</th></tr> <tr><th>Return Type</th><th>Function Name</th><th>Argument List</th></tr>
<tr>
<td>int</td>
<td><a href = "#WidgetContent">WidgetContent</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetDate">WidgetDate</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetFilealt">WidgetFilealt</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetFiledesc">WidgetFiledesc</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetFilehref">WidgetFilehref</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetFileicon">WidgetFileicon</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetFilename">WidgetFilename</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetFiles">WidgetFiles</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetFilesize">WidgetFilesize</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetNews">WidgetNews</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetNewsname">WidgetNewsname</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetNow">WidgetNow</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetPwd">WidgetPwd</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetRoot">WidgetRoot</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
<tr>
<td>int</td>
<td><a href = "#WidgetTitle">WidgetTitle</a></td>
<td>const struct Files *f, FILE *fp</td>
</tr>
</table> </table>
<a name = "_detail"><!-- --></a><h2>Function Detail</h2> <a name = "_detail"><!-- --></a><h2>Function Detail</h2>
<div><a name = "WidgetContent"><!-- --></a>
<h3>WidgetContent</h3>
<pre>int <b>WidgetContent</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetDate"><!-- --></a>
<h3>WidgetDate</h3>
<pre>int <b>WidgetDate</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetFilealt"><!-- --></a>
<h3>WidgetFilealt</h3>
<pre>int <b>WidgetFilealt</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetFiledesc"><!-- --></a>
<h3>WidgetFiledesc</h3>
<pre>int <b>WidgetFiledesc</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetFilehref"><!-- --></a>
<h3>WidgetFilehref</h3>
<pre>int <b>WidgetFilehref</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetFileicon"><!-- --></a>
<h3>WidgetFileicon</h3>
<pre>int <b>WidgetFileicon</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetFilename"><!-- --></a>
<h3>WidgetFilename</h3>
<pre>int <b>WidgetFilename</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetFiles"><!-- --></a>
<h3>WidgetFiles</h3>
<pre>int <b>WidgetFiles</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetFilesize"><!-- --></a>
<h3>WidgetFilesize</h3>
<pre>int <b>WidgetFilesize</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetNews"><!-- --></a>
<h3>WidgetNews</h3>
<pre>int <b>WidgetNews</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetNewsname"><!-- --></a>
<h3>WidgetNewsname</h3>
<pre>int <b>WidgetNewsname</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetNow"><!-- --></a>
<h3>WidgetNow</h3>
<pre>int <b>WidgetNow</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetPwd"><!-- --></a>
<h3>WidgetPwd</h3>
<pre>int <b>WidgetPwd</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetRoot"><!-- --></a>
<h3>WidgetRoot</h3>
<pre>int <b>WidgetRoot</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
<div><a name = "WidgetTitle"><!-- --></a>
<h3>WidgetTitle</h3>
<pre>int <b>WidgetTitle</b> (const struct Files *f, FILE *fp)</pre>
<dl>
<dt>implements</dt>
<dd>ParserWidget</dd>
</dl>
</div>
</body> </body>
</html> </html>

View File

@ -5,12 +5,11 @@
Files is a list of File (private class defiend below,) the Files can have Files is a list of File (private class defiend below,) the Files can have
a relation to other Files by 'parent' and 'favourite' (@(pwd) uses this.) a relation to other Files by 'parent' and 'favourite' (@(pwd) uses this.)
@file Files @title Files
@author Neil @author Neil
@version 0.9; 2017-03 fixed pedantic warnings @std C89/90
@since 0.8; 2013-07 case-insensitive sort @version 1.1; 2017-03 fixed pedantic warnings; took out arg
0.7; 2012 sth.dsth.d handled properly @since 0.6; 2008-03-24 */
0.6; 2008-03-24 */
#include <stdlib.h> /* malloc free */ #include <stdlib.h> /* malloc free */
#include <stdio.h> /* fprintf */ #include <stdio.h> /* fprintf */
@ -22,7 +21,7 @@
/* constants */ /* constants */
const char *dirCurrent = "."; /* used in multiple files */ const char *dirCurrent = "."; /* used in multiple files */
const char *dirParent = ".."; const char *dirParent = "..";
static const int maxFilename = 128; static const size_t maxFilename = 128;
/* public */ /* public */
struct Files { struct Files {
@ -161,10 +160,10 @@ int FilesIsDir(const struct Files *files) {
/* this is just a list of filenames, (not public) "class File" */ /* this is just a list of filenames, (not public) "class File" */
static struct File *File(const char *name, const int size, const int isDir) { static struct File *File(const char *name, const int size, const int isDir) {
int len; size_t len;
struct File *file; struct File *file;
if(!name || !*name) { fprintf(stderr, "File: file has no name.\n"); return 0; } if(!name || !*name) { fprintf(stderr, "File: file has no name.\n"); return 0; }
if((len = strlen(name)) > maxFilename) { fprintf(stderr, "File: file name \"%s\" is too long (%d.)\n", name, maxFilename); return 0; } if((len = strlen(name)) > maxFilename) { fprintf(stderr, "File: file name \"%s\" is too long (%lu.)\n", name, maxFilename); return 0; }
file = malloc(sizeof(struct File) + (len + 1)); file = malloc(sizeof(struct File) + (len + 1));
if(!file) { File_(file); return 0; } if(!file) { File_(file); return 0; }
file->next = 0; file->next = 0;

View File

@ -1,6 +1,5 @@
/** See \see{Files}. */ /** See \see{Files}. */
struct Files; struct Files;
struct Recursor;
/** Returns a boolean value. */ /** Returns a boolean value. */
typedef int (*FilesFilter)(const struct Files *, const char *); typedef int (*FilesFilter)(const struct Files *, const char *);

View File

@ -1,8 +1,43 @@
/* Copyright 2008, 2012 Neil Edelman, distributed under the terms of the /* Copyright 2008, 2012 Neil Edelman, distributed under the terms of the
GNU General Public License, see copying.txt */ GNU General Public License, see copying.txt
/* Parsing of strings. Parsing of strings. '~' on a line by itself is recognised in ".newsfile.rss"
* Created by Neil Edelman on 2008-03-21. */ and ".sitemap.xml" as a <head>~<body>~<tail>; there should be two of them.
Parsed in ".index.html",
* @(content) prints {content.d}, or, if it is missing, {index.d};
* @(files){} repeats for all the files in the directory the contents of the
argument;
* @(htmlcontent);
* @(pwd){} prints the directory, the argument is the separator; eg, @(pwd){/};
* @(root){}, like @(pwd), except up instead of down;
* @(now) prints the date and the time in UTC.
Further parsed in @(files){} in ".index.html",
* @(filealt) prints Dir or File;
* @(filedesc);
* @(filehref) prints the filename or the {.link};
* @(fileicon) prints it's {.d.jpeg}, or if it is not there, {dir.jpeg} or
{file.jpeg};
* @(filename) prints the file name;
* @(filesize) prints the file size, if it exits;
* @(now) prints the date and the time in UTC.
Parsed in ".newsfeed.rss",
* @(date) prints the date on the news file;
* @(news) prints the contents of the file (as a text file);
* @(newsname) prints the filename of the news story;
* @(now) prints the date and the time in UTC;
* @(title) prints the second line in the {.news}.
@title Parser
@author Neil
@std C89/90
@version 1.1; 2017-03 fixed pedantic warnings; took out arg
@since 0.6; 2008-03-21 */
#include <stdio.h> /* [f]printf FILE */ #include <stdio.h> /* [f]printf FILE */
#include <stdlib.h> /* malloc */ #include <stdlib.h> /* malloc */
@ -22,11 +57,11 @@ struct Parser {
}; };
/* private - this is the list of 'widgets', see Widget.c - add widgets to here /* private - this is the list of 'widgets', see Widget.c - add widgets to here
to make them recognised - ASCIIbetical */ to make them recognised - ASCIIbetical */
struct Symbol { static const struct Symbol {
char *symbol; char *symbol;
int (*handler)(const struct Files *, FILE *fp); const ParserWidget handler;
int onlyInRoot; /* fixme: not used, just trust the users? haha */ int onlyInRoot; /* fixme: not used, just trust the users? haha */
} static const sym[] = { } sym[] = {
{ "content", &WidgetContent, 0 }, /* index */ { "content", &WidgetContent, 0 }, /* index */
{ "date", &WidgetDate, 0 }, /* news */ { "date", &WidgetDate, 0 }, /* news */
{ "filealt", &WidgetFilealt, 0 }, /* files */ { "filealt", &WidgetFilealt, 0 }, /* files */
@ -41,54 +76,52 @@ struct Symbol {
{ "news", &WidgetNews, 0 }, /* news */ { "news", &WidgetNews, 0 }, /* news */
{ "newsname", &WidgetNewsname, 0 }, /* news */ { "newsname", &WidgetNewsname, 0 }, /* news */
{ "now", &WidgetNow, 0 }, /* any */ { "now", &WidgetNow, 0 }, /* any */
{ "pwd", &WidgetPwd, -1 }, /* don't put it where it doesn't make sense */ { "pwd", &WidgetPwd, -1 }, /* index */
{ "root", &WidgetRoot, -1 }, /* like pwd exept up instead of dn */ { "root", &WidgetRoot, -1 }, /* like pwd except up instead of dn */
{ "title", &WidgetTitle, 0 } /* news */ { "title", &WidgetTitle, 0 } /* news */
}; };
/* private */ /* private */
int parse(struct Parser *p, int invisible, FILE *fp); static const struct Symbol *match(const char *str, const char *end);
/** @return Creates a parser for the string, {str}. */
struct Parser *Parser(const char *str) { struct Parser *Parser(const char *str) {
struct Parser *p; struct Parser *p;
p = malloc(sizeof(struct Parser)); if(!(p = malloc(sizeof *p))) return 0;
p->str = (char *)str; p->str = (char *)str;
p->pos = p->str; p->pos = p->str;
p->rew = p->str; p->rew = p->str;
p->recursion = 0; p->recursion = 0;
return p; return p;
} }
void Parser_(struct Parser *p) {
if(!p) return; /** @param p_ptr: A pointer to the {Parser} that's to be destucted. */
void Parser_(struct Parser **const p_ptr) {
struct Parser *p;
if(!p_ptr || !(p = *p_ptr)) return;
if(p->recursion) fprintf(stderr, "Parser~: a file was closed with recursion level of %d; syntax error?\n", p->recursion); if(p->recursion) fprintf(stderr, "Parser~: a file was closed with recursion level of %d; syntax error?\n", p->recursion);
free(p); free(p);
*p_ptr = 0;
} }
/** binary search */ /** Resets the parser, {p}. */
const struct Symbol *match(const char *str, const char *end) {
const int N = sizeof(sym) / sizeof(struct Symbol);
int a, lenMatch, lenComp, lo = 0, mid, hi = N - 1;
lenMatch = end - str;
while(lo <= hi) {
mid = (lo + hi) >> 1;
/* this is highly inefficient */
lenComp = strlen(sym[mid].symbol);
a = strncmp(str, sym[mid].symbol, lenMatch > lenComp ? lenMatch : lenComp);
if (a < 0) hi = mid - 1;
else if(a > 0) lo = mid + 1;
else return &sym[mid];
}
return 0;
}
void ParserRewind(struct Parser *p) { void ParserRewind(struct Parser *p) {
if(!p) return; if(!p) return;
p->pos = p->rew; p->pos = p->rew;
} }
/** parse, called recusively (invisible, hack) fixme: this fn needs rewriting, messy */
int ParserParse(struct Parser *p, const struct Files *f, int invisible, FILE *fp) { /** Parse, called recursively.
@param f: Called in the handler to {ParserWidget}s.
@param invisible: No output.
@param fp: Output.
@fixme This fn needs rewriting; messy.
@fixme Invisible, hack. */
int ParserParse(struct Parser *p, const struct Files *f, int invisible,
FILE *fp) {
char *mark; char *mark;
if(!p || !fp || !p->pos) return 0; if(!p || !fp || !p->pos) return 0;
if(++p->recursion > maxRecursion) fprintf(stderr, "Parser::parse: %d recursion levels reached (Ctrl-C to stop!)\n", p->recursion); if(++p->recursion > maxRecursion) fprintf(stderr, "Parser::parse: %d "
"recursion levels reached (Ctrl-C to stop!)\n", p->recursion);
mark = p->pos; mark = p->pos;
if(p->recursion == 1) p->rew = mark; if(p->recursion == 1) p->rew = mark;
for( ; ; ) { for( ; ; ) {
@ -117,7 +150,8 @@ int ParserParse(struct Parser *p, const struct Files *f, int invisible, FILE *fp
char *start = p->pos + 2, *end; char *start = p->pos + 2, *end;
if(!invisible) fprintf(fp, "%.*s", (int)(p->pos - mark), mark); if(!invisible) fprintf(fp, "%.*s", (int)(p->pos - mark), mark);
if(!(end = strpbrk(start, ")"))) break; /* syntax error */ if(!(end = strpbrk(start, ")"))) break; /* syntax error */
if(!(m = match(start, end))) fprintf(stderr, "Parser::parse: symbol not reconised, '%.*s.'\n", (int)(end - start), start); if(!(m = match(start, end))) fprintf(stderr, "Parser::parse: "
"symbol not reconised, '%.*s.'\n", (int)(end - start), start);
/* if(p->recursion == 1 && m && m->onlyInRoot) return -1; ? */ /* if(p->recursion == 1 && m && m->onlyInRoot) return -1; ? */
open = *(end + 1) == '{' ? -1 : 0; open = *(end + 1) == '{' ? -1 : 0;
do { do {
@ -135,3 +169,22 @@ int ParserParse(struct Parser *p, const struct Files *f, int invisible, FILE *fp
p->recursion--; p->recursion--;
return 0; return 0;
} }
/** binary search */
static const struct Symbol *match(const char *str, const char *end) {
const int N = sizeof(sym) / sizeof(struct Symbol);
int a, lo = 0, mid, hi = N - 1;
size_t lenMatch, lenComp;
lenMatch = end - str;
while(lo <= hi) {
mid = (lo + hi) >> 1;
/* this is highly inefficient */
lenComp = strlen(sym[mid].symbol);
a = strncmp(str, sym[mid].symbol,
lenMatch > lenComp ? lenMatch : lenComp);
if (a < 0) hi = mid - 1;
else if(a > 0) lo = mid + 1;
else return &sym[mid];
}
return 0;
}

View File

@ -1,7 +1,14 @@
/** See \see{Parser}. */
struct Parser; struct Parser;
/** Dependancy on {Files} */
struct Files; struct Files;
/** All {ParserWidget}s are in {Widget.c} */
typedef int (*ParserWidget)(const struct Files *, FILE *fp);
struct Parser *Parser(const char *str); struct Parser *Parser(const char *str);
void Parser_(struct Parser *p); void Parser_(struct Parser **const p_ptr);
void ParserRewind(struct Parser *p); void ParserRewind(struct Parser *p);
int ParserParse(struct Parser *p, const struct Files *f, int invisible, FILE *fp); int ParserParse(struct Parser *p, const struct Files *f, int invisible,
FILE *fp);

View File

@ -1,11 +1,52 @@
/** Copyright 2008, 2012 Neil Edelman, distributed under the terms of the /** Copyright 2008, 2012 Neil Edelman, distributed under the terms of the
GNU General Public License, see copying.txt GNU General Public License, see copying.txt
This is the main program. I didn't know what to call it. {MakeIndex} is a simple content management system that generates static
content, (mostly index.html,) on all the directories rooted at the directory
specified by the argument. It is based on a template file, ".index.html" and
".newsfeed.rss". Also included are files to summarise the directory structure
for a {xml} site map, compatible with Google, and any {.news} for an {rss}
feed. It takes one argument, <directory>, which is the root of the recursion.
There should be an <example> directory that has a bunch of files in it. Run
{bin/MakeIndex example/}; it should make a webpage out of the directory
structure and {.index.html}, open {example/index.html} after running to see.
* If the {.index.html} file exists in the <directory>, prints <index.html>
recursively; overwrites any {index.html} on all the directories rooted at
<directory>;
* if the {.sitemap.xml} file exists in <directory>, prints (and overwrites) an
index called {sitemap.xml};
* if the {.newsfeed.rss} file exists in <directory>, prints (and overwrites)
to {newsfeed.rss} all the {.news} files (if there are any.)
* Treats {.d} as a description of the file without the {.d};
if this is an empty text-file or a zero-byte file, it skips over this file.
* treats {index.d} as a description of the directory;
* treats {content.d} as an in-depth description of the directory,
replacing <index.d> when in the directory;
* treats {.d.jpg} as a image that will go with the description;
* treats {.news} as a newsworthy item; the format of this file is ISO 8601
date (YYYY-MM-DD,) next line title;
* treats {.link} as a link with the href in the file.
{.index.html}, {.sitemap.xml}, {.newsfeed.rss}, see {Parser} for recognised
symbols. Assumes '..' is the parent directory, '.' is the current directory,
and '/' is the directory separator; works for UNIX, MacOS, Windows.
If this is not the case, the constants are in {Files.c}.
@title Parser
@author Neil @author Neil
@version 1.0; 2016-09-19 Added umask @std C89/90
@since 1.0; 2008-03-27 */ @version 1.1; 2017-03 fixed pedantic warnings; took out arg
@since 1.0; 2016-09-19 Added umask
0.8; 2013-07 case-insensitive sort
0.7; 2012 sth.dsth.d handled properly
0.6; 2008-03-27
@fixme Don't have <directory> be an argument; just do it in the current.
@fixme Have a subset of LaTeX converted into html for the .d files?
@fixme Encoding is an issue; especially the newsfeed, 7bit.
@fixme It's not robust; eg @(files){@(files){Don't do this.}}. */
#include <stdlib.h> /* malloc free fgets */ #include <stdlib.h> /* malloc free fgets */
#include <stdio.h> /* fprintf FILE */ #include <stdio.h> /* fprintf FILE */
@ -38,7 +79,7 @@ void usage(const char *programme);
/* constants */ /* constants */
static const int versionMajor = 0; static const int versionMajor = 0;
static const int versionMinor = 8; static const int versionMinor = 8;
static const int granularity = 1024; static const size_t granularity= 1024;
static const int maxRead = 0x1000; static const int maxRead = 0x1000;
const char *htmlIndex = "index.html"; /* in multiple files */ const char *htmlIndex = "index.html"; /* in multiple files */
static const char *xmlSitemap = "sitemap.xml"; static const char *xmlSitemap = "sitemap.xml";
@ -50,15 +91,15 @@ static const char *tmplNewsfeed= ".newsfeed.rss";
extern const char *dirCurrent; extern const char *dirCurrent;
extern const char *dirParent; extern const char *dirParent;
/* in Widget.c */ /* in Widget.c */
extern const char *desc; extern const char *dot_desc;
extern const char *news; extern const char *dot_news;
/* there can only be one recursor at a time, sorry */ /* there can only be one recursor at a time, sorry */
static struct Recursor *r = 0; static struct Recursor *r = 0;
/* public */ /* public */
struct Recursor *Recursor(const char *index, const char *map, const char *news) { struct Recursor *Recursor(const char *idx, const char *map, const char *news) {
if(!index || !index || !map || !news) return 0; if(!idx || !idx || !map || !news) return 0;
if(r) { fprintf(stderr, "Recursor: there is already a Recursor.\n"); return 0; } if(r) { fprintf(stderr, "Recursor: there is already a Recursor.\n"); return 0; }
r = malloc(sizeof(struct Recursor)); r = malloc(sizeof(struct Recursor));
if(!r) { perror("recursor"); Recursor_(); return 0; } if(!r) { perror("recursor"); Recursor_(); return 0; }
@ -74,8 +115,8 @@ struct Recursor *Recursor(const char *index, const char *map, const char *news)
if(!(r->sitemap = fopen(xmlSitemap, "w"))) perror(xmlSitemap); if(!(r->sitemap = fopen(xmlSitemap, "w"))) perror(xmlSitemap);
if(!(r->newsfeed = fopen(rssNewsfeed, "w"))) perror(rssNewsfeed); if(!(r->newsfeed = fopen(rssNewsfeed, "w"))) perror(rssNewsfeed);
/* read from the input files */ /* read from the input files */
if( !(r->indexString = readFile(index))) { if( !(r->indexString = readFile(idx))) {
fprintf(stderr, "Recursor: to make an index, create the file <%s>.\n", index); fprintf(stderr, "Recursor: to make an index, create the file <%s>.\n", idx);
} }
if(r->sitemap && !(r->sitemapString = readFile(map))) { if(r->sitemap && !(r->sitemapString = readFile(map))) {
fprintf(stderr, "Recursor: to make an sitemap, create the file <%s>.\n", map); fprintf(stderr, "Recursor: to make an sitemap, create the file <%s>.\n", map);
@ -85,7 +126,7 @@ struct Recursor *Recursor(const char *index, const char *map, const char *news)
} }
/* create Parsers attached to them */ /* create Parsers attached to them */
if(r->indexString && !(r->indexParser = Parser(r->indexString))) { if(r->indexString && !(r->indexParser = Parser(r->indexString))) {
fprintf(stderr, "Recursor: error generating Parser from <%s>.\n", index); fprintf(stderr, "Recursor: error generating Parser from <%s>.\n", idx);
} }
if(r->sitemapString && !(r->sitemapParser = Parser(r->sitemapString))) { if(r->sitemapString && !(r->sitemapParser = Parser(r->sitemapString))) {
fprintf(stderr, "Recursor: error generating Parser from <%s>.\n", map); fprintf(stderr, "Recursor: error generating Parser from <%s>.\n", map);
@ -117,11 +158,11 @@ void Recursor_(void) {
ParserParse(r->newsfeedParser, 0, 0, r->newsfeed); ParserParse(r->newsfeedParser, 0, 0, r->newsfeed);
} }
if(r->newsfeed && fclose(r->newsfeed)) perror(rssNewsfeed); if(r->newsfeed && fclose(r->newsfeed)) perror(rssNewsfeed);
Parser_(r->indexParser); Parser_(&r->indexParser);
free(r->indexString); free(r->indexString);
Parser_(r->sitemapParser); Parser_(&r->sitemapParser);
free(r->sitemapString); free(r->sitemapString);
Parser_(r->newsfeedParser); Parser_(&r->newsfeedParser);
free(r->newsfeedString); free(r->newsfeedString);
free(r); free(r);
r = 0; r = 0;
@ -137,7 +178,7 @@ int main(int argc, char **argv) {
if(chdir(argv[1])) { perror(argv[1]); return EXIT_FAILURE; } if(chdir(argv[1])) { perror(argv[1]); return EXIT_FAILURE; }
/* make sure that umask is set so that others can read what we create */ /* make sure that umask is set so that others can read what we create */
umask(S_IWGRP | S_IWOTH); umask((mode_t)(S_IWGRP | S_IWOTH));
/* recursing; fixme: this should be configurable */ /* recursing; fixme: this should be configurable */
if(!Recursor(tmplIndex, tmplSitemap, tmplNewsfeed)) return EXIT_FAILURE; if(!Recursor(tmplIndex, tmplSitemap, tmplNewsfeed)) return EXIT_FAILURE;
@ -153,13 +194,13 @@ int filter(const struct Files *files, const char *fn) {
FILE *fd; FILE *fd;
if(!r) { fprintf(stderr, "Recusor::filter: recursor not initialised.\n"); return 0; } if(!r) { fprintf(stderr, "Recusor::filter: recursor not initialised.\n"); return 0; }
/* *.d[.0]* */ /* *.d[.0]* */
for(str = (char *)fn; (str = strstr(str, desc)); ) { for(str = (char *)fn; (str = strstr(str, dot_desc)); ) {
str += strlen(desc); str += strlen(dot_desc);
if(*str == '\0' || *str == '.') return 0; if(*str == '\0' || *str == '.') return 0;
} }
/* *.news$ */ /* *.news$ */
if((str = strstr(fn, news))) { if((str = strstr(fn, dot_news))) {
str += strlen(news); str += strlen(dot_news);
if(*str == '\0') { if(*str == '\0') {
if(WidgetSetNews(fn) && ParserParse(r->newsfeedParser, files, 0, r->newsfeed)) { if(WidgetSetNews(fn) && ParserParse(r->newsfeedParser, files, 0, r->newsfeed)) {
ParserRewind(r->newsfeedParser); ParserRewind(r->newsfeedParser);
@ -176,12 +217,12 @@ int filter(const struct Files *files, const char *fn) {
/* index.html */ /* index.html */
if(!strcmp(fn, htmlIndex)) return 0; if(!strcmp(fn, htmlIndex)) return 0;
/* add .d, check 1 line for \n (hmm, this must be a real time waster) */ /* add .d, check 1 line for \n (hmm, this must be a real time waster) */
if(strlen(fn) > sizeof(filed) - strlen(desc) - 1) { if(strlen(fn) > sizeof(filed) - strlen(dot_desc) - 1) {
fprintf(stderr, "Recusor::filter: regected '%s' because it was too long (%d.)\n", fn, (int)sizeof(filed)); fprintf(stderr, "Recusor::filter: regected '%s' because it was too long (%d.)\n", fn, (int)sizeof(filed));
return 0; return 0;
} }
strcpy(filed, fn); strcpy(filed, fn);
strcat(filed, desc); strcat(filed, dot_desc);
if((fd = fopen(filed, "r"))) { if((fd = fopen(filed, "r"))) {
int ch = fgetc(fd); int ch = fgetc(fd);
if(ch == '\n' || ch == '\r' || ch == EOF) { if(ch == '\n' || ch == '\r' || ch == EOF) {
@ -223,7 +264,7 @@ int recurse(const struct Files *parent) {
} }
char *readFile(const char *filename) { char *readFile(const char *filename) {
char *buf = 0, *newBuf; char *buf = 0, *newBuf;
int bufPos = 0, bufSize = 0, read; size_t bufPos = 0, bufSize = 0, rd;
FILE *fp; FILE *fp;
if(!filename) return 0; if(!filename) return 0;
if(!(fp = fopen(filename, "r"))) { perror(filename); return 0; } if(!(fp = fopen(filename, "r"))) { perror(filename); return 0; }
@ -231,11 +272,12 @@ char *readFile(const char *filename) {
newBuf = realloc(buf, (bufSize += granularity) * sizeof(char)); newBuf = realloc(buf, (bufSize += granularity) * sizeof(char));
if(!newBuf) { perror(filename); free(buf); return 0; } if(!newBuf) { perror(filename); free(buf); return 0; }
buf = newBuf; buf = newBuf;
read = fread(buf + bufPos, sizeof(char), granularity, fp); rd = fread(buf + bufPos, sizeof(char), granularity, fp);
bufPos += read; bufPos += rd;
if(read < granularity) { buf[bufPos] = '\0'; break; } if(rd < granularity) { buf[bufPos] = '\0'; break; }
} }
fprintf(stderr, "Opened '%s' and alloted %d bytes to read %d characters.\n", filename, bufSize, bufPos); fprintf(stderr, "Opened '%s' and alloted %lu bytes to read %lu "
"characters.\n", filename, bufSize, bufPos);
if(fclose(fp)) perror(filename); if(fclose(fp)) perror(filename);
return buf; /** you must free() the memory! */ return buf; /** you must free() the memory! */
} }

View File

@ -1,13 +1,18 @@
/* Copyright 2008, 2012 Neil Edelman, distributed under the terms of the /* Copyright 2008, 2012 Neil Edelman, distributed under the terms of the
GNU General Public License, see copying.txt */ GNU General Public License, see copying.txt
/* Widgets like @files @pwd. How to create a widget? Widgets like @files @pwd. To create a widget:
1. stick the code below, it's prototype must be the same, int(FILE *), where
the FILE* is called with the output file * stick the code below implementing {ParserWidget};
2. create a prototype in Widget.h * create a prototype in Widget.h;
3. in Parser.c, add to the symbol table, sym[] with the symbol you want, in * in {Parser.c}, add to the symbol table, sym[] with the symbol you want, in
ASCIIbetical order ASCIIbetical order.
* Created by Neil Edelman on 2008-03-25. */
@title Widget
@author Neil
@std C89/90
@version 1.1; 2017-03 fixed pedantic warnings; took out arg
@since 0.6; 2008-03-25 */
#include <string.h> /* strncat strncpy */ #include <string.h> /* strncat strncpy */
#include <stdio.h> /* fprintf FILE */ #include <stdio.h> /* fprintf FILE */
@ -17,15 +22,28 @@
#include "Recursor.h" #include "Recursor.h"
#include "Widget.h" #include "Widget.h"
/* <-- ugly */
#ifndef _MSC_VER /* <-- not msvc */
#define UNUSED(a) while(0 && (a))
#else /* not msvc --><-- msvc: not a C89/90 compiler; needs a little help */
#pragma warning(push)
/* "Assignment within conditional expression." No. */
#pragma warning(disable: 4706)
/* "<ANSI/ISO name>: The POSIX name for this item is deprecated." No. */
#pragma warning(disable: 4996)
#define UNUSED(a) (void)(sizeof((a), 0))
#endif /* msvc --> */
/* ugly --> */
/* constants */ /* constants */
static const char *htmlDesc = "index.d"; static const char *htmlDesc = "index.d";
static const char *htmlContent = "content.d"; static const char *htmlContent = "content.d";
static const char *separator = "/"; static const char *separator = "/";
static const char *picture = ".jpeg"; /* yeah, I hard coded this */ static const char *picture = ".jpeg"; /* yeah, I hard coded this */
static const size_t maxRead = 512; static const size_t maxRead = 512;
static const char *link = ".link"; static const char *dot_link = ".link";
const char *desc = ".d"; /* used in multiple files */ const char *dot_desc = ".d"; /* used in multiple files */
const char *news = ".news"; const char *dot_news = ".news";
extern const char *dirCurrent; extern const char *dirCurrent;
extern const char *dirParent; extern const char *dirParent;
extern const char *htmlIndex; extern const char *htmlIndex;
@ -38,15 +56,17 @@ static char title[64] = "(no title)";
static char filenews[64] = "(no file name)"; static char filenews[64] = "(no file name)";
/* private */ /* private */
int correctNo(int no, const int low, const int high); int clip(int no, const int low, const int high);
int WidgetSetNews(const char *fn) { int WidgetSetNews(const char *fn) {
char *dot; char *dot;
int read, tLen; int read;
size_t tLen;
FILE *fp; FILE *fp;
if(!fn || !(dot = strstr(fn, news))) return 0; if(!fn || !(dot = strstr(fn, dot_news))) return 0;
if(strlen(fn) > sizeof(filenews) / sizeof(char) - sizeof(char)) { if(strlen(fn) > sizeof(filenews) / sizeof(char) - sizeof(char)) {
fprintf(stderr, "Widget::SetNews: news file name, \"%s,\" doesn't fit in buffer (%d.)\n", fn, (int)(sizeof(filenews) / sizeof(char))); fprintf(stderr, "Widget::SetNews: news file name, \"%s,\" doesn't fit "
"in buffer (%d.)\n", fn, (int)(sizeof(filenews) / sizeof(char)));
return 0; return 0;
} }
/* save the fn, safe because we checked it, and strip off .news */ /* save the fn, safe because we checked it, and strip off .news */
@ -55,44 +75,56 @@ int WidgetSetNews(const char *fn) {
/* open .news */ /* open .news */
if(!(fp = fopen(fn, "r"))) { perror(fn); return 0; } if(!(fp = fopen(fn, "r"))) { perror(fn); return 0; }
read = fscanf(fp, "%d-%d-%d\n", &year, &month, &day); read = fscanf(fp, "%d-%d-%d\n", &year, &month, &day);
if(read < 3) fprintf(stderr, "Widget::setNews: error parsing ISO 8601 date, <YYYY-MM-DD>.\n"); if(read < 3) fprintf(stderr, "Widget::setNews: error parsing ISO 8601 "
month = correctNo(month, 1, 12); "date, <YYYY-MM-DD>.\n");
day = correctNo(day, 1, 31); month = clip(month, 1, 12);
day = clip(day, 1, 31);
/* fgets reads a newline at the end (annoying) so we strip that off */ /* fgets reads a newline at the end (annoying) so we strip that off */
if(!fgets(title, sizeof(title), fp)) { perror(fn); *title = '\0'; } if(!fgets(title, (int)sizeof(title), fp)) { perror(fn); *title = '\0'; }
else if((tLen = strlen(title)) > 0 && title[tLen - 1] == '\n') title[tLen - 1] = '\0'; else if((tLen = strlen(title)) > 0 && title[tLen - 1] == '\n')
title[tLen - 1] = '\0';
if(fclose(fp)) perror(fn); if(fclose(fp)) perror(fn);
fprintf(stderr, "News <%s>, '%s' %d-%d-%d.\n", filenews, title, year, month, day); fprintf(stderr, "News <%s>, '%s' %d-%d-%d.\n", filenews, title, year,
month, day);
return -1; return -1;
} }
/* the widget handlers */ /* the widget handlers */
/** @implements ParserWidget */
int WidgetContent(const struct Files *f, FILE *fp) { int WidgetContent(const struct Files *f, FILE *fp) {
char buf[81], *bufpos; char buf[81], *bufpos;
int i; size_t i;
FILE *in; FILE *in;
UNUSED(f);
/* it's a nightmare to test if this is text (which most is,) in which case /* it's a nightmare to test if this is text (which most is,) in which case
we should insert <p>...</p> after every paragraph, <>& -> &lt;&gt;&amp;, we should insert <p>...</p> after every paragraph, <>& -> &lt;&gt;&amp;,
but we have to not translate already encoded html; the only solution that but we have to not translate already encoded html; the only solution that
a could see is have a new langauge (like-LaTeX) that gracefully handles a could see is have a new langauge (like-LaTeX) that gracefully handles
plain-text */ plain-text */
if((in = fopen(htmlContent, "r")) || (in = fopen(htmlDesc, "r"))) { if((in = fopen(htmlContent, "r")) || (in = fopen(htmlDesc, "r"))) {
for(i = 0; (i < maxRead) && (bufpos = fgets(buf, sizeof(buf), in)); i++) { for(i = 0; (i < maxRead)
&& (bufpos = fgets(buf, (int)sizeof(buf), in)); i++) {
fprintf(fp, "%s", bufpos); fprintf(fp, "%s", bufpos);
} }
if(fclose(in)) perror(htmlDesc); if(fclose(in)) perror(htmlDesc);
} }
return 0; return 0;
} }
/** @implements ParserWidget */
int WidgetDate(const struct Files *f, FILE *fp) { int WidgetDate(const struct Files *f, FILE *fp) {
UNUSED(f);
/* ISO 8601 - YYYY-MM-DD */ /* ISO 8601 - YYYY-MM-DD */
fprintf(fp, "%4.4d-%2.2d-%2.2d", year, month, day); fprintf(fp, "%4.4d-%2.2d-%2.2d", year, month, day);
return 0; return 0;
} }
/** @implements ParserWidget */
int WidgetFilealt(const struct Files *f, FILE *fp) { int WidgetFilealt(const struct Files *f, FILE *fp) {
fprintf(fp, "%s", FilesIsDir(f) ? "Dir" : "File"); fprintf(fp, "%s", FilesIsDir(f) ? "Dir" : "File");
return 0; return 0;
} }
/** @implements ParserWidget */
int WidgetFiledesc(const struct Files *f, FILE *fp) { int WidgetFiledesc(const struct Files *f, FILE *fp) {
char buf[256], *name; char buf[256], *name;
FILE *in; FILE *in;
@ -100,29 +132,32 @@ int WidgetFiledesc(const struct Files *f, FILE *fp) {
if(FilesIsDir(f)) { if(FilesIsDir(f)) {
/* <file>/index.d */ /* <file>/index.d */
strncpy(buf, name, sizeof(buf) - 9); strncpy(buf, name, sizeof(buf) - 9);
strncat(buf, separator, 1); strncat(buf, separator, 1lu);
strncat(buf, htmlDesc, 7); strncat(buf, htmlDesc, 7lu);
} else { } else {
/* <file>.d */ /* <file>.d */
strncpy(buf, name, sizeof(buf) - 6); strncpy(buf, name, sizeof(buf) - 6);
strncat(buf, desc, 5); strncat(buf, dot_desc, 5lu);
} }
if((in = fopen(buf, "r"))) { if((in = fopen(buf, "r"))) {
char *bufpos; char *bufpos;
int i; size_t i;
for(i = 0; (i < maxRead) && (bufpos = fgets(buf, sizeof(buf), in)); i++) { for(i = 0; (i < maxRead)
&& (bufpos = fgets(buf, (int)sizeof(buf), in)); i++) {
fprintf(fp, "%s", bufpos); fprintf(fp, "%s", bufpos);
} }
if(fclose(in)) perror(buf); if(fclose(in)) perror(buf);
} }
return 0; return 0;
} }
/** @implements ParserWidget */
int WidgetFilehref(const struct Files *f, FILE *fp) { int WidgetFilehref(const struct Files *f, FILE *fp) {
char *str, *name; char *str, *name;
int ch; int ch;
FILE *fhref; FILE *fhref;
if(!(name = FilesName(f))) return 0; if(!(name = FilesName(f))) return 0;
if((str = strstr(name, link)) && *(str += strlen(link)) == '\0' && (fhref = fopen(name, "r"))) { if((str = strstr(name, dot_link)) && *(str += strlen(dot_link)) == '\0'
&& (fhref = fopen(name, "r"))) {
/* fixme: not too good, with the reading one char at a time */ /* fixme: not too good, with the reading one char at a time */
for( ; ; ) { for( ; ; ) {
ch = fgetc(fhref); ch = fgetc(fhref);
@ -135,14 +170,15 @@ int WidgetFilehref(const struct Files *f, FILE *fp) {
} }
return 0; return 0;
} }
/** @implements ParserWidget */
int WidgetFileicon(const struct Files *f, FILE *fp) { int WidgetFileicon(const struct Files *f, FILE *fp) {
char buf[256], *name; char buf[256], *name;
FILE *in; FILE *in;
if(!(name = FilesName(f))) return 0; if(!(name = FilesName(f))) return 0;
/* insert <file>.d.jpeg if available */ /* insert <file>.d.jpeg if available */
strncpy(buf, name, sizeof(buf) - 12); strncpy(buf, name, sizeof(buf) - 12);
strncat(buf, desc, 5); strncat(buf, dot_desc,5lu);
strncat(buf, picture, 6); strncat(buf, picture, 6lu);
if((in = fopen(buf, "r"))) { if((in = fopen(buf, "r"))) {
fprintf(fp, "%s", buf); fprintf(fp, "%s", buf);
if(fclose(in)) perror(buf); if(fclose(in)) perror(buf);
@ -158,44 +194,57 @@ int WidgetFileicon(const struct Files *f, FILE *fp) {
} }
return 0; return 0;
} }
/** @implements ParserWidget */
int WidgetFilename(const struct Files *f, FILE *fp) { int WidgetFilename(const struct Files *f, FILE *fp) {
fprintf(fp, "%s", FilesName(f)); fprintf(fp, "%s", FilesName(f));
return 0; return 0;
} }
/** @implements ParserWidget */
int WidgetFiles(const struct Files *f, FILE *fp) { int WidgetFiles(const struct Files *f, FILE *fp) {
while(0 && fp);
return FilesAdvance((struct Files *)f) ? -1 : 0; return FilesAdvance((struct Files *)f) ? -1 : 0;
} }
/** @implements ParserWidget */
int WidgetFilesize(const struct Files *f, FILE *fp) { /* eww */ int WidgetFilesize(const struct Files *f, FILE *fp) { /* eww */
if(!FilesIsDir(f)) fprintf(fp, " (%d KB)", FilesSize(f)); if(!FilesIsDir(f)) fprintf(fp, " (%d KB)", FilesSize(f));
return 0; return 0;
} }
/** @implements ParserWidget */
int WidgetNews(const struct Files *f, FILE *fp) { int WidgetNews(const struct Files *f, FILE *fp) {
char buf[256], *bufpos; char buf[256], *bufpos;
int i; size_t i;
FILE *in; FILE *in;
UNUSED(f);
if(!filenews[0]) return 0; if(!filenews[0]) return 0;
if(!(in = fopen(filenews, "r"))) { perror(filenews); return 0; } if(!(in = fopen(filenews, "r"))) { perror(filenews); return 0; }
for(i = 0; (i < maxRead) && (bufpos = fgets(buf, sizeof(buf), in)); i++) { for(i = 0; (i < maxRead)&&(bufpos = fgets(buf, (int)sizeof(buf), in)); i++){
fprintf(fp, "%s", bufpos); fprintf(fp, "%s", bufpos);
} }
if(fclose(in)) perror(filenews); if(fclose(in)) perror(filenews);
return 0; return 0;
} }
/** @implements ParserWidget */
int WidgetNewsname(const struct Files *f, FILE *fp) { int WidgetNewsname(const struct Files *f, FILE *fp) {
UNUSED(f);
fprintf(fp, "%s", filenews); fprintf(fp, "%s", filenews);
return 0; return 0;
} }
/** @implements ParserWidget */
int WidgetNow(const struct Files *f, FILE *fp) { int WidgetNow(const struct Files *f, FILE *fp) {
char t[22]; char t[22];
time_t currentTime; time_t currentTime;
struct tm *formatedTime; struct tm *formatedTime;
UNUSED(f);
if((currentTime = time(0)) == (time_t)(-1)) { perror("@date"); return 0; } if((currentTime = time(0)) == (time_t)(-1)) { perror("@date"); return 0; }
formatedTime = gmtime(&currentTime); formatedTime = gmtime(&currentTime);
/* ISO 8601 - YYYY-MM-DDThh:mm:ssTZD */ /* ISO 8601 - YYYY-MM-DDThh:mm:ssTZD */
strftime(t, 21, "%Y-%m-%dT%H:%M:%SZ", formatedTime); strftime(t, 21lu, "%Y-%m-%dT%H:%M:%SZ", formatedTime);
fprintf(fp, "%s", t); fprintf(fp, "%s", t);
return 0; return 0;
} }
/** @implements ParserWidget */
int WidgetPwd(const struct Files *f, FILE *fp) { int WidgetPwd(const struct Files *f, FILE *fp) {
static int persistant = 0; /* ick, be very careful! */ static int persistant = 0; /* ick, be very careful! */
char *pwd; char *pwd;
@ -205,6 +254,7 @@ int WidgetPwd(const struct Files *f, FILE *fp) {
fprintf(fp, "%s", pwd); fprintf(fp, "%s", pwd);
return -1; return -1;
} }
/** @implements ParserWidget */
int WidgetRoot(const struct Files *f, FILE *fp) { int WidgetRoot(const struct Files *f, FILE *fp) {
static int persistant = 0; /* ick, be very careful! */ static int persistant = 0; /* ick, be very careful! */
char *pwd; char *pwd;
@ -214,12 +264,14 @@ int WidgetRoot(const struct Files *f, FILE *fp) {
fprintf(fp, "%s", dirParent); fprintf(fp, "%s", dirParent);
return -1; return -1;
} }
/** @implements ParserWidget */
int WidgetTitle(const struct Files *f, FILE *fp) { int WidgetTitle(const struct Files *f, FILE *fp) {
UNUSED(f);
fprintf(fp, "%s", title); fprintf(fp, "%s", title);
return 0; return 0;
} }
int correctNo(int no, const int low, const int high) { int clip(int no, const int low, const int high) {
if(no < low) no = low; if(no < low) no = low;
else if(no > high) no = high; else if(no > high) no = high;
return no; return no;