%{
/*
* Программа генерирует пополняемый контекст постранично для создания
* псевдодинамического сайта. Для пользователей и поисковиков данный
* сайт представляется в виде статически сформированных страниц,
* например: /news1.html /news2.html ... /pub1.html /pub2.html ...
* где страницы с номером 1 - самые старые опубликованные страницы,
* и с наибольшим номером - самые свежие публикации.
* Такой сайт удобен для поиска и установки закладок на нужные страницы,
* а так же кешируемый.
*
* Для web-сервера файлов /news*.html и /pub*.html на самом деле
* не существует. Директивами модуля Apache mod_rewrite создаем такой
* примерный список правил:
*
* RewriteEngine On
* RewriteBase /
* RewriteRule ^news[0-9]*\.[s]?html$ index.shtml
* RewriteRule ^pub[0-9]*\.[s]?html$ index.shtml
*
* ErrorDocument 404 /error.shtml
*
* web-сервер перенаправляет эти несуществующие вызовы на SSI страничку
* /index.shtml с примерным содержанием:
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
* Директивы SSI устанавливают переменную ZAGOLOVOK, подключают единый
* файл начала страниц top.shtml, где можно использовать вышеуказанную
* переменную для установки и и т. д.
* Следующая директива вызывает настоящую CGI программу. И последняя
* директива SSI подключает единый файл оформления оставшейся части странички.
* Вызов с ключём -r /news.html сделан для примера, если корневая страница
* сайта должна быть страницей новостей.
* Если на сайте у вас есть меню, то его пункты можно прописать
* в top.shtml примерно так:
*
*
- НовостиНовости
* - ПубликацииПубликации
*
* При таких условиях пункт меню становится обычным текстом, если текущая
* страница одна из подстраниц заказанного раздела, сделанных этой программой
* или ссылкой на другой раздел.
*
* Данные для данной программы есть пополняемые файлы синтаксиса:
* - html текст
, где текст - любой html текст. Допускается
* включение собственных тегов и
со своими списками
* (синтаксис строгий, не допускается опускание закрывающих тегов),
* коментарии допускаются и игнорируются. Пустой текст
* внутри тега - не допускается.
* Файлы должны пополняться сверху, первая записть
- html текст
-
* самая свежая.
*
* Если URL не содержит цифру (до SUFFIX), то программа выводит
* до MIN_ON_1PAGE+NUM_ON_PAGES при их наличии (почему именно так -
* см. далее в описании недостатка метода) самых свежих записей из файла.
* При наличии номера в подстроке запрашиваемого URL, программа выводит
* содержимое соответствующей страницы, так для URL вида /news1.html
* будут выведены самые старые новости в количестве NUM_ON_PAGES.
* Имя рабочего файла совпадает с началом URL без начального полного пути
* (он заменяется на LOAD_PATH) и без номера с заменой SUFFIX на
* SUFFIX_DATAFILE. Т. е. если SUFFIX установлен в коде программы в ".html",
* а SUFFIX_DATAFILE опеределен как ".txt", то при вызове URL
* http://www.domain/dir/news2.html
* программа будет работать с данными из файла LOAD_PATH/news.txt
*
* Установка END_ECHO печается, если файл данных не пуст.
* В оригинальном тексте программы это завершающий тег списка:
.
* Если контент пустой или содержит ровно одну страницу до
* MIN_ON_1PAGE+NUM_ON_PAGES сообщений, то программа завершает работу.
*
* К вышеуказанным действиям программа дополнительно выводит сообщение
* PAGES_MSG и ссылки в виде \n"
/* Количество сообщений на странице */
#define NUM_ON_PAGES 20
/* Минимальное количество сообщений на первой странице */
#define MIN_ON_1PAGE 6
/* Текст выводимый перед отображением списка указателей на списка страниц */
#define PAGES_MSG "Страницы: "
/* Формат (стиль) вывода текущей страницы */
#define CURRENT_PAGE ""
#define CURRENT_PAGE_END "\n"
#include /* off_t */
static void process(off_t start, off_t end);
static int yylex(void);
static void yyerror(const char *m);
#define YYSTYPE off_t
%}
%token LI UL OTHER OL
%start list
%%
list:
li
| list li
;
li:
'<' LI attrs '>' msg_list '<' '/' LI '>' { process($1, $9); }
;
msg_list:
msg
| msg_list msg
;
msg:
txt
| '<' UL attrs '>' all '<' '/' UL '>'
| '<' OL attrs '>' all '<' '/' OL '>'
;
all:
member
| all member
;
member:
msg
| '<' LI attrs '>' msg_list '<' '/' LI '>'
;
attr:
OTHER
| attr OTHER
;
txt:
OTHER
| tag_np
;
tag_np:
'<' OTHER attrs '>'
| '<' '/' OTHER '>'
;
attrs: | attr
;
%%
#include
#include
#include
#include
#include
static jmp_buf env;
static FILE *in;
static off_t fp = -1;
static int linenum = 1;
static void yyerror(const char *m)
{
fprintf(stderr, "%d: %s\n", linenum, m);
exit(5);
}
static int getc0(int flg_unexpect_eof)
{
int c = getc(in);
if(c == EOF) {
if(flg_unexpect_eof)
yyerror("unexpected EOF");
longjmp(env, EOF);
}
fp++;
if(c == '\n')
linenum++;
return c;
}
#define MODE_OTHER 0
#define MODE_TAG 1
#define MODE_ATTR 2
static int mode;
static int yylex(void)
{
int c;
char *s;
char tok[4];
while(1) {
c = getc0(0);
if(c == '\0' || strchr("\t\n\v\f\r ", c) != NULL)
continue;
if(c == '<') {
c = getc0(0);
if(c == '!') {
c = getc0(0);
if(c == '-') {
c = getc0(0);
if(c == '-') {
for(;;) {
c = getc0(0);
if(c != '-')
continue;
c = getc0(0);
if(c != '-')
continue;
more2_minus:
c = getc0(0);
if(c != '>') {
if(c == '-')
goto more2_minus;
continue;
}
break;
}
continue; /* main loop */
}
}
yyerror("bad start remark, use '