си

«Гопник 2»: порт под Линукс и МакОС

Я искал медь, а нашёл золото! Постоянные читатели блога знают, что я маниакально одержим текстовой игрой «Гопник» и её продолжением, которые были написаны ещё под ДОС. Хотя её время давно прошло, я постоянно пытаюсь разыскать что-нибудь новенькое про неё, и у меня даже есть отдельный тег для заметок на эту тему.

Можно даже сказать, что я председатель фан-клуба этой серии игр. Жаль только миссионер из меня не очень и в моём клубе на членских взносах не пожируешь.

В общем иногда на меня накатывает и я опять начинаю шерстить интернет в поисках какой-нибудь информации об этих играх. Особой надежды у меня нет, но мало ли, вдруг авторы себя как-то проявят или кто-то напишет продолжение.

И вот наконец мне крупно повезло!

Скриншот текстовой игры: выбор роли (подтас, отморозок), сложности и ника «Bolknote». Управление командами: w, s, h, mh, kos, rep, mar, girl, met, sav, loa, help, e, i.
Игровой процесс. Игра запущена под МакОС

Как оказалось, автор второй части когда-то выкладывал в сеть исходный код, и хотя сейчас он, по всей видимости, потерян, зато доступна модифицированная версия — некто Андрей Тихонов («tiandrey») запустил игру под Линукс.

Интернет со временем всё забывает и чтобы это не случилось и с этим портом, я выложил его на «Гитхаб», минимально причесал, внёс исправление для компиляции под МакОС и пофиксил один баг (при переходе в метро игра падала с ошибкой).

В планах починить сохранение и загрузку состояния игры — Андрей почему-то оставил это место разломанным. Попробую выделить на это время в выходные.

4 комментария

«Крестики-нолики» и printf

Очень люблю так называемое ненормальное программирование (нормального мне и на работе хватает), когда программируют ради преодоления каких-то препятствий, а не ради практического результата. С удовольствием занимаюсь им сам и очень люблю находить такие примеры у других.

На днях один из читателей очень меня порадовал игрой «Крестики-нолики», написанной на… языке функции printf! Возможно я когда-то и слышал, что язык printf полный по Тьюрингу, но в голове это не отложилось.

Текст на чёрном фоне: три строки с комбинациями X и O, разделённые тире, и внизу надпись «P1 TIES».
Пример сыгранной партии в «Крестики-нолики»

Для тех, кто не знает, поясню, язык printf — это значки, которыми описывается в каком именно виде нам хочется вывести на экран информацию о переменных. Используется во многих языках, но особенно часто в Си.

В этом языке много интересных конструкций, есть даже такие, которыми можно даже что-то записывать в другие переменные!

Например, вот небольшой пример, который запишет число «42» (длину строки «Answer to the Ultimate Question of Life is») в переменную c:

#include <stdio.h>

int main() {
  int c;
  printf("Answer to the Ultimate Question of Life is%n ", &c);
  printf("%d", c);
}

Как, используя эти значки, можно что-то запрограммировать? С большим трудом. Автор программы нашёл способ описания логических операций, а потом с их помощью реализовал нужную ему логику.

Если закодировать «ложь» пустой строкой, а «истину» строкой длиной один, то логическую операцию «ИЛИ» можно получить, если померить совокупную длину двух входных значений:

// c = strlen("") + strlen("")
printf("%s%s%n", "", "", &c); // в c будет «0»

// c = strlen("1") + strlen("")
printf("%s%s%n", "1", "", &c); // в c будет «1»

«НЕ» получается сложнее, для этого надо использовать несколько хитростей.

Во-первых, у printf есть возможность задавать отступ для значения.

Во-вторых, у %n есть параметр, который выводит длину по модулю 256.

В-третьих, вместо форматирования входных параметров по порядку, есть способ для указания параметра, который мы хотим вывести, по его номеру.

Всё это позволяет закодировать «НЕ» как (strlen(a)+255)%256 или strlen(a)-1:

printf("%1$255s%1$s%2$hhn", a, &c);

Тут написано следующее: вывести первый параметр как строку, дополнив его до длины в 255 символов пробелами (%1$255s), снова вывести первый параметр как строку (%1$s), записать полученную длину по модулю 256 во второй параметр (%2$hhn).

Отсюда легко понять как сделать операцию «И-НЕ»:

printf("%1$254s%1$s%2$s%3$hhn", a, b, &c);

В принципе, этого хватило, что реализовать всю требуемую логику.

Играют два игрока, последовательно вводя номер ячейки, куда делается ход (от единицы до девяти, считая слева направо, сверху вниз). Программа отрисовывает поле и определяет победу одного из игроков или ничью.

Очень заморочено и очень интересная идея!

2 комментария

Алгол и Баш

Удивительно, я и не догадывался, что иногда употребляю ключевые слова родом из «Алгола-68»!

Оказывается автор командной оболочки bsh Стивен Борн притащил ключевые слова IF/FI и CASE/ESAC прямиком из «Алгола». Позже оттуда они попали в более известный сейчас bash, на котором я нередко пишу.

Более того, Стивен Борн по всей видимости насколько крепко фанател по этому языку, что специальными макросами превратил Си, на котором написал bsh, в некое подобие «Алгола» (исходники есть в интернете).

Если скачать себе пару заголовочных файлов (и выкинуть из них всё то, что мешает компиляции), то можно и сейчас попробовать этот макроязык в деле (это я пузырьковую сортировку написал):

#pragma GCC diagnostic ignored "-Wimplicit-int"
#pragma GCC diagnostic ignored "-Wreturn-type"

#include "mac.h"
#include "mode.h"
#include <stdio.h>

bubbleSort(arr, n)
    INT arr[], n;
BEGIN
    INT i, j;

    FOR i = 0; i < n - 1; i++
    DO  FOR j = 0; j < n - i - 1; j++
        DO  IF arr[j] > arr[j + 1]
            THEN    arr[j] = arr[j] - arr[j+1];
                    arr[j+1] = arr[j] + arr[j+1];
                    arr[j] = arr[j+1] - arr[j];
            FI
        OD
    OD
END
 
printArray(arr, n)
    INT arr[], n;
BEGIN
    INT i;
    FOR i = 0; i < n; i++
    DO
        printf("%d ", arr[i]);
    OD

    printf("\n");
END

main()
BEGIN
    INT arr[] = { 0xFE, 0xED, 0xBE, 0xEF };
    INT n = 1[&arr] - arr;

    printArray(arr, n);
    bubbleSort(arr, n);
    printArray(arr, n);
END

Примерно так выглядят исходники bsh. Единственное моё добавление — BEGIN и END, которые Борн для описания тела функций не использует, но зато в «Алголе» принято делать именно так.

Кстати (век живи — век учись), такое неординарное объявление функций, как у меня в листинге (а я подсмотрел его в исходниках bsh), — как оказалось, устаревший синтаксис Си, причём он до сих пор поддерживается компиляторами.

6 комментариев

День Радио ★

Сегодня, 7 мая в России отмечают День радио — в этот день, 125 лет назад российский физик Александр Степанович Попов на заседании Русского физико-химического общества продемонстрировал «прибор, предназначенный для показывания быстрых колебаний в атмосферном электричестве».

К этому юбилею, превозмогая лень, прокрастинацию и уныние от «самоизоляции», мне удалось наконец дописать игрушку, которую я задумал ещё несколько лет назад. Игра была готова неделю назад, но я всё никак не мог сделать последний шаг — добавить описание и выложить наружу.

Таблица с эмодзи волн, взрывов и черепов, расположенных по строкам 01–10 и столбцам А–К на чёрном фоне.
Отладочный режим получившегося «Морского боя», в обычном режиме видно только мигание светодиода

Для практики в моей любимой дисциплине — «ненормальном программировании», очень хотелось написать какую-то игрушку, в которую играть нужно будет кодом Морзе.

В итоге, для этого я выбрал «Морской бой». В моём варианте игрок вводит информацию клавишей левого «Шифта», а компьютер отвечает, мигая светодиодом кнопки «Капс Лок». Чуть более подробные правила есть в репозитории проекта.

Обёртка и некоторые функции (мигание светодиодом, опрос «Шифта» и функция задержки) написаны на Си, остальная часть — на языке «Лу́а» (Lua). Давно хотелось изучить этот странноватый язык поглубже, а тут ещё удалось поучиться встраивать его в Си.

Чтобы увеличить градус безумия всего проекта, в Си были использованы диграфы — они очень странно выглядят и дают ощущение, что используется какой-то доселе невиданный язык.

Код на C с вставками Lua: создание состояния Lua, загрузка скрипта battleship.lua или строки PROGRAM, обработка ошибок загрузки.
Диграфы в Си немного запутывают и вносят в код толику безумия

Пока работал над игрой, приходилось много гуглить, в очередной раз поразился, как много кода люди бездумно копируют друг у друга. Реализация мигания светодиодом, например, кочует из проекта в проект в неизменном виде — видно, что никто из скопировавших не понимает как этот код вообще работает. Я в нём попытался разобраться и написать чуть чище, чем буквально везде.

Для тех безумцев, которые захотят попробовать скопмилировать этот вариант «Морского боя» и сыграть, ещё раз привожу репозиторий проекта (только под «МакОСь») — https://github.com/bolknote/battleship.

4 комментария

Комментарии в Си

Из документации к языку Си на сайте «Микрософта», секция про комментарии, описывается нестандартное расширение спецификации:

Comments beginning with two forward slashes (//) are terminated by the next newline character that is not preceded by an escape character. […] the newline character is preceded by a backslash (\), creating an «escape sequence». This escape sequence causes the compiler to treat the next line as part of the previous line. (For more information, see Escape Sequences.)

The default for Microsoft C is that the Microsoft extensions are enabled. Use /Za to disable these extensions.

То есть в примере ниже, если его скомпилировать в «Визуал Студио», выражение i++; на самом деле будет частью комментарий и не выполнится:

// мой комментарий \
    i++;

Счастливой отладки!

Добавлено позднее: в компиляторе gcc тоже работает, причём раскрашивается как комментарий в редакторах vim и «Саблайм».

18 комментариев

InlineC

Продолжая тему интерфейсов к языку Си, кстати будет упомянуть появившийся недавно модуль inlinec для Пайтона. Он позволяет вставлять в программу на Пайтоне Си-код довольно естественным способом. Вот пример из документации:

# coding: inlinec
from inlinec import inlinec

@inlinec
def Q_rsqrt(number):
    float Q_rsqrt( float number )
    {
        long i;
        float x2, y;
        const float threehalfs = 1.5F;

        x2 = number * 0.5F;
        y  = number;
        i  = * ( long * ) &y;
        i  = 0x5f3759df - ( i >> 1 );
        y  = * ( float * ) &i;
        y  = y * ( threehalfs - ( x2 * y * y ) );

        return y;
    }

print(Q_rsqrt(1.234))

Я проверил, это действительно работает. Тут вычисляется так называемый быстрый обратный квадратный корень от числа 1,234.

Пока этот модуль скорее прототип — скорость оставляет желать лучшего, в рабочем каталоге создаётся куча мусорных временных файлов, любое отступление от эталонного примера грозит выводом ошибки, которая совсем не помогает понять что не так.

Куда интереснее разобраться как это всё работает. Декоратор @inlinec тут ничего не делает. Судя по коду модуля, он возвращает функцию как есть и служит маркером, что ниже пойдёт сишная функция. Всё работу выполняет кодек, который подключается первой строкой.

Приём не новый, несколько лет назад я про него уже рассказывал — в Пайтоне в специальном магическом комментарии можно указать кодек, который пропускает через себя текст программы. Обычно он используется для программирования в кодировках, отличных от ЮТФ-8, но ничего не мешает использовать его иначе.

Итак, код перед выполнением скармливается специальному кодеку inlinec, который разбирает программу, находит в ней метки-декораторы, компилирует вставки на Си через gcc и заменяет тело на вызовы скомпилированного через библиотеку cffi.

Оставить комментарий

Программисты-«волшебники»

Про программистов-«волшебников», большая цитата (ниже весь текст не мой).

Хочу высказаться также по триаде «объект — указатель — ссылка».

Изначально в Си (не «++») ссылок не было. Были только объекты и указатели. Любой начинающий сталкивался с указателями, как только ему требовалось впервые изменить в теле функции значение переданного функции параметра:

void func1(int i) { i = 1; }
void func2(int* i) { *i = 1; }

Далее:

int i = 0;
func1(i); // всё ещё i==0
func2(i); // вот теперь i==1

Этот код демонстрирует то свойство Си, из-за которого он называется «высокоуровневым ассемблером». В тексте языка явно указано, что происходит на уровне ассемблера. В func1 в ячейку на стеке, отведённую под параметры функции, кладут целое значение, i — имя этой ячейки. Туда пишется «1». В func2() в ячейку кладётся указатель i, то есть адрес некоторой другой ячейки, где и лежит значение. В теле явно стоит операция разадресации (*i) — «обратимся к той другой ячейке, адрес которой лежит i». Именно в ту ячейку засовываем «1».

Спрашивается, так зачем ещё потребовались ссылки? Ответ таков. В мире существует, не исчезает и даже порой ширится класс «программистов-волшебников», то есть любителей «программирования с волшебными словами». Программисты-волшебники рассуждают так: запись i = 1; хорошая и понятная. «Присвой i единицу». Запись *i = 1; — противная, компьютерная, не для людей. «Положи „1“ в ячейку, адрес которой лежит в i». Фу.

Пусть лучше в теле func2 тоже будет написано по-человечески: i=1. Однако работает пусть всё, как раньше — func1 получает на стек значение, а func2 — указатель. И оператор присваивания, с виду теперь одинаковый, пусть работает по разному. В func1 — обычное присваивание, в func2 — с разадресацией указателя. А чтобы теперь понять, как это работает, мы введём в язык волшебный значок «&». Теперь всё просто:

void func1(int i) { i = 1; }
void func1(int &i){ i = 1; }
int i = 0;
func1(i); // волшебного значка нет, i не изменилось
func2(i); // волшебный значок! i изменилось.

Смотрите, операторы в теле функций одинаковые, а работает по-разному, и всё из-за волшебного значка! При этом можно даже не разбираться, как это работает, даже не знать про какие-то указатели. Как-то само присваивается, из-за чудесного значка.

Программисты Си долго сопротивлялись, но программисты-волшебники победили, и ссылки появились в Си++.

Оставить комментарий

Числа от «n» до нуля без сравнений

На «Хабре» интересную задачу увидел, требуется написать на Си программу, выводящую числа от «n» до нуля, не используя (скрыто или явно) операторы сравнения.

Мой вариант:

#include <stdlib.h>
#include <stdio.h>

void print(const int n) {
	printf("%d\n", n - 1);
}

int main(int argc, char* argv[])
{
	const int N = atoi(argv[argc - 1]);

	void (*f[])(int) = {print, exit};
	for (int n = -1;;n++) {
		f[~n/~N](N - n);
	}
}

Оставить комментарий

Структуры в Си и CGO

По горячим следам хочу написать какая забытая мною особенность языка Си вчера ввела меня в заблуждение и почему несмотря на то, что я работал с сишной структурой, CGO так как будто не считало.

Для начала посмотрим как определяются и передаются структуры в Си. Полную спецификацию я приводить не буду, посмотрим на два распространённых способа. Первый используется в этом небольшом примере:

#include <stdio.h>
#include <math.h>

struct point {
	double x, y;
};

double point(struct point p) {
	return sqrt(pow(p.x, 2) + pow(p.y, 2));
}

int main() {
	printf("%g\n", point((struct point){1, 2}));
}

Тут можно обратить внимание на две особенности — во-первых, везде, где мы используем структуру, приходится использовать и ключевое слово struct, во-вторых, в коде существует и структура point, и функция с таким названием.

Это происходит потому, что имена структур обитают в своём собственном пространстве имён, на его использование и указывает struct. Там же живут имена объединений (union) и перечислений (enum). Имена функций находятся в общем пространстве, так что два таких определения с одним именем друг другу не мешают.

Структуры, объявленные таким образом видны через CGO компилятора Гоу как C.struct_name (C.struct_point в данном случае). К сожалению, тут есть особенность, о которую я споткнулся — если запрашиваемая структура не определена, то Гоу не выдаст ошибки, мы просто получим пустую структуру:

package main

import ("C"; . "fmt")

func main() {
	Println(C.struct_undefined{}) // ошибки не будет
}

Но программисты — люди ленивые, писать всюду struct неудобно. К счастью есть способ этого не делать — можно завести структуру, а потом дать ей имя в пространстве всех остальных типов. Это делается при помощи ключевого слова typedef позволяющего создавать алиасы типов:

struct point {
	double x, y;
};

typedef struct point point;

Теперь у нас есть два имени для одного типа — один в пространстве структур и прочего, второе — в общем пространстве. Можно даже сделать их одинаковыми, что очень удобно. Если второе имя нам ни к чему (бывают случаи, когда оно необходимо, но я не буду их тут рассматривать), то можно определить анонимную структуру и сразу дать имя этому типу в общем пространстве, так тоже будет работать.

Это нас подводит ко второму способу работы со структурами:

#include <stdio.h>
#include <math.h>

typedef struct {
	double x, y;
} point;

double veclen(point p) {
	return sqrt(pow(p.x, 2) + pow(p.y, 2));
}

int main() {
	printf("%g\n", veclen((point){1, 2}));
}

Ключевое слово struct перед типом уже не нужно, раз все имена в общем пространстве. Это же касается и CGO.

Как раз на эти грабли я и наступил — позабыл про эти все особенности. Когда я ещё писал на Си, всегда пользовался вторым способом, с именем в общем пространстве и привык к тому, что это и есть структуры.

2 комментария

Триграфы в Си

Век живи, век учись, больше заработаешь. Язык C я недолюбливаю, преимущественно из-за собственной лени, но, в своё время знал его достаточно хорошо. Но я не знал, что в C есть так называемые «триграфы»:

Вообще триграфы были придуманы для терминалов, в которых некоторых символов не хватает. В итоге вместо #define можно написать ??=define. Триграфы подменяются на нужные символы в самом начале, поэтому эти записи эквивалентны. Вместо { можно написать ??< , вместо } использовать ??>

Остальные триграфы можно найти в статье Елены Сагалаевой «Триграфы и альтернативные символы» на её персональном блоге. Кстати, очень рекомендую сам блог — отличное чтиво на темы связанные с программированием.

Оставить комментарий

Мой mod_autoindex

Испокон веков в Apache (внимание! речь идёт об Apache 1.x) существует модуль mod_autoindex — в комментариях в его исходном коде есть дата, видимо написания первой версии — 23 марта 1993 года. С тех пор модуль, очевидно, претерпевал какие-то изменения, но с 1993 года форматирование вряд ли изменилось — всё тот же тег PRE.

С 1993 года HTML обогатился таблицами и каскадными стилями (CSS). Вряд ли сейчас кто-то использует браузеры не знающие что это такое, странно, что для вывода информации в модуле mod_autoindex до сих пор используется PRE. Сам по себе модуль очень неплох — он позволяет быстро (часто для этого вообще ничего не надо делать — просто убрать индексный файл из папки) организовать файловые архивы, а главное — организовать их без использования относительно медленного скриптинга, что может часто бывает критично для сервисов, пользующихся большой популярностью.

В моём портфолио есть несколько проектов, где приходилось изобретать какие-то вещи (где-то, наверняка, велосипеды, знания о всех готовых решениях у меня нет) для улучшения производительности. Как я уже сказал, для огранизации файловых архивов иногда очень удобно использовать модуль mod_autoindex. Удобно, да вот незадача — владельцу сервиса, как правило, помимо производительности важна такая вещь как дизайн, оформление.

Стандартный модуль Apache позволяет менять, в этом плане:

  • header, т. е. часть над списком файлов (HeaderName, SuppressHTMLPreamble)
  • footer, часть под списком файлов (ReadmeName)
  • размер иконок (IconWidth, IconHeight)
  • внешний вид иконок (AddIcon, AddIconByType, AddIconByEncoding)
  • убирать из списка некоторые столбцы (SuppressLastModified, SuppressSize, SuppressDescription)
  • изменять описание файла (AddDescription)
  • и весьма ограниченно менять внешний вид выводимой информации (FoldersFirst, SuppressColumnSorting и т. п.)

Чаще всего этого для «упаковки» списка файлов в дизайн очень мало. Для облегчения задачи интеграции вывода mod_autoindex в дизайн я несколько усовершенствовал этот модуль. Всё по порядку.

Что умеет новый модуль

my_mod_autoindex (10.06КиБ)
  • Режим FancyIndex всегда включен и не выключается. Вряд ли найдётся много людей
    не использующих этот режим.
  • В основном режиме (об этом подробнее — чуть ниже) таблица файлов выводится при
    помощи тега TABLE, где у большинства объектов (например, у первой строка, чётных
    и нечётных строк) прописаны идентификаторы CSS-классов, из чего следует, что внешний
    вид таблицы вы легко сможете задать при помощи файла стилей.
  • Новая опция, позволяющая включить в листинг файла ссылку на корень сайта
    (IndexOptions +RootFolder, при использовании не забудьте добавить иконку,
    например так: «AddIcon /icons/back.gif .»)
  • Появилась возможность перенести Description в отдельную (новую) строку
    (IndexOptions +DescriptionAtNewRow)
  • Появилась возможность локализовать (перевести на родной язык) текстовую
    информацию модуля (директивы ParentStr, RootStr, NameStr, SizeStr, DescriptionStr, LastModifiedStr).
  • С первой страницы (если пользователь находится в корне сайта) убрана
    ссылка «Parent Directory», ведущая в этом случае, на ту же самую страницу.
  • Появился новый режим вывода, основанный на теге SPAN (именно он на иллюстрации),
    в частности, количество иконок в строке в этом режиме зависит от ширины окна браузера
    (IndexOptions +BoxWidth=N +BoxHeight=N +MaxIconHeight=N)

Новый режим вывода  

Прямоугольник (7.08КиБ)

Новый режим вывода включается автоматически, если были использованы параметры BoxWidth и BoxHeight. Эти два параметра отвечают за размер прямоугольника, в который заключена иконка (на иллюстрации выделено чёрным) и, по сути, определяют расстояние между соседними иконками.

Размер этот нужно выбирать исходя из размеров иконки, текста названия файла и строки, где выводится размер файла, плюс некоторое пространство, необходимое для обеспечения зазора между соседними иконками. Есть ещё один параметр — MaxIconHeight, выбрать его просто — это всего лишь максимальная высота иконки в вашем наборе. Нужен этот параметр для того, чтобы подписи к иконкам располагались на одном уровне (на иллюстации — синяя линия).

В этом режиме под иконкой выводится имя файла, размер и дата модификации (если, конечно, не были использованы опции SuppressLastModified и SuppressSize), описание файла выводится в аттрибут «title» тега SPAN, охватывающего иконку и надписи (если не была использована опция SuppressDescription) — вы можете использовать DHTML, чтобы выводить информацию из title в статусную строку, всплывающую подсказку и т. п.

Пример

Файлы для вывода информации так, как это изображено на иллюстрации выглядят так:

Файл «.htaccess»:

IndexOptions +SuppressHTMLPreamble +NameWidth=*
IndexOptions +SuppressLastModified +FoldersFirst +RootFolder +DescriptionWidth=*
IndexOptions +BoxWidth=80 +BoxHeight=80 +MaxIconHeight=33

HeaderName /_bolk_autoindex/.HEADER.html
ReadmeName /_bolk_autoindex/.FOOTER.html
ParentStr "Наверх"
RootStr "В корень"
NameStr "Имя"
SizeStr "Размер"
DescriptionStr "Описание"

Файл «.HEADER.html»:

<head>
    <title></title>
    <style type="text/css">
    td,
    body { background-color: white; font-family: Verdana,Tahoma; font-size:10px }
    a    { color: black; text-decoration:none }
    .cell0, .cell1 {text-align: center}
    a:hover { text-decoration: underline }
    </style>

</head>
<body>
<h4>Пример использования</h4>
Содержимое каталога:
<!--#echo var="DOCUMENT_URI" encoding="none" -->
<br clear="all" /><br />

Файл «.FOOTER.html»:

</body>

Где взять и как установить

Файл можно взять у меня на сайте (ZIP, около 15Кб), для установки нужно переписать его на место старого модуля (каталог src/modules/standard) и перекомпилировать Apache.   Проблемы и их решения

Часто, помимо имени файла, его размера и даты создания, хочется вывести другую полезную информацию — например, разрешение для картинок, ID3 теги для MP3 файлов и так далее. Для этой цели я рекомендую воспользоваться полем «Description» и директивой «AddDesription». Задачей модуля не является и, надеюсь, не будет являться (иначе это приведёт к снижению производительности) автоматический вывод информации такого рода. Напишите скрипт (кстати, возможно позднее я его выложу), который пробежит по каталогам и добавит эту информацию в соответствующие .htaccess файлы и вызывайте его далее по мере необходимости.

Один из заказчиков попросил предоставить пользователю возможность самому выбирать какой вид листинга файлов он хочет получить — табличный или в виде иконок. К сожалению, у Apache 1.x нет методов переключения конфигурации в зависимости от каких-то внешних условий «на лету», так что было выбрано такое решение. На портах 80 и 443 (обычно используется для HTTPS-соединений) были заведены два виртуальных хоста:

<VirtualHost example.com:80>
...
AccessFileName .htaccess .htaccess-table
...
</VirtualHost>

<VirtualHost example.com:443>
...
AccessFileName .htaccess .htaccess-icons
...
</VirtualHost>

где прописаны одно общее имя .htaccess-файла для общих настроек и деректив AddDescription и два разных имени для различных наборов настроек mod_autoindex. Переключение происходит перенаправлением пользователя на определённый порт.   Хотелось бы ещё…

По всем вопросам, с пожеланиями по улучшению — добро пожаловать в мой почтовый ящик, он есть на моём сайте внизу каждой страницы.

Оставить комментарий

← 1 2 3 →