283 lines
8.4 KiB
C
283 lines
8.4 KiB
C
/** Copyright 2008, 2012 Neil Edelman, distributed under the terms of the
|
|
GNU General Public License, see copying.txt
|
|
|
|
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.
|
|
|
|
See Parser for more information.
|
|
|
|
@title Widget
|
|
@author Neil
|
|
@std POSIX.1
|
|
@version 1.1; 2017-03 fixed pedantic warnings; command-line improvements
|
|
@since 0.6; 2008-03-25 */
|
|
|
|
#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"
|
|
|
|
/* <-- 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 */
|
|
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;
|
|
|
|
/* 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 */
|
|
int clip(int no, const int low, const int high);
|
|
|
|
int WidgetSetNews(const char *fn) {
|
|
char *dot;
|
|
int read;
|
|
size_t tLen;
|
|
FILE *fp;
|
|
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)));
|
|
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);
|
|
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);
|
|
/* fgets reads a newline at the end (annoying) so we strip that off */
|
|
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);
|
|
return -1;
|
|
}
|
|
|
|
/* the widget handlers */
|
|
|
|
/** @implements ParserWidget */
|
|
int WidgetContent(struct Files *const f, FILE *const fp) {
|
|
char buf[81], *bufpos;
|
|
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 <p>...</p> 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(html_content, "r")) || (in = fopen(html_desc, "r"))) {
|
|
for(i = 0; (i < max_read)
|
|
&& (bufpos = fgets(buf, (int)sizeof(buf), in)); i++) {
|
|
fprintf(fp, "%s", bufpos);
|
|
}
|
|
if(fclose(in)) perror(html_desc);
|
|
}
|
|
return 0;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetDate(struct Files *const f, FILE *const 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(struct Files *const f, FILE *const fp) {
|
|
fprintf(fp, "%s", FilesIsDir(f) ? "Dir" : "File");
|
|
return 0;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetFiledesc(struct Files *const f, FILE *const fp) {
|
|
char buf[256];
|
|
const char *name;
|
|
FILE *in;
|
|
if(!(name = FilesName(f))) return 0;
|
|
if(FilesIsDir(f)) {
|
|
/* <file>/index.d */
|
|
strncpy(buf, name, sizeof(buf) - 9);
|
|
strncat(buf, separator, 1lu);
|
|
strncat(buf, html_desc, 7lu);
|
|
} else {
|
|
/* <file>.d */
|
|
strncpy(buf, name, sizeof(buf) - 6);
|
|
strncat(buf, dot_desc, 5lu);
|
|
}
|
|
if((in = fopen(buf, "r"))) {
|
|
char *bufpos;
|
|
size_t i;
|
|
for(i = 0; (i < max_read)
|
|
&& (bufpos = fgets(buf, (int)sizeof(buf), in)); i++) {
|
|
fprintf(fp, "%s", bufpos);
|
|
}
|
|
if(fclose(in)) perror(buf);
|
|
}
|
|
return 0;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetFilehref(struct Files *const f, FILE *const fp) {
|
|
const char *str, *name;
|
|
int ch;
|
|
FILE *fhref;
|
|
if(!(name = FilesName(f))) return 0;
|
|
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);
|
|
if(ch == '\n' || ch == '\r' || ch == EOF) break;
|
|
fprintf(fp, "%c", ch);
|
|
}
|
|
if(fclose(fhref)) perror(name);
|
|
} else {
|
|
fprintf(fp, "%s", name);
|
|
}
|
|
return 0;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetFileicon(struct Files *const f, FILE *const fp) {
|
|
char buf[256];
|
|
const char *name;
|
|
FILE *in;
|
|
if(!(name = FilesName(f))) return 0;
|
|
/* insert <file>.d.jpeg if available */
|
|
strncpy(buf, name, sizeof(buf) - 12);
|
|
strncat(buf, dot_desc,5lu);
|
|
strncat(buf, picture, 6lu);
|
|
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)) {
|
|
fprintf(fp, "%s%s", dir_parent, separator);
|
|
}
|
|
fprintf(fp, "%s%s", FilesIsDir(f) ? "dir" : "file", picture);
|
|
}
|
|
return 0;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetFilename(struct Files *const f, FILE *const fp) {
|
|
fprintf(fp, "%s", FilesName(f));
|
|
return 0;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetFiles(struct Files *const f, FILE *const fp) {
|
|
while(0 && fp);
|
|
return FilesAdvance((struct Files *)f) ? -1 : 0;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetFilesize(struct Files *const f, FILE *const fp) { /* eww */
|
|
if(!FilesIsDir(f)) fprintf(fp, " (%d KB)", FilesSize(f));
|
|
return 0;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetNews(struct Files *const f, FILE *const fp) {
|
|
char buf[256], *bufpos;
|
|
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 < max_read) && (bufpos = fgets(buf, (int)sizeof(buf), in));
|
|
i++){
|
|
fprintf(fp, "%s", bufpos);
|
|
}
|
|
if(fclose(in)) perror(filenews);
|
|
return 0;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetNewsname(struct Files *const f, FILE *const fp) {
|
|
UNUSED(f);
|
|
fprintf(fp, "%s", filenews);
|
|
return 0;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetNow(struct Files *const f, FILE *const 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, 21lu, "%Y-%m-%dT%H:%M:%SZ", formatedTime);
|
|
fprintf(fp, "%s", t);
|
|
return 0;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetPwd(struct Files *const f, FILE *const fp) {
|
|
static int persistant = 0; /* ick, be very careful! */
|
|
const char *pwd;
|
|
if(!persistant) { persistant = -1; FilesSetPath((struct Files *)f); }
|
|
pwd = FilesEnumPath(f);
|
|
if(!pwd) { persistant = 0; return 0; }
|
|
fprintf(fp, "%s", pwd);
|
|
return -1;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetRoot(struct Files *const f, FILE *const fp) {
|
|
static int persistant = 0; /* ick, be very careful! */
|
|
const char *pwd;
|
|
if(!persistant) { persistant = -1; FilesSetPath((struct Files *)f); }
|
|
pwd = FilesEnumPath(f);
|
|
if(!pwd) { persistant = 0; return 0; }
|
|
fprintf(fp, "%s", dir_parent);
|
|
return -1;
|
|
}
|
|
/** @implements ParserWidget */
|
|
int WidgetTitle(struct Files *const f, FILE *const fp) {
|
|
UNUSED(f);
|
|
fprintf(fp, "%s", title);
|
|
return 0;
|
|
}
|
|
|
|
int clip(int no, const int low, const int high) {
|
|
if(no < low) no = low;
|
|
else if(no > high) no = high;
|
|
return no;
|
|
}
|