make-index/src/Widget.c

283 lines
8.4 KiB
C
Raw Permalink Normal View History

/** Copyright 2008, 2012 Neil Edelman, distributed under the terms of the
2017-03-26 04:47:35 -04:00
GNU General Public License, see copying.txt
2016-09-11 02:40:29 -04:00
Widgets like @(files), @(pwd). To create a widget:
2017-03-26 04:47:35 -04:00
* 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.
See Parser for more information.
2017-03-26 04:47:35 -04:00
@title Widget
@author Neil
@std POSIX.1
2017-03-26 20:08:32 -04:00
@version 1.1; 2017-03 fixed pedantic warnings; command-line improvements
2017-03-26 04:47:35 -04:00
@since 0.6; 2008-03-25 */
2016-09-11 02:40:29 -04:00
#include <string.h> /* strncat strncpy */
#include <stdio.h> /* fprintf FILE */
#include <time.h> /* time gmtime - for @date */
#include "Files.h"
#include "Parser.h"
#include "Recursor.h"
#include "Widget.h"
2017-03-26 04:47:35 -04:00
/* <-- 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 --> */
2016-09-11 02:40:29 -04:00
/* constants */
2017-03-26 20:08:32 -04:00
static const char *html_desc = "index.d";
static const char *html_content = "content.d";
static const char *separator = "/";
static const char *picture = ".jpeg"; /* yeah, I hard coded this */
static const size_t max_read = 512;
static const char *dot_link = ".link";
const char *dot_desc = ".d"; /* used in multiple files */
const char *dot_news = ".news";
extern const char *dir_current;
extern const char *dir_parent;
2016-09-11 02:40:29 -04:00
/* global, ick: news */
static int year = 1983;
static int month = 1;
static int day = 30;
static char title[64] = "(no title)";
static char filenews[64] = "(no file name)";
/* private */
2017-03-26 04:47:35 -04:00
int clip(int no, const int low, const int high);
2016-09-11 02:40:29 -04:00
int WidgetSetNews(const char *fn) {
char *dot;
2017-03-26 04:47:35 -04:00
int read;
size_t tLen;
2016-09-11 02:40:29 -04:00
FILE *fp;
2017-03-26 04:47:35 -04:00
if(!fn || !(dot = strstr(fn, dot_news))) return 0;
2016-09-11 02:40:29 -04:00
if(strlen(fn) > sizeof(filenews) / sizeof(char) - sizeof(char)) {
2017-03-26 04:47:35 -04:00
fprintf(stderr, "Widget::SetNews: news file name, \"%s,\" doesn't fit "
"in buffer (%d.)\n", fn, (int)(sizeof(filenews) / sizeof(char)));
2016-09-11 02:40:29 -04:00
return 0;
}
/* save the fn, safe because we checked it, and strip off .news */
strcpy(filenews, fn);
filenews[dot - fn] = '\0';
/* open .news */
if(!(fp = fopen(fn, "r"))) { perror(fn); return 0; }
read = fscanf(fp, "%d-%d-%d\n", &year, &month, &day);
2017-03-26 04:47:35 -04:00
if(read < 3) fprintf(stderr, "Widget::setNews: error parsing ISO 8601 "
"date, <YYYY-MM-DD>.\n");
month = clip(month, 1, 12);
day = clip(day, 1, 31);
2016-09-11 02:40:29 -04:00
/* fgets reads a newline at the end (annoying) so we strip that off */
2017-03-26 04:47:35 -04:00
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';
2016-09-11 02:40:29 -04:00
if(fclose(fp)) perror(fn);
2017-03-26 04:47:35 -04:00
fprintf(stderr, "News <%s>, '%s' %d-%d-%d.\n", filenews, title, year,
month, day);
2016-09-11 02:40:29 -04:00
return -1;
}
/* the widget handlers */
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetContent(struct Files *const f, FILE *const fp) {
2016-09-11 02:40:29 -04:00
char buf[81], *bufpos;
2017-03-26 04:47:35 -04:00
size_t i;
2016-09-11 02:40:29 -04:00
FILE *in;
2017-03-26 04:47:35 -04:00
UNUSED(f);
2016-09-11 02:40:29 -04:00
/* 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;,
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 */
2017-03-26 20:08:32 -04:00
if((in = fopen(html_content, "r")) || (in = fopen(html_desc, "r"))) {
for(i = 0; (i < max_read)
2017-03-26 04:47:35 -04:00
&& (bufpos = fgets(buf, (int)sizeof(buf), in)); i++) {
2016-09-11 02:40:29 -04:00
fprintf(fp, "%s", bufpos);
}
2017-03-26 20:08:32 -04:00
if(fclose(in)) perror(html_desc);
2016-09-11 02:40:29 -04:00
}
return 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetDate(struct Files *const f, FILE *const fp) {
2017-03-26 04:47:35 -04:00
UNUSED(f);
2016-09-11 02:40:29 -04:00
/* ISO 8601 - YYYY-MM-DD */
fprintf(fp, "%4.4d-%2.2d-%2.2d", year, month, day);
return 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetFilealt(struct Files *const f, FILE *const fp) {
2016-09-11 02:40:29 -04:00
fprintf(fp, "%s", FilesIsDir(f) ? "Dir" : "File");
return 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetFiledesc(struct Files *const f, FILE *const fp) {
char buf[256];
const char *name;
2016-09-11 02:40:29 -04:00
FILE *in;
if(!(name = FilesName(f))) return 0;
if(FilesIsDir(f)) {
/* <file>/index.d */
strncpy(buf, name, sizeof(buf) - 9);
2017-03-26 04:47:35 -04:00
strncat(buf, separator, 1lu);
2017-03-26 20:08:32 -04:00
strncat(buf, html_desc, 7lu);
2016-09-11 02:40:29 -04:00
} else {
/* <file>.d */
strncpy(buf, name, sizeof(buf) - 6);
2017-03-26 04:47:35 -04:00
strncat(buf, dot_desc, 5lu);
2016-09-11 02:40:29 -04:00
}
if((in = fopen(buf, "r"))) {
char *bufpos;
2017-03-26 04:47:35 -04:00
size_t i;
2017-03-26 20:08:32 -04:00
for(i = 0; (i < max_read)
2017-03-26 04:47:35 -04:00
&& (bufpos = fgets(buf, (int)sizeof(buf), in)); i++) {
2016-09-11 02:40:29 -04:00
fprintf(fp, "%s", bufpos);
}
if(fclose(in)) perror(buf);
}
return 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetFilehref(struct Files *const f, FILE *const fp) {
const char *str, *name;
2016-09-11 02:40:29 -04:00
int ch;
FILE *fhref;
if(!(name = FilesName(f))) return 0;
2017-03-26 04:47:35 -04:00
if((str = strstr(name, dot_link)) && *(str += strlen(dot_link)) == '\0'
&& (fhref = fopen(name, "r"))) {
2016-09-11 02:40:29 -04:00
/* fixme: not too good, with the reading one char at a time */
for( ; ; ) {
ch = fgetc(fhref);
if(ch == '\n' || ch == '\r' || ch == EOF) break;
fprintf(fp, "%c", ch);
}
if(fclose(fhref)) perror(name);
} else {
fprintf(fp, "%s", name);
}
return 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetFileicon(struct Files *const f, FILE *const fp) {
char buf[256];
const char *name;
2016-09-11 02:40:29 -04:00
FILE *in;
if(!(name = FilesName(f))) return 0;
/* insert <file>.d.jpeg if available */
strncpy(buf, name, sizeof(buf) - 12);
2017-03-26 04:47:35 -04:00
strncat(buf, dot_desc,5lu);
strncat(buf, picture, 6lu);
2016-09-11 02:40:29 -04:00
if((in = fopen(buf, "r"))) {
fprintf(fp, "%s", buf);
if(fclose(in)) perror(buf);
} else {
/* added thing to get to root instead of / because sometimes 'root'
is not the real root! eg www.geocities.com/~foo/; does the same thing
as having a @root{/} */
FilesSetPath((struct Files *)f);
while(FilesEnumPath((struct Files *)f)) {
2017-03-26 20:08:32 -04:00
fprintf(fp, "%s%s", dir_parent, separator);
2016-09-11 02:40:29 -04:00
}
fprintf(fp, "%s%s", FilesIsDir(f) ? "dir" : "file", picture);
}
return 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetFilename(struct Files *const f, FILE *const fp) {
2016-09-11 02:40:29 -04:00
fprintf(fp, "%s", FilesName(f));
return 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetFiles(struct Files *const f, FILE *const fp) {
2017-03-26 04:47:35 -04:00
while(0 && fp);
2016-09-11 02:40:29 -04:00
return FilesAdvance((struct Files *)f) ? -1 : 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetFilesize(struct Files *const f, FILE *const fp) { /* eww */
2016-09-11 02:40:29 -04:00
if(!FilesIsDir(f)) fprintf(fp, " (%d KB)", FilesSize(f));
return 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetNews(struct Files *const f, FILE *const fp) {
2016-09-11 02:40:29 -04:00
char buf[256], *bufpos;
2017-03-26 04:47:35 -04:00
size_t i;
2016-09-11 02:40:29 -04:00
FILE *in;
2017-03-26 04:47:35 -04:00
UNUSED(f);
2016-09-11 02:40:29 -04:00
if(!filenews[0]) return 0;
if(!(in = fopen(filenews, "r"))) { perror(filenews); return 0; }
2017-03-26 20:08:32 -04:00
for(i = 0; (i < max_read) && (bufpos = fgets(buf, (int)sizeof(buf), in));
i++){
2016-09-11 02:40:29 -04:00
fprintf(fp, "%s", bufpos);
}
if(fclose(in)) perror(filenews);
return 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetNewsname(struct Files *const f, FILE *const fp) {
2017-03-26 04:47:35 -04:00
UNUSED(f);
2016-09-11 02:40:29 -04:00
fprintf(fp, "%s", filenews);
return 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetNow(struct Files *const f, FILE *const fp) {
2016-09-11 02:40:29 -04:00
char t[22];
time_t currentTime;
struct tm *formatedTime;
2017-03-26 04:47:35 -04:00
UNUSED(f);
2016-09-11 02:40:29 -04:00
if((currentTime = time(0)) == (time_t)(-1)) { perror("@date"); return 0; }
formatedTime = gmtime(&currentTime);
/* ISO 8601 - YYYY-MM-DDThh:mm:ssTZD */
2017-03-26 04:47:35 -04:00
strftime(t, 21lu, "%Y-%m-%dT%H:%M:%SZ", formatedTime);
2016-09-11 02:40:29 -04:00
fprintf(fp, "%s", t);
return 0;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetPwd(struct Files *const f, FILE *const fp) {
2016-09-11 02:40:29 -04:00
static int persistant = 0; /* ick, be very careful! */
2017-03-26 20:08:32 -04:00
const char *pwd;
2016-09-11 02:40:29 -04:00
if(!persistant) { persistant = -1; FilesSetPath((struct Files *)f); }
2017-03-26 20:08:32 -04:00
pwd = FilesEnumPath(f);
2016-09-11 02:40:29 -04:00
if(!pwd) { persistant = 0; return 0; }
fprintf(fp, "%s", pwd);
return -1;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetRoot(struct Files *const f, FILE *const fp) {
2016-09-11 02:40:29 -04:00
static int persistant = 0; /* ick, be very careful! */
2017-03-26 20:08:32 -04:00
const char *pwd;
2016-09-11 02:40:29 -04:00
if(!persistant) { persistant = -1; FilesSetPath((struct Files *)f); }
2017-03-26 20:08:32 -04:00
pwd = FilesEnumPath(f);
2016-09-11 02:40:29 -04:00
if(!pwd) { persistant = 0; return 0; }
2017-03-26 20:08:32 -04:00
fprintf(fp, "%s", dir_parent);
2016-09-11 02:40:29 -04:00
return -1;
}
2017-03-26 04:47:35 -04:00
/** @implements ParserWidget */
2017-03-26 20:08:32 -04:00
int WidgetTitle(struct Files *const f, FILE *const fp) {
2017-03-26 04:47:35 -04:00
UNUSED(f);
2016-09-11 02:40:29 -04:00
fprintf(fp, "%s", title);
return 0;
}
2017-03-26 04:47:35 -04:00
int clip(int no, const int low, const int high) {
2016-09-11 02:40:29 -04:00
if(no < low) no = low;
else if(no > high) no = high;
return no;
}