From 7613e60e8636b4373f3b35b6df1a3518c2f01062 Mon Sep 17 00:00:00 2001 From: Neil Edelman Date: Sun, 26 Mar 2017 04:47:35 -0400 Subject: [PATCH] Fixed a lot. --- Makefile.mingw | 37 -------- doc/Files.html | 40 ++++----- doc/Parser.html | 90 +++++++++++++++++--- doc/Recursor.html | 85 +++++++++++++++++-- doc/Widget.html | 210 ++++++++++++++++++++++++++++++++++++++++++++++ src/Files.c | 19 ++--- src/Files.h | 1 - src/Parser.c | 117 +++++++++++++++++++------- src/Parser.h | 11 ++- src/Recursor.c | 98 +++++++++++++++------- src/Widget.c | 122 +++++++++++++++++++-------- 11 files changed, 640 insertions(+), 190 deletions(-) delete mode 100644 Makefile.mingw diff --git a/Makefile.mingw b/Makefile.mingw deleted file mode 100644 index 257186f..0000000 --- a/Makefile.mingw +++ /dev/null @@ -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) diff --git a/doc/Files.html b/doc/Files.html index a1ae360..0d7ba02 100644 --- a/doc/Files.html +++ b/doc/Files.html @@ -41,22 +41,22 @@

Copyright 2008, 2012 Neil Edelman, distributed under the terms of the - GNU General Public License, see copying.txt, or - https://opensource.org/licenses/GPL-3.0. +GNU General Public License, see copying.txt, or +https://opensource.org/licenses/GPL-3.0.

- 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.) +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.)

-
author:
+
minimum standard
+
C89/90
+
author
Neil
-
version:
-
0.9; 2017-03 fixed pedantic warnings
-
since:
-
0.8; 2013-07 case-insensitive sort - 0.7; 2012 sth.dsth.d handled properly - 0.6; 2008-03-24
+
version
+
1.1; 2017-03 fixed pedantic warnings; took out arg
+
since
+
0.6; 2008-03-24
@@ -200,12 +200,8 @@ After FilesSetFarourite, this enumerates them.

FilesName

char * FilesName (const struct Files *files)
-

-

-

-

-
return:
+
return
The file name of the selected file.
@@ -213,12 +209,8 @@ After FilesSetFarourite, this enumerates them.

FilesSize

int FilesSize (const struct Files *files)
-

-

-

-

-
return:
+
return
File size of the selected file.
@@ -226,12 +218,8 @@ After FilesSetFarourite, this enumerates them.

FilesIsDir

int FilesIsDir (const struct Files *files)
-

-

-

-

-
return:
+
return
Whether the file is a directory.
diff --git a/doc/Parser.html b/doc/Parser.html index 51c7d8a..befce96 100644 --- a/doc/Parser.html +++ b/doc/Parser.html @@ -45,31 +45,90 @@

Declarations

+
+

struct Parser

+
struct Parser
+

+See Parser. +

+
+
+
+ +
+

struct Files

+
struct Files
+

+Dependancy on Files +

+
+
+
+ +
+

typedef int (*ParserWidget)(const struct Files *, FILE *fp)

+
typedef int (*ParserWidget)(const struct Files *, FILE *fp)
+

+All ParserWidgets are in Widget.c +

+
+
+
+

Function Summary

- - - + + + + + + + + + + + + + - +
Return TypeFunction NameArgument List
const struct Symbol *matchconst char *str, const char *endstruct Parser *Parserconst char *str
voidParser_struct Parser **const p_ptr
voidParserRewindstruct Parser *p
int ParserParsestruct Parser *p, const struct Files *f, int invisible, FILE *fpstruct Parser *p, const struct Files *f, int invisible, + FILE *fp

Function Detail

-
-

match

-
const struct Symbol * match (const char *str, const char *end)
+
+

Parser

+
struct Parser * Parser (const char *str)
+
+
return
+
Creates a parser for the string, str.
+
+
+ +
+

Parser_

+
void Parser_ (struct Parser **const p_ptr)
+
+
parameter: p_ptr
+
A pointer to the Parser that's to be destucted.
+
+
+ +
+

ParserRewind

+
void ParserRewind (struct Parser *p)

-binary search +Resets the parser, p.

@@ -77,11 +136,22 @@ binary search

ParserParse

-
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)

-parse, called recusively (invisible, hack) fixme: this fn needs rewriting, messy +Parse, called recursively.

+
parameter: f
+
Called in the handler to ParserWidgets.
+
parameter: invisible
+
No output.
+
parameter: fp
+
Output.
+
fixme
+
This fn needs rewriting; messy.
+
fixme
+
Invisible, hack.
diff --git a/doc/Recursor.html b/doc/Recursor.html index 7271a25..04aa1a4 100644 --- a/doc/Recursor.html +++ b/doc/Recursor.html @@ -25,13 +25,13 @@ padding: 4px; } - +Parser -

+

Parser

  • Declarations
  • @@ -41,18 +41,85 @@

    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.

    -
    author:
    +
    minimum standard
    +
    C89/90
    +
    author
    Neil
    -
    version:
    -
    1.0; 2016-09-19 Added umask
    -
    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.}.
    diff --git a/doc/Widget.html b/doc/Widget.html index 57ce3f3..4dc6f34 100644 --- a/doc/Widget.html +++ b/doc/Widget.html @@ -50,11 +50,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Return TypeFunction NameArgument List
    intWidgetContentconst struct Files *f, FILE *fp
    intWidgetDateconst struct Files *f, FILE *fp
    intWidgetFilealtconst struct Files *f, FILE *fp
    intWidgetFiledescconst struct Files *f, FILE *fp
    intWidgetFilehrefconst struct Files *f, FILE *fp
    intWidgetFileiconconst struct Files *f, FILE *fp
    intWidgetFilenameconst struct Files *f, FILE *fp
    intWidgetFilesconst struct Files *f, FILE *fp
    intWidgetFilesizeconst struct Files *f, FILE *fp
    intWidgetNewsconst struct Files *f, FILE *fp
    intWidgetNewsnameconst struct Files *f, FILE *fp
    intWidgetNowconst struct Files *f, FILE *fp
    intWidgetPwdconst struct Files *f, FILE *fp
    intWidgetRootconst struct Files *f, FILE *fp
    intWidgetTitleconst struct Files *f, FILE *fp

    Function Detail

    +
    +

    WidgetContent

    +
    int WidgetContent (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetDate

    +
    int WidgetDate (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetFilealt

    +
    int WidgetFilealt (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetFiledesc

    +
    int WidgetFiledesc (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetFilehref

    +
    int WidgetFilehref (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetFileicon

    +
    int WidgetFileicon (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetFilename

    +
    int WidgetFilename (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetFiles

    +
    int WidgetFiles (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetFilesize

    +
    int WidgetFilesize (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetNews

    +
    int WidgetNews (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetNewsname

    +
    int WidgetNewsname (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetNow

    +
    int WidgetNow (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetPwd

    +
    int WidgetPwd (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetRoot

    +
    int WidgetRoot (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + +
    +

    WidgetTitle

    +
    int WidgetTitle (const struct Files *f, FILE *fp)
    +
    +
    implements
    +
    ParserWidget
    +
    +
    + diff --git a/src/Files.c b/src/Files.c index 5cf7805..0eb8548 100644 --- a/src/Files.c +++ b/src/Files.c @@ -5,12 +5,11 @@ 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.) - @file Files + @title Files @author Neil - @version 0.9; 2017-03 fixed pedantic warnings - @since 0.8; 2013-07 case-insensitive sort - 0.7; 2012 sth.dsth.d handled properly - 0.6; 2008-03-24 */ + @std C89/90 + @version 1.1; 2017-03 fixed pedantic warnings; took out arg + @since 0.6; 2008-03-24 */ #include /* malloc free */ #include /* fprintf */ @@ -20,9 +19,9 @@ #include "Files.h" /* constants */ -const char *dirCurrent = "."; /* used in multiple files */ -const char *dirParent = ".."; -static const int maxFilename = 128; +const char *dirCurrent = "."; /* used in multiple files */ +const char *dirParent = ".."; +static const size_t maxFilename = 128; /* public */ struct Files { @@ -161,10 +160,10 @@ int FilesIsDir(const struct Files *files) { /* this is just a list of filenames, (not public) "class File" */ static struct File *File(const char *name, const int size, const int isDir) { - int len; + size_t len; struct File *file; 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)); if(!file) { File_(file); return 0; } file->next = 0; diff --git a/src/Files.h b/src/Files.h index de6ecd6..042f15b 100644 --- a/src/Files.h +++ b/src/Files.h @@ -1,6 +1,5 @@ /** See \see{Files}. */ struct Files; -struct Recursor; /** Returns a boolean value. */ typedef int (*FilesFilter)(const struct Files *, const char *); diff --git a/src/Parser.c b/src/Parser.c index c400116..7daee66 100644 --- a/src/Parser.c +++ b/src/Parser.c @@ -1,8 +1,43 @@ /* 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. - * Created by Neil Edelman on 2008-03-21. */ + Parsing of strings. '~' on a line by itself is recognised in ".newsfile.rss" + and ".sitemap.xml" as a ~~; 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 /* [f]printf FILE */ #include /* malloc */ @@ -22,11 +57,11 @@ struct Parser { }; /* private - this is the list of 'widgets', see Widget.c - add widgets to here to make them recognised - ASCIIbetical */ -struct Symbol { +static const struct Symbol { char *symbol; - int (*handler)(const struct Files *, FILE *fp); + const ParserWidget handler; int onlyInRoot; /* fixme: not used, just trust the users? haha */ -} static const sym[] = { +} sym[] = { { "content", &WidgetContent, 0 }, /* index */ { "date", &WidgetDate, 0 }, /* news */ { "filealt", &WidgetFilealt, 0 }, /* files */ @@ -41,54 +76,52 @@ struct Symbol { { "news", &WidgetNews, 0 }, /* news */ { "newsname", &WidgetNewsname, 0 }, /* news */ { "now", &WidgetNow, 0 }, /* any */ - { "pwd", &WidgetPwd, -1 }, /* don't put it where it doesn't make sense */ - { "root", &WidgetRoot, -1 }, /* like pwd exept up instead of dn */ + { "pwd", &WidgetPwd, -1 }, /* index */ + { "root", &WidgetRoot, -1 }, /* like pwd except up instead of dn */ { "title", &WidgetTitle, 0 } /* news */ }; /* 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 *p; - p = malloc(sizeof(struct Parser)); + if(!(p = malloc(sizeof *p))) return 0; p->str = (char *)str; p->pos = p->str; p->rew = p->str; p->recursion = 0; 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); free(p); + *p_ptr = 0; } -/** binary search */ -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; -} +/** Resets the parser, {p}. */ void ParserRewind(struct Parser *p) { if(!p) return; 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; 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; if(p->recursion == 1) p->rew = mark; for( ; ; ) { @@ -117,7 +150,8 @@ int ParserParse(struct Parser *p, const struct Files *f, int invisible, FILE *fp char *start = p->pos + 2, *end; if(!invisible) fprintf(fp, "%.*s", (int)(p->pos - mark), mark); 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; ? */ open = *(end + 1) == '{' ? -1 : 0; do { @@ -135,3 +169,22 @@ int ParserParse(struct Parser *p, const struct Files *f, int invisible, FILE *fp p->recursion--; 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; +} diff --git a/src/Parser.h b/src/Parser.h index 9baf1e8..aa47c9b 100644 --- a/src/Parser.h +++ b/src/Parser.h @@ -1,7 +1,14 @@ +/** See \see{Parser}. */ struct Parser; + +/** Dependancy on {Files} */ struct Files; +/** All {ParserWidget}s are in {Widget.c} */ +typedef int (*ParserWidget)(const struct Files *, FILE *fp); + struct Parser *Parser(const char *str); -void Parser_(struct Parser *p); +void Parser_(struct Parser **const p_ptr); 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); diff --git a/src/Recursor.c b/src/Recursor.c index 233487d..bc1242b 100644 --- a/src/Recursor.c +++ b/src/Recursor.c @@ -1,11 +1,52 @@ /** Copyright 2008, 2012 Neil Edelman, distributed under the terms of the 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, , which is the root of the recursion. + + There should be an 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 , prints + recursively; overwrites any {index.html} on all the directories rooted at + ; + * if the {.sitemap.xml} file exists in , prints (and overwrites) an + index called {sitemap.xml}; + * if the {.newsfeed.rss} file exists in , 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 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 - @version 1.0; 2016-09-19 Added umask - @since 1.0; 2008-03-27 */ + @std C89/90 + @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 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 /* malloc free fgets */ #include /* fprintf FILE */ @@ -38,7 +79,7 @@ void usage(const char *programme); /* constants */ static const int versionMajor = 0; static const int versionMinor = 8; -static const int granularity = 1024; +static const size_t granularity= 1024; static const int maxRead = 0x1000; const char *htmlIndex = "index.html"; /* in multiple files */ static const char *xmlSitemap = "sitemap.xml"; @@ -50,15 +91,15 @@ static const char *tmplNewsfeed= ".newsfeed.rss"; extern const char *dirCurrent; extern const char *dirParent; /* in Widget.c */ -extern const char *desc; -extern const char *news; +extern const char *dot_desc; +extern const char *dot_news; /* there can only be one recursor at a time, sorry */ static struct Recursor *r = 0; /* public */ -struct Recursor *Recursor(const char *index, const char *map, const char *news) { - if(!index || !index || !map || !news) return 0; +struct Recursor *Recursor(const char *idx, const char *map, const char *news) { + if(!idx || !idx || !map || !news) return 0; if(r) { fprintf(stderr, "Recursor: there is already a Recursor.\n"); return 0; } r = malloc(sizeof(struct Recursor)); 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->newsfeed = fopen(rssNewsfeed, "w"))) perror(rssNewsfeed); /* read from the input files */ - if( !(r->indexString = readFile(index))) { - fprintf(stderr, "Recursor: to make an index, create the file <%s>.\n", index); + if( !(r->indexString = readFile(idx))) { + fprintf(stderr, "Recursor: to make an index, create the file <%s>.\n", idx); } if(r->sitemap && !(r->sitemapString = readFile(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 */ 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))) { fprintf(stderr, "Recursor: error generating Parser from <%s>.\n", map); @@ -117,11 +158,11 @@ void Recursor_(void) { ParserParse(r->newsfeedParser, 0, 0, r->newsfeed); } if(r->newsfeed && fclose(r->newsfeed)) perror(rssNewsfeed); - Parser_(r->indexParser); + Parser_(&r->indexParser); free(r->indexString); - Parser_(r->sitemapParser); + Parser_(&r->sitemapParser); free(r->sitemapString); - Parser_(r->newsfeedParser); + Parser_(&r->newsfeedParser); free(r->newsfeedString); free(r); r = 0; @@ -137,7 +178,7 @@ int main(int argc, char **argv) { if(chdir(argv[1])) { perror(argv[1]); return EXIT_FAILURE; } /* 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 */ if(!Recursor(tmplIndex, tmplSitemap, tmplNewsfeed)) return EXIT_FAILURE; @@ -153,13 +194,13 @@ int filter(const struct Files *files, const char *fn) { FILE *fd; if(!r) { fprintf(stderr, "Recusor::filter: recursor not initialised.\n"); return 0; } /* *.d[.0]* */ - for(str = (char *)fn; (str = strstr(str, desc)); ) { - str += strlen(desc); + for(str = (char *)fn; (str = strstr(str, dot_desc)); ) { + str += strlen(dot_desc); if(*str == '\0' || *str == '.') return 0; } /* *.news$ */ - if((str = strstr(fn, news))) { - str += strlen(news); + if((str = strstr(fn, dot_news))) { + str += strlen(dot_news); if(*str == '\0') { if(WidgetSetNews(fn) && ParserParse(r->newsfeedParser, files, 0, r->newsfeed)) { ParserRewind(r->newsfeedParser); @@ -176,12 +217,12 @@ int filter(const struct Files *files, const char *fn) { /* index.html */ if(!strcmp(fn, htmlIndex)) return 0; /* 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)); return 0; } strcpy(filed, fn); - strcat(filed, desc); + strcat(filed, dot_desc); if((fd = fopen(filed, "r"))) { int ch = fgetc(fd); if(ch == '\n' || ch == '\r' || ch == EOF) { @@ -223,19 +264,20 @@ int recurse(const struct Files *parent) { } char *readFile(const char *filename) { char *buf = 0, *newBuf; - int bufPos = 0, bufSize = 0, read; + size_t bufPos = 0, bufSize = 0, rd; FILE *fp; if(!filename) return 0; if(!(fp = fopen(filename, "r"))) { perror(filename); return 0; } for( ; ; ) { newBuf = realloc(buf, (bufSize += granularity) * sizeof(char)); if(!newBuf) { perror(filename); free(buf); return 0; } - buf = newBuf; - read = fread(buf + bufPos, sizeof(char), granularity, fp); - bufPos += read; - if(read < granularity) { buf[bufPos] = '\0'; break; } + buf = newBuf; + rd = fread(buf + bufPos, sizeof(char), granularity, fp); + bufPos += rd; + 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); return buf; /** you must free() the memory! */ } diff --git a/src/Widget.c b/src/Widget.c index 4ae42bf..04c0559 100644 --- a/src/Widget.c +++ b/src/Widget.c @@ -1,13 +1,18 @@ /* 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? - 1. stick the code below, it's prototype must be the same, int(FILE *), where - the FILE* is called with the output file - 2. create a prototype in Widget.h - 3. in Parser.c, add to the symbol table, sym[] with the symbol you want, in - ASCIIbetical order - * Created by Neil Edelman on 2008-03-25. */ + Widgets like @files @pwd. To create a widget: + + * stick the code below implementing {ParserWidget}; + * create a prototype in Widget.h; + * in {Parser.c}, add to the symbol table, sym[] with the symbol you want, in + ASCIIbetical order. + + @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 /* strncat strncpy */ #include /* fprintf FILE */ @@ -17,15 +22,28 @@ #include "Recursor.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) +/* ": The POSIX name for this item is deprecated." No. */ +#pragma warning(disable: 4996) +#define UNUSED(a) (void)(sizeof((a), 0)) +#endif /* msvc --> */ +/* ugly --> */ + /* constants */ static const char *htmlDesc = "index.d"; static const char *htmlContent = "content.d"; static const char *separator = "/"; static const char *picture = ".jpeg"; /* yeah, I hard coded this */ static const size_t maxRead = 512; -static const char *link = ".link"; -const char *desc = ".d"; /* used in multiple files */ -const char *news = ".news"; +static const char *dot_link = ".link"; +const char *dot_desc = ".d"; /* used in multiple files */ +const char *dot_news = ".news"; extern const char *dirCurrent; extern const char *dirParent; extern const char *htmlIndex; @@ -38,15 +56,17 @@ static char title[64] = "(no title)"; static char filenews[64] = "(no file name)"; /* 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) { char *dot; - int read, tLen; + int read; + size_t tLen; 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)) { - 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; } /* save the fn, safe because we checked it, and strip off .news */ @@ -55,44 +75,56 @@ int WidgetSetNews(const char *fn) { /* open .news */ if(!(fp = fopen(fn, "r"))) { perror(fn); return 0; } read = fscanf(fp, "%d-%d-%d\n", &year, &month, &day); - if(read < 3) fprintf(stderr, "Widget::setNews: error parsing ISO 8601 date, .\n"); - month = correctNo(month, 1, 12); - day = correctNo(day, 1, 31); + if(read < 3) fprintf(stderr, "Widget::setNews: error parsing ISO 8601 " + "date, .\n"); + month = clip(month, 1, 12); + day = clip(day, 1, 31); /* fgets reads a newline at the end (annoying) so we strip that off */ - if(!fgets(title, sizeof(title), fp)) { perror(fn); *title = '\0'; } - else if((tLen = strlen(title)) > 0 && title[tLen - 1] == '\n') title[tLen - 1] = '\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'; 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; } /* the widget handlers */ + +/** @implements ParserWidget */ int WidgetContent(const struct Files *f, FILE *fp) { char buf[81], *bufpos; - int i; + size_t i; FILE *in; + + UNUSED(f); /* it's a nightmare to test if this is text (which most is,) in which case we should insert

    ...

    after every paragraph, <>& -> <>&, 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 plain-text */ 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); } if(fclose(in)) perror(htmlDesc); } return 0; } +/** @implements ParserWidget */ int WidgetDate(const struct Files *f, FILE *fp) { + UNUSED(f); /* ISO 8601 - YYYY-MM-DD */ fprintf(fp, "%4.4d-%2.2d-%2.2d", year, month, day); return 0; } +/** @implements ParserWidget */ int WidgetFilealt(const struct Files *f, FILE *fp) { fprintf(fp, "%s", FilesIsDir(f) ? "Dir" : "File"); return 0; } +/** @implements ParserWidget */ int WidgetFiledesc(const struct Files *f, FILE *fp) { char buf[256], *name; FILE *in; @@ -100,29 +132,32 @@ int WidgetFiledesc(const struct Files *f, FILE *fp) { if(FilesIsDir(f)) { /* /index.d */ strncpy(buf, name, sizeof(buf) - 9); - strncat(buf, separator, 1); - strncat(buf, htmlDesc, 7); + strncat(buf, separator, 1lu); + strncat(buf, htmlDesc, 7lu); } else { /* .d */ strncpy(buf, name, sizeof(buf) - 6); - strncat(buf, desc, 5); + strncat(buf, dot_desc, 5lu); } if((in = fopen(buf, "r"))) { char *bufpos; - int i; - for(i = 0; (i < maxRead) && (bufpos = fgets(buf, sizeof(buf), in)); i++) { + size_t i; + for(i = 0; (i < maxRead) + && (bufpos = fgets(buf, (int)sizeof(buf), in)); i++) { fprintf(fp, "%s", bufpos); } if(fclose(in)) perror(buf); } return 0; } +/** @implements ParserWidget */ int WidgetFilehref(const struct Files *f, FILE *fp) { char *str, *name; int ch; FILE *fhref; 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 */ for( ; ; ) { ch = fgetc(fhref); @@ -135,14 +170,15 @@ int WidgetFilehref(const struct Files *f, FILE *fp) { } return 0; } +/** @implements ParserWidget */ int WidgetFileicon(const struct Files *f, FILE *fp) { char buf[256], *name; FILE *in; if(!(name = FilesName(f))) return 0; /* insert .d.jpeg if available */ strncpy(buf, name, sizeof(buf) - 12); - strncat(buf, desc, 5); - strncat(buf, picture, 6); + strncat(buf, dot_desc,5lu); + strncat(buf, picture, 6lu); if((in = fopen(buf, "r"))) { fprintf(fp, "%s", buf); if(fclose(in)) perror(buf); @@ -158,44 +194,57 @@ int WidgetFileicon(const struct Files *f, FILE *fp) { } return 0; } +/** @implements ParserWidget */ int WidgetFilename(const struct Files *f, FILE *fp) { fprintf(fp, "%s", FilesName(f)); return 0; } +/** @implements ParserWidget */ int WidgetFiles(const struct Files *f, FILE *fp) { + while(0 && fp); return FilesAdvance((struct Files *)f) ? -1 : 0; } +/** @implements ParserWidget */ int WidgetFilesize(const struct Files *f, FILE *fp) { /* eww */ if(!FilesIsDir(f)) fprintf(fp, " (%d KB)", FilesSize(f)); return 0; } +/** @implements ParserWidget */ int WidgetNews(const struct Files *f, FILE *fp) { char buf[256], *bufpos; - int i; + size_t i; FILE *in; + + UNUSED(f); if(!filenews[0]) 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); } if(fclose(in)) perror(filenews); return 0; } +/** @implements ParserWidget */ int WidgetNewsname(const struct Files *f, FILE *fp) { + UNUSED(f); fprintf(fp, "%s", filenews); return 0; } +/** @implements ParserWidget */ int WidgetNow(const struct Files *f, FILE *fp) { char t[22]; time_t currentTime; struct tm *formatedTime; + + UNUSED(f); if((currentTime = time(0)) == (time_t)(-1)) { perror("@date"); return 0; } formatedTime = gmtime(¤tTime); /* 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); return 0; } +/** @implements ParserWidget */ int WidgetPwd(const struct Files *f, FILE *fp) { static int persistant = 0; /* ick, be very careful! */ char *pwd; @@ -205,6 +254,7 @@ int WidgetPwd(const struct Files *f, FILE *fp) { fprintf(fp, "%s", pwd); return -1; } +/** @implements ParserWidget */ int WidgetRoot(const struct Files *f, FILE *fp) { static int persistant = 0; /* ick, be very careful! */ char *pwd; @@ -214,12 +264,14 @@ int WidgetRoot(const struct Files *f, FILE *fp) { fprintf(fp, "%s", dirParent); return -1; } +/** @implements ParserWidget */ int WidgetTitle(const struct Files *f, FILE *fp) { + UNUSED(f); fprintf(fp, "%s", title); 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; else if(no > high) no = high; return no;