• Введение
  • Начинаем
  • Читаем текстовый файл
  • Устанавливаем стиль заголовка
  • Редактирование строки
  • Создание FB2
  • Структура
  • Приложение
  • Unit1.dfm
  • Код файла Unit1.pas соответствующего Form1
  • genres.dfm
  • genres.pas
  • EditStr.dfm
  • EditStr.pas
  • authors.dfm
  • authors.pas
  • dm.pas
  • my_FB2.dpr
  • UmFB2.pas
  • Пишем программу (в Delphi) для создания книг FB2

    Введение

    В начале было слово, и слово было 2 байта…

    (Автор мне неизвестен.)

    Все началось с покупки электронной книжки LBook eReader V3.

    Затем я убедился, что книги, лучше всего читаются в формате FB2.

    Потом мне захотелось оцифровать книги моего любимого писателя Кальмана Миксата, и тут я увидел, что все не так просто…

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

    Состряпал программку, конечно еще сырую, а потом вспомнил опыт Линуса Торвальдса и подумал:

    - А, кину я исходник в рунет, и может добрые люди выкормят, вырастят моего ребенка и выведут в люди.

    Вы можете спросить, а чего же ты сам это не сделаешь? Во-первых, меня ждут другие "великие дела", во-вторых, я уверен, что коллективным разумом, можно сделать больше и быстрее…

    Писал я в своем любимом Delphi (Delphi 6) - но думаю это не принципиально, перевести можно в любой язык.

    Это не учебник Delphi и основы, я рассказывать не собираюсь, но постараюсь расписать как можно подробней.

    В программе используются только стандартные компоненты Дельфи.

    Начинаем

    План работы:

    * Берем текстовый файл

    * Присваиваем строчкам стили

    * Делаем файл FB2.


    Общие принципы программы.

    Содержание книги будет хранится в ListBox1.

    Каждая строчка в ListBox1 будет содержать абзац текста и будет начинаться с идентификатора стиля абзаца, например:

    // начало примера.

    H1 | Кальман Миксат. ЧЕРНЫЙ ГОРОД

    H2 | ЧАСТЬ ПЕРВАЯ

    H3 | ГЛАВА ПЕРВАЯ.

    S| В которой содержатся сведения и подробности, весьма важные для читателя

    N| Пал Гёргей был самым примечательным вице-губернатором Спеша во времена Тёкёли

    // конец примера.

    Символ | отделяет информацию о стиле от строки текста. Теперь надо объяснить, что означают эти буковки.

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

    S: Subtitle - подзаголовок.

    N: Normal - обычный абзац.

    Еще могут использоваться стили:

    E: Epigraph - эпиграф

    T: Text-author - автор цитаты / эпиграфа

    P: Poem - стихи

    -: None строка будет игнорироваться при записи FB2 файла.

    Если потребуется Вы добавите еще…

    Читаем текстовый файл

    При чтении текстового файла, к каждой строчке прибавляется начало ' N| ' т. к. форматирование еще не сделано и все строки одинаково обычны.


    // начало кода

    procedure LoadTXT(FName: string);

    var

    L: TStringList;

    i, j: integer;

    s, ss: string;

    begin


    L:= TStringList.Create; // создаем временный список

    L.LoadFromFile(fname); // читаем из файла // можно сделать грамотнее с помощью try

    for i:= 0 to L.Count - 1 do// просматриваем текст

    begin

    s:= ''; ss:= L[i];

    for j:= 1 to length(Ss) do

    begin // просматриваем строку

    case ss[j] of

    '<': S:= S + '&#60;'; // знак < вызывает сбой в читалке. т. к. она думает что дальше следует тэг

    '>': S:= S + '&#62;'; // заменяем, на всякий случай

    '^': S:= S + '&#94;'; // этот символ будет использован в служебных целях

    '~': S:= S + '&#126;'; // - // -

    '&': S:= S + '&#38;';

    else S:= S + ss[j]; // иначе, претензий нет, символ добавляем к строке

    end; // case

    end; // обработка строки завершена

    L[i]:= ' N| ' + S; // в начало каждой строки вводим указатель стиля Normal

    end; // обработка текста завершена

    Form1.ListBox1.Items.Assign(L); // сбрасываем список в ListBox

    L.Free; // удаляем временный список

    end;

    // конец кода


    Если файл считан, теперь мы можем его форматировать.

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

    [>]

    При этом вызывается процедура ChangeStyle(TmyStyle(RG.itemindex));

    Как параметр она получает стиль из радио - списка RG.

    К сожалению это все делать надо ручками. Конечно, возможна некая автоматизация, но пока идет речь об упрощенной программе…


    Процедура считывает выделенную строку из списка ListBox1, удаляет сведения о типе и записывает строку на старое место с новым стилем.


    // начало кода

    procedure ChangeStyle(LStyle: TmyStyle);

    var

    n, curIndex: integer;

    S: string;

    begin

    with Form1.ListBox1 do

    begin

    curIndex:= ItemIndex; // читаем текущий индекс в списке ListBox

    if curIndex = -1 then exit; // если ничего не выделено выходим


    S:= Items[curIndex]; // считываем текущую строку

    n:= pos('|', s); // находим разделитель

    / / хотя это лишнее, n всегда = 4 / когда писал это еще не было ясно, утрясался формат…

    // в окончательном варианте n можно удалить

    delete(S, 1, n+1); // удаляем информацию о стиле

    // Записывается строка с новым стилем. Приводить SetStyle не буду, она очень простенькая

    Items[curIndex]:= SetStyle1(LStyle)+ S;

    if ItemIndex < Items.Count - 1

    then ItemIndex:= ItemIndex+1;

    SetFocus; // активным снова становится список с содержимым книги.

    end;

    end;

    // конец кода


    (Одно предложение: можно, и не трудно, предоставить пользователю возможность возврата старого стиля)


    Теперь о расстановке заголовков

    Для этой работы предназначены три кнопки: [+] [H1] [-]. Вообще-то средняя кнопка будем менять свое название, и показывать этим текущий (в данном месте текста) стиль заголовка.

    Посмотрим, как это делается:

    При любом клике на ListBox вызывается процедура ShowHeadStyle ее параметром является индекс выделенной строки.


    // начало кода

    procedure ShowHeadStyle(n: integer);

    var

    LStyle: TmyStyle;

    begin

    LStyle:= ScanUpStyle(n); // получаем тип заголовка к которому относится эта строка

    Form1.Button2.Caption:= SetStyle(LStyle); // меняем название кнопки

    Form1.Button2.Tag:= integer(LStyle); // запоминаем этот стиль, чтобы потом меньше возиться.

    end;

    // конец кода


    Теперь посмотрим, как мы получаем информацию о стиле.

    Элементарно, Ватсон!


    // начало кода

    function ScanUpStyle(n: integer):TmyStyle;

    var

    i: integer;

    LStyle: TmyStyle;

    begin

    with Form1.ListBox1 do

    for i:= n downto 0 do

    begin // просматриваем список от заданной строки вверх

    GetStyle(Items[i], LStyle); // получаем стиль строки

    if LStyle in [H1..H5] then

    begin // если стиль строки заголовочный

    result:= LStyle; // записываем его в результат

    exit; // и выходим, нечего больше время терять!

    end;

    end; // если дошли до начала списка, а заголовков не найдено…

    result:= H1; // присваиваем тип заголовка H1

    end;

    // конец кода

    Устанавливаем стиль заголовка

    Выбираем строку в тексте

    И если указанный на кнопке стиль подходит, нажимаем ее.

    При этом вызывается процедура ChangeStyle(TmyStyle(Button2.Tag));

    Параметром ее будет ранее сохраненные сведения о текущем стиле заголовка.

    Процедура ChangeStyle описана ранее.

    Теперь кнопки [+] и [-]

    Код процедур аналогичен, разница только в одной строчке


    // начало кода

    procedure TForm1.Button5Click(Sender: TObject);

    var // кнопка плюс

    LStyle: TmyStyle;

    begin

    LStyle:= TmyStyle(Button2.Tag); // получаем текущий стиль

    if LStyle < H5 then ChangeStyle(Succ(LStyle)); // если он не слишком велик, прибавляем единицу

    // а для кнопки минус, вот эта строчка. Вычитается единичка, если есть откуда вычитать

    // if LStyle > H1 then ChangeStyle(Pred(LStyle));

    end;

    // конец кода

    Редактирование строки

    Двойной щелчок на строке и открывается окно редактирования

    Текст можно исправить или строку разбить на несколько. После нажатия ОК все содержимое записывается в книгу с сохранением старого стиля.

    Нажатием кнопок Bold и Italic можно получить соответствующее оформление выделенного текста

    (т. е. если текст не выделен ничего не произойдет).

    Тут два замечания: отмена такого форматирования возможна только вручную удалением соответствующих тегов, второе, не допустимо форматирование такого вида:

    <strong> <emphasis> какой либо текст </strong></emphasis>. Можно конечно отслеживать такую ошибку и программным путем, но небольшое облегчение жизни пользователя, резко усложняет жизнь программиста.


    Концевые сноски.

    Книга может содержать концевые сноски. Я поленился и сделал пока так: необходимые сноски записываются в файл EndNotes.txt и этот файл должен находится в папке программы.

    Внимание! Каждая сноска - одна строка в файле.

    В тексте книги в местах сносок надо расставить значки тильды - ~


    Ударения.

    В первой же книге, которую я делал, в одном слове мне потребовалось сделать ударение и поэтому пришлось ввести значок «крышки» ^

    Создание FB2

    Наконец добрались.

    Казалось бы, что проще, бери строку за строкой и вперед…

    // начало кода

    with Form1.ListBox1 do

    for i:= 0 to Count - 1 do // просматриваем текст абзац за абзацем

    begin

    S:= Items[i]; // считываем строку

    Ss:= GetStyle(S, CurStyle); // получаем чистую строку и стиль

    s:= ''; // подготавливаемся к преобразованию строки

    if ss <> '' then

    for j:= 1 to length(Ss) do

    begin // просматриваем строку посимвольно

    case ss[j] of

    '~': begin // если это концевая сноска

    S:= S + '<a l: href="#n_'+IntToStr(EndNotes_count)+'" type="note">'

    +IntToStr(EndNotes_count)+'</a>';

    inc(EndNotes_count); // увеличиваем счетчик сносок

    end;

    '^': S:= S + '&#769;'; // ставим ударение

    else S:= S + ss[j]; // иначе записываем символ в итоговую строку

    end; // case

    end;

    // тут я пока немножко пропущу

    // анализ стилей

    case CurStyle of // в зависимости от стиля абзаца

    Norm,Epig,Citat: OutList.Add('<p>'+S+'</p>');

    H1..H5: StyleStucture; // Heading

    Sub: OutList.Add('<subtitle>'+s+'</subtitle>'); // Subtitle

    // конец кода

    Давайте рассмотрим все по порядку:

    Начнем со стихов. В стандарте FB2 используется три тега для работы со стихами, я использую только один стиль "P".

    Для разделения стихов на строфы я предлагаю использовать пустые строки помеченные стилем "P".


    // начало кода

    if (CurStyle <> oldStyle) then // если предыдущий стиль отличен от текущего

    begin // а нынешний стиль есть в данном списке, то значит надо начинать нужный блок.

    case CurStyle of // начало блока

    Poem: OutList.Add('<poem><stanza>');

    Epig: OutList.Add('<epigraph>');

    Citat: OutList.Add('<cite>');

    end; // case начало блока

    end;

    // конец кода


    А для обработки стиля используется следующие строки

    // начало кода

    case CurStyle of // в зависимости от стиля абзаца

    Norm,Epig,Citat: OutList.Add('<p>'+S+'</p>');

    Poem: begin

    if S = ''

    then OutList.Add('</stanza><stanza>')

    else OutList.Add('<v>'+S+'</v>');

    end;

    // конец кода


    В случае Нормальное стиля, Эпиграфа и Цитаты, просто добавляются абзацы, а для стихов еще отслеживается пустая строка…


    Как видите блоки не завершены. Эту функцию выполняет следующий код.


    // начало кода

    if (CurStyle <> oldStyle) and (CurStyle <> Auth) then

    begin

    case oldStyle of // завершение предыдущего блока

    Poem: OutList.Add('</stanza></poem>');

    Epig: OutList.Add('</epigraph>');

    Citat: OutList.Add('</cite>');


    end; // case завершение предыдущего блока

    end;

    // конец кода


    Но как Вы увидите в исходнике последний программный кусок находится выше предыдущего (и вообще все немного не так), но в данном тексте, мне пришлось расположить их так для последовательного, логичного объяснения, а в программе: сначала проверяется завершенность предыдущих блоков, затем при необходимости начинается другой, а затем обрабатываем текущий стиль.

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


    Если Вы внимательно следите за процессом, то заметили " and (CurStyle <> Auth) " в предыдущем кусочке о начале блока, я это дело опустил, что бы не затуманивать описание.

    Это достаточно забавный код призван выполнить требования формата:

    // начало цитаты

    Внутри тэгов <poem>, <cite> и <epigraph> возможно указать автора соответственно стихотворения, цитаты или эпиграфа. Для этого служит тэг <text-author>. Этот тэг должен стоять в самом конце родительского тэга, то есть непосредственно перед его закрытием.

    // конец цитаты


    А теперь как это я сделал.

    // начало кода

    Auth: begin

    OutList.Add('<text-author>'+S+'</text-author>');

    if oldStyle in [Poem, Epig, Citat]

    then CurStyle:= oldStyle;

    // т. е. корректно отработается закрытие родительских блоков

    end;

    // конец кода


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

    ДОПОТОПНАЯ КОСТЬ[1] (Аполлон Майков)
    Я с содроганием смотрел
    На эту кость иного века…
    И нас такой же ждет удел:
    Пройдет и время человека…
    Умолкнет славы нашей шум;
    Умрут о людях и преданья;
    Всё, чем могуч и горд наш ум,
    В иные не войдет созданья.
    Оледенелою звездой
    Или потухнувшим волканом
    Помчится, как корабль пустой,
    Земля небесным океаном.
    И, странствуя между миров,
    Воссядет дух мимолетящий
    На остов наших городов,
    Как на гранит неговорящий
    Так разум в тайнах бытия
    Читает нам… Но сердце бьется,
    Надежду робкую тая -
    Авось он, гордый, ошибется!
    1857

    Структура

    Теперь, после лирического отступления, самое интересное: структурирование книги.

    Книга может иметь разделение на части, главы, тома и книги, ну мало ли чего придумает автор…

    В FB2 структура задается тэгами <section> разной степени вложенности. Но в любом случае эта структура - дерево. В корне(в первой строчке), я предлагаю писать название книги, а дальше части, главы или что там есть.

    Программе для обработки структуры понадобится стек (напомню, стек - это список с правилом "последний пришел - первый вышел")


    Полученный код FB2, как эталоном, я проверяю программой "FictionBook Editor". Так вот, экзаменатору не нравится такая структура:


    // начало примера

    H1 | Кальман Миксат. ОСАДА БЕСТЕРЦЕ

    S| (История одного чудака)

    H2 | ВВЕДЕНИЕ

    // конец примера


    Т.е. между секциями не должно быть ничего лишнего…

    А вот так будет все нормально:


    // начало примера

    H1 | Кальман Миксат. ОСАДА БЕСТЕРЦЕ

    H1 | (История одного чудака)

    H2 | ВВЕДЕНИЕ

    // конец примера


    Итак, когда при обработке списка ListBox1 встречается строка с типом от H1 до H5 вызывается процедура StyleStucture;

    // начало кода

    procedure StyleStucture;

    begin

    if CurStyle <> oldStyle then

    begin // пока предположим, что предыдущий стиль был не заголовок

    if SytleStack.Count = 0 then // если стек пуст

    begin // записываем стиль в стек

    SytleStack.Add(TObject(CurStyle))

    end

    else // если в стеке что-то есть

    begin // значит надо проверить последний из заголовков

    LastStyle:= TmyStyle(SytleStack.Last); // считываем последний стиль

    case SubStyle(CurStyle, LastStyle) of // вычисляем разность текущий стиль минус последний

    0: OutList.Add('</section>'); // стили равны, ничего особенного делать не надо

    1: SytleStack.Add(TObject(CurStyle)); // новый стиль больше, добавляем его в стек

    // предыдущая секция не закончилась, т. к. новая будет в ее входить как матрешка

    else // иначе, считаем что разность меньше нуля

    begin

    OutList.Add('</section>');

    while CurStyle <>LastStyle do

    begin

    SytleStack.Delete(SytleStack.Count-1); // уменьшаем стек

    OutList.Add('</section>'); // завершаем секции до тех пор пока

    LastStyle:= TmyStyle(SytleStack.Last); // текущий стиль и стиль в стеке не сравняются.

    end;

    end;

    end;// case

    end;

    OutList.Add('<section>'); // начинаем новую секцию

    OutList.Add('<title>');

    end;

    OutList.Add('<p>'+s+'</p>'); // записываем заголовок секции

    end; // StyleStucture;

    // конец кода


    Пожалуй, это самый тяжелый код в данном манускрипте, но он вроде работает, хотя я вижу в нем по крайней мере две неувязки, но что это, не скажу…


    Ну вот с обработкой книги почти закончили, мелкие подробности увидите в исходнике.


    Нажимаем пункт меню File - Save as FB2.

    И - ничего не получается. Запланированная шутка. Вылезла надпись "Заполнить поля" и фокус перенаправлен на начальную закладку.

    Напоминаю FB2 - это не только легкоусвояемый (легкоусваиваемый) текст, но и очень нужный и полезный заголовок книги.

    Давайте посмотрим, все таки, что происходит при выборе пункта Save as FB2

    // начало кода

    procedure TForm1.SaveasFB21Click(Sender: TObject);

    begin

    if not BookHaveName then // проверяем, все ли в порядке в заголовке

    begin // если нет, то происходит все то что Вы видели

    PageControl1.ActivePageIndex:= 0;

    ShowMessage('Fill the form.');

    exit;

    end;

    SaveDialog1.FileName:= form1.FB2_file.Text;

    if SaveDialog1.Execute then

    Make_fb2(SaveDialog1.FileName);

    end;

    // конец кода


    Посмотрим на процедуру BookHaveName

    // начало кода

    function BookHaveName: boolean;

    begin

    with Form1 do

    result:= (book_title.Text <> '') and

    (FB2_file.Text <> '') and

    (GenresBox.Count > 0);

    end;

    // конец кода

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


    А я пока вернусь к заполнению заголовка.

    В программе Вы видите три закладки Title-info, Document-info и Publish-info. В формате FB2 есть еще кое-что, но я пока это игнорировал. Предоставляю Вам такую возможность. Код Вам в руки…


    Итак Title-info

    Поле Project - само заполнится при открытии текстового файла. При желании, Вы можете изменить, имя сохраняемого fb2 файла.


    Поле book-title действительно обязательно надо заполнить


    Теперь Genre - Жанр.

    Ага, тут немного интереснее, есть о чем погуторить.

    Нажимаем кнопку с тремя точками.

    И открывается окошко Жанры.

    Наша цель добавить один или несколько жанров в левый ListBox.

    Выберите подходящий жанр в правом ListBoxсике и нажмите кнопку Add

    В навигации по жанрам поможет верхний ComboBox

    О коде в этом unit мне говорить лень, ничего особенного, рутина.

    Интереснее, вот, что, информация для загрузки в эти Боксики находится в unit dm

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

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


    Вернемся к заполнению заголовка

    Нам надо ввести данные об авторе / авторах и переводчике / переводчиках

    Так же нажимаем на соответствующую кнопочку с троеточием и работаем в открывшемся окне.


    Вы уже наверно заметили, что мне прискучило очень уж подробно расписывать код. Но в данном unit тоже ничего особенного, единственно, пришлось ввести структуру TPerson, я думаю Вы легко разберетесь зачем она мне нужна.

    Мне интереснее, совершенствование программы. Представьте ситуацию, Вы делаете 10 книг (или 100) одного автора и каждый раз делая новую книгу, заполняете опять и опять данные об этом человеке. Мне было бы лень. Ваши предложения?…


    Ну хорошо мы заполнили и Title-info и Document-info и Publish-info.


    Давайте-ка глянем, что там в коде записи файла FB2.


    // начало кода

    Procedure Make_fb2(S: string);

    begin //

    if Form1.ListBox1.Items.Count = 0 then exit;

    SytleStack.Clear; // подготовка стека стилей

    OutList.Clear; // подготовка выходного списка

    SaveDescription;

    SaveBodyFB2; // это мы уже в общем рассмотрели

    SaveEndnotes;

    OutList.Add('</FictionBook>'); // закрываем книгу

    OutList.SaveToFile(S); // Запись в файл

    showMessage('Done.'); // Сообщаем об удачном завершении

    end;

    // конец кода


    Как видите мы еще не рассмотрели две процедуры.


    // начало кода

    procedure SaveDescription;

    const

    max = 5; // может я захочу изменить число строк в массиве, тогда я изменю только одну цифру

    mas: array[1.. max] of string =

    (// массив для заголовочной части FB2 файла

    '<?xml version="1.0" encoding="windows-1251"?>', // как видите я делаю файл в кодировке Win

    // я не вижу смысла в применении юникода, но если речь идет не о русском языке,

    // то сделайте здесь изменение.

    '<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0"',

    ' xmlns: l="http://www.w3.org/1999/xlink">',

    ' <description>',

    ' <title-info>'

    );

    var i: byte;

    begin

    // Выводим в выходной файл начало FB2 файла

    for i:= 1 to max do

    OutList.Add(Mas[i]);

    // конец кода

    Дальше просматриваем списки Жанров, Автором и Переводчиков и выводим оттуда информацию (если она там есть).

    Т.е. проверяем все заполненные поля форм описывающих книгу и выводим информацию в соответствующие секции заголовка книги.


    Будем считать, что с Description - покончили.


    Осталось только


    // начало кода

    procedure SaveEndnotes;

    var

    S: string;

    i: integer;

    begin

    if Form1.EndNotesList.Items.Count = 0 then exit;


    OutList.Add('<body name="notes"><title><p>Примечания</p></title>');


    for i:= 0 to Form1.EndNotesList.Items.Count - 1 do

    begin

    S:= Form1.EndNotesList.Items[i];

    OutList.Add('<section id="n_'+IntToStr(i+1)+'"><title><p>'+IntToStr(i+1)+'</p>');

    OutList.Add('</title><p>'+S+'</p>');

    OutList.Add('</section>');

    end;


    OutList.Add('</body>');

    end;

    // конец кода


    Согласитесь, что здесь все просто, просматриваем список сносок и соблюдаем формат FB2. Но остается один маленький вопрос, а что если нам нужно будет вывести многострочную (точнее много абзачную) сноску. Да, возникает вопрос, приходят и варианты решения…


    Ладно, кое-что в коде я пропустил. Но основные недостатки программы, я кажется описал. Правда, наверняка есть ляпы, которые я не заметил…


    Наконец файл книги в формате FB2 создан.


    На этом все? Ну нет, сейчас все авторы заканчивают книги словами "Продолжение следует". И я замыслил по крайней мере одно продолжение. Мне кажется оно просто необходимо.

    Программа должна уметь не только создавать, но и читать файл FB2. Тогда можно растягивать удовольствие изготовления книги на несколько дней, и не потребуется каждый раз заново: читать текстовый файл, расставлять стили, форматировать строки и т. д. и все это с одной и той же книгой - ужас.

    Но, как известно из математики, обратная задача всегда сложнее прямой. И т. к. я считаю, что на сегодня уже достаточно утомил Вас. Давайте рассказ о второй версии программы отложим.


    Связаться со мной Вы сможете по адресу w__cat@mail.ru (обратите внимание, 2 подчеркивания, т. к. w_cat@mail.ru оказался уже занят). Предупреждаю сразу, я ленив, почту смотрю не каждый день, да и отвечать всем может и не смогу (я же не знаю сколько найдется желающих мне написать). Второе, эту почту я специально завел для этой программки, и если Вы, друзья мои завалите ее спамом или матом, я просто забуду туда дорогу.


    Лицензионные условия таковы, пользуйтесь на здоровье, копируйте, переделывайте, если сможете заработать на этом деньги, буду только рад.


    Карпов Юрий.

    Кохтла-Ярве.

    2010.


    Итак.

    Продолжение следует…

    Приложение

    Исходный код программы.

    Выложил исходник на один сайт, но боюсь, что там ему и потерянному быть…

    Поэтому, не буду ждать милости, справимся и сами.

    Для начала, извлечем исходник из этого файла.


    «Нет таких задач, которые не могли бы решить комму… (извиняюсь) программисты!»


    Сделаем копию этого файла. Переименуем его как текст. В этом тексте найдем слово «Приложение». Удалим все до этого слова, да и немного далее, до начала исходного текста.

    Теперь заменим все <p> и </p> на пустое место.

    Еще заменим:

    <empty-line/> на пустое место.

    &#38; на &

    &lt; на <

    &gt; на >

    «Цели определены, задачи поставлены, за работу товарищи…»



    Программа состоит из 4 форм и 6 файлов pas, всего около 50 кбайт.

    Далее, последует инструкция, как сделать программку.

    Если Delphi 5 и выше то все просто.

    Получившийся пирожок, нужно разрезать на отдельные файлы и назвать так как они подписаны

    И запустить проект.


    Иначе придется повозится.

    В новой папочке создайте пустой проект Delphi.


    На форме кликните правой кнопкой мыши и выберите View as Text

    Скопируйте код формы из книги (не захватывая слова "начало кода" и "конец кода"). Вставьте его в открытое окно. Нажмите правую кнопку мыши и выберите View as Form. Если все сделано правильно Вы увидите форму.

    Скопируйте код соответствующего unit. Замените им код в окне Code.

    Хорошо, одна форма сделана.


    Теперь создайте новую форму File - New - Form

    И повторите предыдущие операции

    Форм и соответствующих им Юнитов нужно сделать 4:

    Unit1.dfm, genres.dfm, EditStr.dfm, authors.dfm

    Unit1.pas, genres.pas, EditStr.pas, authors.pas

    Файлы UmFB2.pas и dm.pas форм не имеют т.е. просто сделайте их из текстовых.


    Итак, начали.

    Unit1.dfm

    // начало кода

    object Form1: TForm1

    Left = 187

    Top = 98

    Width = 722

    Height = 463

    Caption = 'Form1'

    Color = clBtnFace

    Font.Charset = DEFAULT_CHARSET

    Font.Color = clWindowText

    Font.Height = -11

    Font.Name = 'MS Sans Serif'

    Font.Style = []

    Menu = MainMenu1

    OldCreateOrder = False

    OnCreate = FormCreate

    PixelsPerInch = 96

    TextHeight = 13

    object PageControl1: TPageControl

    Left = 0

    Top = 0

    Width = 714

    Height = 417

    ActivePage = TabSheet2

    Align = alClient

    TabIndex = 3

    TabOrder = 0

    object TabSheet1: TTabSheet

    Caption = 'title-info'

    object Annotation: TMemo

    Left = 0

    Top = 273

    Width = 706

    Height = 116

    Align = alClient

    ScrollBars = ssVertical

    TabOrder = 0

    WordWrap = False

    end

    object Panel3: TPanel

    Left = 0

    Top = 0

    Width = 706

    Height = 273

    Align = alTop

    BevelOuter = bvNone

    TabOrder = 1

    object Lbook_title: TLabel

    Left = 8

    Top = 64

    Width = 43

    Height = 13

    Caption = 'book-title'

    end

    object LProject: TLabel

    Left = 8

    Top = 8

    Width = 36

    Height = 13

    Caption = 'Project:'

    end

    object LAnnotation: TLabel

    Left = 16

    Top = 240

    Width = 51

    Height = 13

    Caption = 'Annotation'

    end

    object Lsequence: TLabel

    Left = 16

    Top = 176

    Width = 49

    Height = 13

    Caption = 'Sequence'

    end

    object LLang: TLabel

    Left = 376

    Top = 176

    Width = 27

    Height = 13

    Caption = 'Lang.'

    end

    object Lsrc_lang: TLabel

    Left = 456

    Top = 176

    Width = 49

    Height = 13

    Caption = 'Src. Lang.'

    end

    object LTome: TLabel

    Left = 200

    Top = 176

    Width = 27

    Height = 13

    Caption = 'Tome'

    end

    object book_title: TEdit

    Left = 64

    Top = 56

    Width = 217

    Height = 21

    TabOrder = 0

    end

    object FB2_file: TEdit

    Left = 8

    Top = 24

    Width = 273

    Height = 21

    TabOrder = 1

    end

    object Au: TGroupBox

    Left = 296

    Top = 8

    Width = 185

    Height = 153

    Caption = ' Authors '

    TabOrder = 2

    object ListBox3: TListBox

    Left = 8

    Top = 15

    Width = 169

    Height = 106

    ItemHeight = 13

    TabOrder = 0

    end

    object Button10: TButton

    Left = 152

    Top = 124

    Width = 25

    Height = 25

    Caption = '...'

    TabOrder = 1

    OnClick = Button10Click

    end

    end

    object GroupBox1: TGroupBox

    Left = 8

    Top = 88

    Width = 273

    Height = 73

    Caption = ' Genre '

    ParentShowHint = False

    ShowHint = False

    TabOrder = 3

    object GenresBox: TListBox

    Left = 8

    Top = 15

    Width = 225

    Height = 50

    ItemHeight = 13

    TabOrder = 0

    end

    object Button4: TButton

    Left = 240

    Top = 40

    Width = 25

    Height = 25

    Caption = '…'

    Font.Charset = DEFAULT_CHARSET

    Font.Color = clWindowText

    Font.Height = -13

    Font.Name = 'MS Sans Serif'

    Font.Style = []

    ParentFont = False

    TabOrder = 1

    OnClick = Button4Click

    end

    end

    object GroupBox3: TGroupBox

    Left = 480

    Top = 8

    Width = 185

    Height = 153

    Caption = ' Translator '

    TabOrder = 4

    object ListBox2: TListBox

    Left = 8

    Top = 15

    Width = 169

    Height = 106

    ItemHeight = 13

    TabOrder = 0

    end

    object Button7: TButton

    Left = 152

    Top = 124

    Width = 25

    Height = 25

    Caption = '…'

    TabOrder = 1

    OnClick = Button7Click

    end

    end

    object sequence: TEdit

    Left = 40

    Top = 192

    Width = 169

    Height = 21

    TabOrder = 5

    end

    object tome: TEdit

    Left = 216

    Top = 192

    Width = 33

    Height = 21

    TabOrder = 6

    end

    object Lang: TComboBox

    Left = 376

    Top = 192

    Width = 65

    Height = 21

    ItemHeight = 13

    TabOrder = 7

    Text = 'ru'

    Items.Strings = (

    'ru'

    'en')

    end

    object SLang: TComboBox

    Left = 456

    Top = 192

    Width = 145

    Height = 21

    ItemHeight = 13

    TabOrder = 8

    end

    object Button9: TButton

    Left = 88

    Top = 238

    Width = 121

    Height = 17

    Caption = 'Load annotation'

    TabOrder = 9

    OnClick = Button9Click

    end

    end

    end

    object TabSheet3: TTabSheet

    Caption = 'document-info'

    ImageIndex = 2

    object Lurl: TLabel

    Left = 32

    Top = 40

    Width = 28

    Height = 13

    Caption = 'src-url'

    end

    object LID: TLabel

    Left = 32

    Top = 120

    Width = 11

    Height = 13

    Caption = 'ID'

    end

    object Lversion: TLabel

    Left = 24

    Top = 200

    Width = 34

    Height = 13

    Caption = 'version'

    end

    object url: TEdit

    Left = 40

    Top = 64

    Width = 553

    Height = 21

    TabOrder = 0

    end

    object id: TEdit

    Left = 40

    Top = 144

    Width = 241

    Height = 21

    TabOrder = 1

    end

    object version: TEdit

    Left = 40

    Top = 224

    Width = 65

    Height = 21

    TabOrder = 2

    Text = '1.0'

    end

    end

    object TabSheet6: TTabSheet

    Caption = 'publish-info'

    ImageIndex = 3

    object LISBN: TLabel

    Left = 40

    Top = 80

    Width = 25

    Height = 13

    Caption = 'ISBN'

    end

    object LBook_name: TLabel

    Left = 16

    Top = 32

    Width = 54

    Height = 13

    Caption = 'Book name'

    end

    object Lpublisher: TLabel

    Left = 16

    Top = 128

    Width = 42

    Height = 13

    Caption = 'publisher'

    end

    object Lcity: TLabel

    Left = 32

    Top = 200

    Width = 16

    Height = 13

    Caption = 'city'

    end

    object Lyear: TLabel

    Left = 280

    Top = 200

    Width = 20

    Height = 13

    Caption = 'year'

    end

    object isbn: TEdit

    Left = 80

    Top = 72

    Width = 217

    Height = 21

    TabOrder = 0

    end

    object Book_name: TEdit

    Left = 80

    Top = 24

    Width = 561

    Height = 21

    TabOrder = 1

    end

    object publisher: TEdit

    Left = 80

    Top = 120

    Width = 553

    Height = 21

    TabOrder = 2

    end

    object year: TEdit

    Left = 312

    Top = 196

    Width = 57

    Height = 21

    TabOrder = 3

    end

    object city: TEdit

    Left = 80

    Top = 192

    Width = 145

    Height = 21

    TabOrder = 4

    end

    end

    object TabSheet2: TTabSheet

    Caption = 'Content'

    ImageIndex = 1

    object Panel1: TPanel

    Left = 0

    Top = 0

    Width = 706

    Height = 41

    Align = alTop

    TabOrder = 0

    end

    object Panel2: TPanel

    Left = 0

    Top = 41

    Width = 265

    Height = 348

    Align = alLeft

    BevelOuter = bvNone

    TabOrder = 1

    object Button12: TButton

    Left = 216

    Top = 123

    Width = 33

    Height = 25

    Caption = '>'

    Font.Charset = DEFAULT_CHARSET

    Font.Color = clWindowText

    Font.Height = -21

    Font.Name = 'MS Sans Serif'

    Font.Style = []

    ParentFont = False

    TabOrder = 0

    OnClick = Button12Click

    end

    object RG: TRadioGroup

    Left = 16

    Top = 72

    Width = 177

    Height = 193

    Caption = ' Styles '

    ItemIndex = 0

    Items.Strings = (

    'Normal'

    'Epigraph'

    'Text-author'

    'Subtitle'

    'Poem'

    'Citation'

    'None')

    TabOrder = 1

    end

    object GroupBox2: TGroupBox

    Left = 16

    Top = 0

    Width = 177

    Height = 65

    Caption = ' Heading '

    TabOrder = 2

    object Button1: TButton

    Left = 16

    Top = 24

    Width = 25

    Height = 25

    Caption = '-'

    Font.Charset = DEFAULT_CHARSET

    Font.Color = clWindowText

    Font.Height = -24

    Font.Name = 'MS Sans Serif'

    Font.Style = []

    ParentFont = False

    TabOrder = 0

    OnClick = Button1Click

    end

    object Button2: TButton

    Left = 72

    Top = 24

    Width = 33

    Height = 25

    Caption = 'H1'

    TabOrder = 1

    OnClick = Button2Click

    end

    object Button5: TButton

    Left = 128

    Top = 24

    Width = 25

    Height = 25

    Caption = '+'

    Font.Charset = DEFAULT_CHARSET

    Font.Color = clWindowText

    Font.Height = -19

    Font.Name = 'MS Sans Serif'

    Font.Style = []

    ParentFont = False

    TabOrder = 2

    OnClick = Button5Click

    end

    end

    end

    object ListBox1: TListBox

    Left = 265

    Top = 41

    Width = 441

    Height = 348

    Align = alClient

    Font.Charset = RUSSIAN_CHARSET

    Font.Color = clWindowText

    Font.Height = -11

    Font.Name = 'Courier'

    Font.Style = []

    ItemHeight = 13

    ParentFont = False

    TabOrder = 2

    OnClick = ListBox1Click

    OnDblClick = ListBox1DblClick

    end

    end

    object TabSheet4: TTabSheet

    Caption = 'End Notes'

    ImageIndex = 4

    object Panel4: TPanel

    Left = 0

    Top = 0

    Width = 706

    Height = 41

    Align = alTop

    TabOrder = 0

    object Button3: TButton

    Left = 8

    Top = 8

    Width = 105

    Height = 25

    Caption = 'Load End Notes'

    TabOrder = 0

    OnClick = Button3Click

    end

    end

    object EndNotesList: TListBox

    Left = 0

    Top = 41

    Width = 706

    Height = 348

    Align = alClient

    ItemHeight = 13

    TabOrder = 1

    end

    end

    end

    object MainMenu1: TMainMenu

    Left = 208

    Top = 32

    object File1: TMenuItem

    Caption = 'File'

    object Open1: TMenuItem

    Caption = 'Open'

    OnClick = Open1Click

    end

    object SaveasFB21: TMenuItem

    Caption = 'Save as FB2'

    OnClick = SaveasFB21Click

    end

    end

    end

    object OpenDialog1: TOpenDialog

    Filter = 'Text|*.txt|Any file|*.*'

    FilterIndex = 2

    Left = 240

    Top = 32

    end

    object SaveDialog1: TSaveDialog

    Filter = 'FB2 |*.fb2'

    Left = 272

    Top = 32

    end

    end

    // конец кода

    Код файла Unit1.pas соответствующего Form1

    // начало кода

    unit Unit1;


    interface


    uses

    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

    Dialogs, StdCtrls, ExtCtrls, Menus, CheckLst, ComCtrls,

    genres, UmFB2, dm, authors;


    type

    TForm1 = class(TForm)

    MainMenu1: TMainMenu;

    File1: TMenuItem;

    Open1: TMenuItem;

    SaveasFB21: TMenuItem;

    PageControl1: TPageControl;

    TabSheet1: TTabSheet;

    Annotation: TMemo;

    TabSheet3: TTabSheet;

    Lurl: TLabel;

    LID: TLabel;

    Lversion: TLabel;

    url: TEdit;

    id: TEdit;

    version: TEdit;

    TabSheet6: TTabSheet;

    LISBN: TLabel;

    LBook_name: TLabel;

    Lpublisher: TLabel;

    Lcity: TLabel;

    Lyear: TLabel;

    isbn: TEdit;

    Book_name: TEdit;

    publisher: TEdit;

    year: TEdit;

    city: TEdit;

    TabSheet2: TTabSheet;

    Panel1: TPanel;

    Panel2: TPanel;

    Button12: TButton;

    OpenDialog1: TOpenDialog;

    SaveDialog1: TSaveDialog;

    ListBox1: TListBox;

    TabSheet4: TTabSheet;

    Panel4: TPanel;

    Button3: TButton;

    EndNotesList: TListBox;

    RG: TRadioGroup;

    Panel3: TPanel;

    Lbook_title: TLabel;

    LProject: TLabel;

    LAnnotation: TLabel;

    Lsequence: TLabel;

    LLang: TLabel;

    Lsrc_lang: TLabel;

    LTome: TLabel;

    book_title: TEdit;

    FB2_file: TEdit;

    Au: TGroupBox;

    ListBox3: TListBox;

    Button10: TButton;

    GroupBox1: TGroupBox;

    GenresBox: TListBox;

    Button4: TButton;

    GroupBox3: TGroupBox;

    ListBox2: TListBox;

    Button7: TButton;

    sequence: TEdit;

    tome: TEdit;

    Lang: TComboBox;

    SLang: TComboBox;

    Button9: TButton;

    GroupBox2: TGroupBox;

    Button1: TButton;

    Button2: TButton;

    Button5: TButton;

    procedure Open1Click(Sender: TObject);

    procedure SaveasFB21Click(Sender: TObject);

    procedure Button12Click(Sender: TObject);

    procedure Button4Click(Sender: TObject);

    procedure Button10Click(Sender: TObject);

    procedure Button7Click(Sender: TObject);

    procedure FormCreate(Sender: TObject);

    procedure Button3Click(Sender: TObject);

    procedure Button9Click(Sender: TObject);

    procedure ListBox1DblClick(Sender: TObject);

    procedure ListBox1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

    procedure Button5Click(Sender: TObject);

    procedure Button1Click(Sender: TObject);

    private

    { Private declarations }

    public

    { Public declarations }

    end;


    var

    Form1: TForm1;

    Path: ANSIstring;

    implementation


    uses EditStr;


    {$R *.dfm}


    procedure LoadTXT(FName: string);

    var

    L: TStringList;

    i, j: integer;

    s, ss: string;

    begin


    L:= TStringList.Create;

    L.LoadFromFile(fname);

    for i:= 0 to L.Count - 1 do

    begin

    s:= ''; ss:= L[i];

    for j:= 1 to length(Ss) do

    begin // просматриваем строку

    case ss[j] of

    '<': S:= S + '&#60;'; // знак < вызывает сбой в читалке

    '>': S:= S + '&#62;'; // заменяем, на всякий случай

    '^': S:= S + '&#94;'; //

    '~': S:= S + '&#126;';

    '&': S:= S + '&#38;';

    else S:= S + ss[j];

    end; // case

    end;

    L[i]:= ' N| ' + S;

    end;

    Form1.ListBox1.Items.Assign(L);

    L.Free;

    end;


    procedure NameFB2_File(S: string);

    begin //

    S:= ExtractFileName(S);

    Form1.Caption:= S;

    Form1.FB2_file.Text:= ChangeFileExt(S,'.fb2');

    end;


    procedure TForm1.Open1Click(Sender: TObject);

    begin

    with OpenDialog1 do

    if Execute then

    begin

    NameFB2_File(FileName);

    ListBox1.Clear;

    LoadTXT(FileName); // txt

    end;

    end;


    function GetGaner(S: string):string;

    var

    i: integer;

    begin

    for i:= 0 to maxg do

    if gg[i][2] = S then

    begin

    result:= gg[i][1];

    exit;

    end;

    result:= s;

    end;


    procedure SaveAnnotation;

    var

    i: integer;

    begin

    OutList.Add('<annotation>');

    with form1.Annotation do

    for i:= 0 to Lines.Count - 1 do

    OutList.Add('<p>'+Lines[i]+'</p>');

    OutList.Add('</annotation>');

    end;


    procedure SavePersons(title: string; LB: TListBox);

    var

    i: integer;

    Person: TPerson;

    begin

    with LB do

    if Count > 0 then

    for i:= 0 to Count - 1 do

    begin

    Person:= TPerson(Items.Objects[i]);

    OutList.Add(' <'+title+'>');

    with Person do

    begin

    PrintString('first-name',fname);

    PrintString('last-name',lname);

    PrintString('middle-name',mname);

    PrintString('nick',nick);

    PrintString('email',email);

    end;

    OutList.Add(' </'+title+'>');

    end;

    end;


    procedure SaveSequence;

    var

    s: string;

    begin

    with Form1 do

    begin

    if sequence.Text = '' then exit;

    S:= '<sequence name="' +sequence.Text+'"';

    if tome.Text = ''

    then S:= S + '/>'

    else S:= S + ' number="'+tome.Text+'"/>';

    end;

    OutList.Add(S);


    end;


    procedure SaveDescription;

    const

    max = 5;

    mas: array[1..max] of string =

    (

    '<?xml version="1.0" encoding="windows-1251"?>',

    '<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0"',

    ' xmlns: l="http://www.w3.org/1999/xlink">',

    ' <description>',

    ' <title-info>'

    );

    var

    i: byte;

    S: string;

    begin

    // head

    for i:= 1 to max do

    OutList.Add(Mas[i]);


    with form1.GenresBox do

    if Items.Count > 0 then

    for i:= 0 to Items.Count - 1 do

    OutList.Add('<genre>'+GetGaner(Items[i])+'</genre>');


    SavePersons('author',Form1.ListBox3);

    SavePersons('translator',Form1.ListBox2);


    with Form1 do

    begin

    PrintString('book-title',book_title.text);

    if Annotation.Lines.Count > 0

    then SaveAnnotation;

    //if _date.text <> '' then

    //OutList.Add('<date value="'+_date.text+'-01-01">'+_date.text+'</date>');


    SaveSequence;

    OutList.Add(' <lang>'+Lang.Text+'</lang>');


    if SLang.ItemIndex > -1 then

    begin

    S:= Lg[SLang.ItemIndex][1];

    if S <> '' then

    OutList.Add(' <src-lang>'+S+'</src-lang>');

    end;


    OutList.Add(' </title-info>');


    // **** document-info ****


    OutList.Add(' <document-info>');

    OutList.Add(' <program-used>my_Make_FB2</program-used>');


    PrintString('src-url', url.Text); //??

    OutList.Add(' <date value="'+FormatDateTime('yyyy-mm-dd', Now)+'">'+ DateToStr(now) +'</date>');


    PrintString('id', id.Text); //??

    OutList.Add(' <version>1.0</version>');

    OutList.Add(' </document-info>');


    // **** publish-info ****


    OutList.Add(' <publish-info>');


    if Book_name.Text = ''

    then PrintString('book-name', book_title.Text)

    else PrintString('book-name', Book_name.Text);


    PrintString('publisher', publisher.Text); //

    PrintString('city', city.Text); //

    PrintString('year', year.Text); //

    PrintString('isbn', isbn.Text); //

    //OutList.Add(' <version>1.0</version>');

    OutList.Add(' </publish-info>');


    end;


    OutList.Add(' </description>');

    OutList.Add('<body>');

    end;


    function SubStyle(m,w: TmyStyle):integer;

    begin

    result:= integer(m) - integer(w);

    end;


    procedure SaveBodyFB2;

    var

    i, j: integer;

    S, ss: string;

    oldStyle,

    LastStyle, CurStyle: TmyStyle; // style


    procedure StyleStucture;

    begin

    if CurStyle <> oldStyle then

    begin

    if SytleStack.Count = 0 then

    begin

    SytleStack.Add(TObject(CurStyle))

    end

    else

    begin

    LastStyle:= TmyStyle(SytleStack.Last);

    case SubStyle(CurStyle,LastStyle) of

    0: OutList.Add('</section>');

    1: SytleStack.Add(TObject(CurStyle));

    else

    begin

    OutList.Add('</section>');

    while CurStyle <> LastStyle do

    begin

    SytleStack.Delete(SytleStack.Count-1);

    OutList.Add('</section>');

    LastStyle:= TmyStyle(SytleStack.Last);

    end;

    end;

    end;// case

    end;

    OutList.Add('<section>');

    OutList.Add('<title>');

    end;

    OutList.Add('<p>'+s+'</p>');

    end; // StyleStucture;


    begin

    oldStyle:= ZZ; EndNotes_count:= 1;

    // if

    OutList.Add('<section>');


    with Form1.ListBox1 do

    for i:= 0 to Count - 1 do // просматриваем текст

    begin

    S:= Items[i];

    Ss:= GetStyle(S, CurStyle); // получаем чистую строку и стиль

    s:= '';

    if ss <> '' then

    for j:= 1 to length(Ss) do

    begin // просматриваем строку

    case ss[j] of

    '~': begin // если это концевая сноска

    S:= S + '<a l: href="#n_'+IntToStr(EndNotes_count)+'" type="note">'

    +IntToStr(EndNotes_count)+'</a>';

    inc(EndNotes_count); // увеличиваем счетчик сносок

    end;

    '^': S:= S + '&#769;'; // ставим ударение

    else S:= S + ss[j];

    end; // case

    end;


    if (S = '') and (CurStyle <> Poem)

    then

    begin

    OutList.Add('<empty-line/>');

    continue;

    end;


    if (CurStyle <> oldStyle) and (CurStyle <> Auth) then

    begin

    case oldStyle of // завершение предыдущего блока

    Poem: OutList.Add('</stanza></poem>');

    Epig: OutList.Add('</epigraph>');

    Citat: OutList.Add('</cite>');


    H1..H5: OutList.Add('</title>');

    end; // case завершение предыдущего блока


    case CurStyle of // начало блока

    Poem: OutList.Add('<poem><stanza>');

    Epig: OutList.Add('<epigraph>');

    Citat: OutList.Add('<cite>');

    end; // case начало блока

    end;


    // анализ стилей

    case CurStyle of // в зависимости от стиля абзаца

    Norm,Epig,Citat: OutList.Add('<p>'+S+'</p>');

    H1..H5: StyleStucture; // Heading

    Sub: OutList.Add('<subtitle>'+s+'</subtitle>'); // Subtitle

    Poem: begin

    if S = ''

    then OutList.Add('</stanza><stanza>')

    else OutList.Add('<v>'+S+'</v>');

    end;

    Auth: begin

    OutList.Add('<text-author>'+S+'</text-author>');

    if oldStyle in [Poem, Epig, Citat]

    then CurStyle:= oldStyle;

    end;

    None: continue; //None


    end; // case


    oldStyle:= CurStyle;


    end; // for просмотр текста


    if SytleStack.Count > 0 then

    begin // закрываем все открытые секции

    while SytleStack.Count > 0 do

    begin

    SytleStack.Delete(SytleStack.Count-1);

    OutList.Add('</section>');

    end;

    end;

    OutList.Add('</section>');

    OutList.Add('</body>');

    end;


    procedure SaveEndnotes;

    var

    S: string;

    i: integer;

    begin

    if Form1.EndNotesList.Items.Count = 0 then exit; //<a type="note" l: href="#n_1">[1]</a>


    OutList.Add('<body name="notes"><title><p>Примечания</p></title>');


    for i:= 0 to Form1.EndNotesList.Items.Count - 1 do

    begin

    S:= Form1.EndNotesList.Items[i];

    OutList.Add('<section id="n_'+IntToStr(i+1)+'"><title><p>'+IntToStr(i+1)+'</p>');

    OutList.Add('</title><p>'+S+'</p>');

    OutList.Add('</section>');

    end;


    OutList.Add('</body>');

    end;


    Procedure Make_fb2(S: string);

    begin //

    if Form1.ListBox1.Items.Count = 0 then exit;

    SytleStack.Clear;


    OutList.Clear;

    SaveDescription;

    SaveBodyFB2;

    SaveEndnotes;

    OutList.Add('</FictionBook>');


    OutList.SaveToFile(S); //++ +


    showMessage('Done.');

    end;


    function BookHaveName: boolean;

    begin

    with Form1 do

    result:= (book_title.Text <> '') and

    (FB2_file.Text <> '') and

    (GenresBox.Count > 0);

    end;


    procedure TForm1.SaveasFB21Click(Sender: TObject);

    begin

    if not BookHaveName then

    begin

    PageControl1.ActivePageIndex:= 0;

    ShowMessage('Fill the form.');

    exit;

    end;

    SaveDialog1.FileName:= form1.FB2_file.Text;

    if SaveDialog1.Execute then

    Make_fb2(SaveDialog1.FileName);


    end;


    function SetStyle(n: TmyStyle):string;

    begin

    case n of

    Norm: result:= ' N';

    Epig: result:= ' E';

    Auth: result:= ' A';

    H1: result:= 'H1';

    H2: result:= 'H2';

    H3: result:= 'H3';

    H4: result:= 'H4';

    H5: result:= 'H5';

    Sub: result:= ' S';

    Poem: result:= ' P';

    Citat: result:= ' C';

    None: result:= '-';

    end; // case

    end;


    function SetStyle1(n: TmyStyle):string;

    begin

    result:= ' '+ SetStyle(n)+'| ';

    end;


    procedure ChangeStyle(LStyle: TmyStyle);

    var

    n, curIndex: integer;

    S: string;

    begin

    with Form1.ListBox1 do

    begin

    curIndex:= ItemIndex;

    if curIndex = -1 then exit;


    S:= Items[curIndex];

    n:= pos('|', s);

    delete(S, 1, n+1);

    Items[curIndex]:= SetStyle1(LStyle)+ S;

    if ItemIndex < Items.Count - 1

    then ItemIndex:= ItemIndex+1;

    SetFocus;

    end;

    end;


    procedure TForm1.Button12Click(Sender: TObject);

    begin

    ChangeStyle(TmyStyle(RG.itemindex));

    end;


    procedure TForm1.Button4Click(Sender: TObject);

    begin

    Form3.ListBox1.Items.Assign(GenresBox.Items);

    Form3.ShowModal;

    if Form3.ModalResult = mrOK then

    begin

    GenresBox.Items.Assign(Form3.ListBox1.Items);

    end;

    end;


    procedure TForm1.Button10Click(Sender: TObject);

    begin

    Form2.ListBox1.Items.Assign(ListBox3.Items);

    Form2.Button1Click(nil);

    Form2.ShowModal;

    if Form2.ModalResult = mrOK then

    begin

    ListBox3.Items.Assign(Form2.ListBox1.Items);

    end;

    end;


    procedure TForm1.Button7Click(Sender: TObject);

    begin

    Form2.ListBox1.Items.Assign(ListBox2.Items);

    Form2.Button1Click(nil);

    Form2.ShowModal;

    if Form2.ModalResult = mrOK then

    begin

    ListBox2.Items.Assign(Form2.ListBox1.Items);

    end;

    end;


    procedure TForm1.FormCreate(Sender: TObject);

    var

    i: integer;

    begin

    Path:= ExtractFileDir(ParamStr(0)) + '\';

    OpenDialog1.InitialDir:= Path;

    for i:= 0 to maxL do

    SLang.Items.Add(Lg[i][2]);

    SLang.ItemIndex:= 0;

    end;


    procedure TForm1.Button3Click(Sender: TObject);

    begin

    if FileExists(Path + 'EndNotes.txt')

    then EndNotesList.Items.LoadFromFile(Path + 'EndNotes.txt');

    end;


    procedure TForm1.Button9Click(Sender: TObject);

    begin

    if FileExists(Path + 'Annotation.txt') then

    Annotation.Lines.LoadFromFile(Path + 'Annotation.txt');

    end;


    function ScanUpStyle(n: integer):TmyStyle;

    var

    i: integer;

    LStyle: TmyStyle;

    begin

    with Form1.ListBox1 do

    for i:= n downto 0 do

    begin

    GetStyle(Items[i], LStyle);

    if LStyle in [H1..H5] then

    begin

    result:= LStyle;

    exit;

    end;

    end;

    result:= H1;

    end;


    procedure ShowHeadStyle(n: integer);

    var

    LStyle: TmyStyle;

    begin

    LStyle:= ScanUpStyle(n);

    Form1.Button2.Caption:= SetStyle(LStyle);

    Form1.Button2.Tag:= integer(LStyle);

    end;


    procedure TForm1.ListBox1DblClick(Sender: TObject);

    var

    S: string;

    CurStyle: TmyStyle;

    i, st: integer;

    begin


    st:= ListBox1.itemIndex;

    S:= GetStyle(ListBox1.Items[st], CurStyle);

    with EditSt do

    begin

    Memo1.WordWrap:= true;

    Memo1.Clear;

    Memo1.Lines.Add(S);

    ShowModal;


    if ModalResult = mrOK then

    begin

    ListBox1.Items.Delete(st);

    Memo1.WordWrap:= false;

    for i:= Memo1.Lines.Count - 1 downto 0 do

    ListBox1.Items.Insert(st, SetStyle1(CurStyle)+Memo1.Lines[i]);

    end;


    end;

    end;


    procedure TForm1.ListBox1Click(Sender: TObject);

    begin

    ShowHeadStyle(ListBox1.itemIndex);

    end;


    procedure TForm1.Button2Click(Sender: TObject);

    begin

    ChangeStyle(TmyStyle(Button2.Tag));

    end;


    procedure TForm1.Button5Click(Sender: TObject);

    var

    LStyle: TmyStyle;

    begin

    LStyle:= TmyStyle(Button2.Tag);

    if LStyle < H5 then ChangeStyle(Succ(LStyle));

    end;


    procedure TForm1.Button1Click(Sender: TObject);

    var

    LStyle: TmyStyle;

    begin

    LStyle:= TmyStyle(Button2.Tag);

    if LStyle > H1 then ChangeStyle(Pred(LStyle));

    end;


    end.

    // конец кода

    * * *

    genres.dfm

    // начало кода

    object Form3: TForm3

    Left = 214

    Top = 121

    BorderIcons = [biSystemMenu, biMinimize]

    BorderStyle = bsSingle

    Caption = 'Genre'

    ClientHeight = 294

    ClientWidth = 603

    Color = clBtnFace

    Font.Charset = DEFAULT_CHARSET

    Font.Color = clWindowText

    Font.Height = -11

    Font.Name = 'MS Sans Serif'

    Font.Style = []

    OldCreateOrder = False

    OnCreate = FormCreate

    PixelsPerInch = 96

    TextHeight = 13

    object ListBox1: TListBox

    Left = 8

    Top = 8

    Width = 241

    Height = 209

    ItemHeight = 13

    TabOrder = 0

    end

    object Button1: TButton

    Left = 272

    Top = 32

    Width = 75

    Height = 25

    Caption = 'Add'

    TabOrder = 1

    OnClick = Button1Click

    end

    object Button2: TButton

    Left = 272

    Top = 64

    Width = 75

    Height = 25

    Caption = 'Delete'

    TabOrder = 2

    OnClick = Button2Click

    end

    object BitBtn1: TBitBtn

    Left = 80

    Top = 248

    Width = 75

    Height = 25

    TabOrder = 3

    Kind = bkOK

    end

    object BitBtn2: TBitBtn

    Left = 448

    Top = 240

    Width = 75

    Height = 25

    TabOrder = 4

    Kind = bkCancel

    end

    object Button3: TButton

    Left = 272

    Top = 112

    Width = 75

    Height = 25

    Caption = 'Up'

    TabOrder = 5

    OnClick = Button3Click

    end

    object Button4: TButton

    Left = 272

    Top = 152

    Width = 75

    Height = 25

    Caption = 'Down'

    TabOrder = 6

    OnClick = Button4Click

    end

    object ListBox2: TListBox

    Left = 368

    Top = 32

    Width = 225

    Height = 185

    ItemHeight = 13

    TabOrder = 7

    OnDblClick = ListBox2DblClick

    end

    object ComboBox1: TComboBox

    Left = 368

    Top = 8

    Width = 225

    Height = 21

    ItemHeight = 13

    ItemIndex = 0

    TabOrder = 8

    Text = #1044#1077#1083#1086#1074#1072#1103' '#1083#1080#1090#1077#1088#1072#1090#1091#1088#1072

    OnChange = ComboBox1Change

    Items.Strings = (

    #1044#1077#1083#1086#1074#1072#1103' '#1083#1080#1090#1077#1088#1072#1090#1091#1088#1072

    #1044#1077#1090#1077#1082#1090#1080#1074#1099' '#1080' '#1058#1088#1080#1083#1083#1077#1088#1099

    #1044#1077#1090#1089#1082#1086#1077

    #1044#1086#1082#1091#1084#1077#1085#1090#1072#1083#1100#1085#1072#1103' '#1083#1080#1090#1077#1088#1072#1090#1091#1088#1072

    #1044#1086#1084#1086#1074#1086#1076#1089#1090#1074#1086

    #1050#1086#1084#1087#1100#1102#1090#1077#1088#1099' '#1080' '#1048#1085#1090#1077#1088#1085#1077#1090

    #1051#1102#1073#1086#1074#1085#1099#1077' '#1088#1086#1084#1072#1085#1099

    #1053#1072#1091#1082#1072', '#1054#1073#1088#1072#1079#1086#1074#1072#1085#1080#1077

    #1055#1077#1088#1080#1086#1076#1080#1082#1072

    #1055#1086#1101#1079#1080#1103', '#1044#1088#1072#1084#1072#1090#1091#1088#1075#1080#1103

    #1055#1088#1080#1082#1083#1102#1095#1077#1085#1080#1103

    #1055#1088#1086#1079#1072

    #1055#1088#1086#1095#1077#1077

    #1056#1077#1083#1080#1075#1080#1103' '#1080' '#1076#1091#1093#1086#1074#1085#1086#1089#1090#1100

    #1057#1087#1088#1072#1074#1086#1095#1085#1072#1103' '#1083#1080#1090#1077#1088#1072#1090#1091#1088#1072

    #1057#1090#1072#1088#1080#1085#1085#1086#1077

    #1058#1077#1093#1085#1080#1082#1072

    #1060#1072#1085#1090#1072#1089#1090#1080#1082#1072

    #1070#1084#1086#1088)

    end

    end

    // конец кода

    genres.pas

    // начало кода

    unit genres;


    interface


    uses

    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

    Dialogs, Buttons, StdCtrls, dm;


    type

    TForm3 = class(TForm)

    ListBox1: TListBox;

    Button1: TButton;

    Button2: TButton;

    BitBtn1: TBitBtn;

    BitBtn2: TBitBtn;

    Button3: TButton;

    Button4: TButton;

    ListBox2: TListBox;

    ComboBox1: TComboBox;

    procedure FormCreate(Sender: TObject);

    procedure Button1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

    procedure ComboBox1Change(Sender: TObject);

    procedure Button3Click(Sender: TObject);

    procedure Button4Click(Sender: TObject);

    procedure ListBox2DblClick(Sender: TObject);

    private

    { Private declarations }

    public

    { Public declarations }

    end;


    var

    Form3: TForm3;


    implementation


    {$R *.dfm}


    procedure TForm3.FormCreate(Sender: TObject);

    var

    i: integer;

    begin

    for i:= 0 to maxg do

    ListBox2.Items.Add(gg[i][2]);

    ListBox2.ItemIndex:= 0;

    end;


    procedure TForm3.Button1Click(Sender: TObject);

    var

    i: integer;

    begin

    for i:= 0 to ListBox1.Items.Count - 1 do

    if ListBox2.Items[ListBox2.ItemIndex] = ListBox1.Items[i]

    then exit;

    ListBox1.Items.Add(ListBox2.Items[ListBox2.ItemIndex]);

    end;


    procedure TForm3.Button2Click(Sender: TObject);

    begin

    if ListBox1.ItemIndex = -1 then exit;

    ListBox1.Items.Delete(ListBox1.ItemIndex);

    end;


    procedure TForm3.ComboBox1Change(Sender: TObject);

    begin

    ListBox2.ItemIndex:= LI[ComboBox1.ItemIndex];

    ListBox2.TopIndex:= ListBox2.ItemIndex;

    end;


    procedure TForm3.Button3Click(Sender: TObject);

    var

    k: integer;

    begin

    k:= ListBox1.ItemIndex;

    if k > 0 then

    begin

    ListBox1.Items.Move(k,k-1);

    ListBox1.ItemIndex:= k -1;

    end;

    end;


    procedure TForm3.Button4Click(Sender: TObject);

    var

    k: integer;

    begin

    k:= ListBox1.ItemIndex;

    if k < ListBox1.Items.Count - 1 then

    begin

    ListBox1.Items.Move(k,k+1);

    ListBox1.ItemIndex:= k+1;

    end;

    end;


    procedure TForm3.ListBox2DblClick(Sender: TObject);

    begin

    Button1Click(nil);

    end;


    end.

    // конец кода

    * * *

    EditStr.dfm

    // начало кода

    object EditSt: TEditSt

    Left = 175

    Top = 164

    Width = 692

    Height = 303

    Caption = 'Edit'

    Color = clBtnFace

    Font.Charset = DEFAULT_CHARSET

    Font.Color = clWindowText

    Font.Height = -11

    Font.Name = 'MS Sans Serif'

    Font.Style = []

    OldCreateOrder = False

    PixelsPerInch = 96

    TextHeight = 13

    object Panel1: TPanel

    Left = 0

    Top = 240

    Width = 684

    Height = 36

    Align = alBottom

    BevelOuter = bvNone

    TabOrder = 0

    object BitBtn1: TBitBtn

    Left = 16

    Top = 8

    Width = 75

    Height = 25

    TabOrder = 0

    Kind = bkOK

    end

    object BitBtn2: TBitBtn

    Left = 592

    Top = 8

    Width = 75

    Height = 25

    TabOrder = 1

    Kind = bkCancel

    end

    object BitBtn3: TBitBtn

    Left = 592

    Top = 8

    Width = 75

    Height = 25

    TabOrder = 2

    Kind = bkAbort

    end

    object Button1: TButton

    Left = 112

    Top = 8

    Width = 75

    Height = 25

    Caption = 'Bold'

    Font.Charset = DEFAULT_CHARSET

    Font.Color = clWindowText

    Font.Height = -11

    Font.Name = 'MS Sans Serif'

    Font.Style = [fsBold]

    ParentFont = False

    TabOrder = 3

    OnClick = Button1Click

    end

    object Button2: TButton

    Left = 200

    Top = 8

    Width = 75

    Height = 25

    Caption = 'Italic'

    Font.Charset = DEFAULT_CHARSET

    Font.Color = clWindowText

    Font.Height = -11

    Font.Name = 'MS Sans Serif'

    Font.Style = [fsItalic]

    ParentFont = False

    TabOrder = 4

    OnClick = Button2Click

    end

    end

    object Memo1: TMemo

    Left = 0

    Top = 0

    Width = 684

    Height = 240

    Align = alClient

    ScrollBars = ssVertical

    TabOrder = 1

    end

    end

    // конец кода

    EditStr.pas

    // начало кода

    unit EditStr;


    interface


    uses

    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

    Dialogs, StdCtrls, ExtCtrls, Buttons, ComCtrls;


    type

    TEditSt = class(TForm)

    Panel1: TPanel;

    Memo1: TMemo;

    BitBtn1: TBitBtn;

    BitBtn2: TBitBtn;

    BitBtn3: TBitBtn;

    Button1: TButton;

    Button2: TButton;

    procedure Button1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

    private

    { Private declarations }

    public

    { Public declarations }

    end;


    var

    EditSt: TEditSt;

    implementation


    {$R *.dfm}


    procedure TEditSt.Button1Click(Sender: TObject);

    begin

    with Memo1 do

    if SelLength > 0 then

    Memo1.SelText:= '<strong>'+ SelText + '</strong>'

    end;


    procedure TEditSt.Button2Click(Sender: TObject);

    begin

    with Memo1 do

    if SelLength > 0 then

    Memo1.SelText:= '<emphasis>'+ SelText + '</emphasis>'

    end;


    end.

    // конец кода

    * * *

    authors.dfm

    // начало кода

    object Form2: TForm2

    Left = 359

    Top = 204

    Width = 502

    Height = 285

    Caption = 'Person'

    Color = clBtnFace

    Font.Charset = DEFAULT_CHARSET

    Font.Color = clWindowText

    Font.Height = -11

    Font.Name = 'MS Sans Serif'

    Font.Style = []

    OldCreateOrder = False

    PixelsPerInch = 96

    TextHeight = 13

    object GroupBox1: TGroupBox

    Left = 296

    Top = 8

    Width = 185

    Height = 193

    Caption = 'Author'

    TabOrder = 0

    object Label2: TLabel

    Left = 8

    Top = 24

    Width = 45

    Height = 13

    Caption = 'first-name'

    end

    object Label3: TLabel

    Left = 8

    Top = 88

    Width = 45

    Height = 13

    Caption = 'last-name'

    end

    object Label4: TLabel

    Left = 8

    Top = 120

    Width = 46

    Height = 13

    Caption = 'nickname'

    end

    object Label5: TLabel

    Left = 8

    Top = 152

    Width = 24

    Height = 13

    Caption = 'email'

    end

    object Label8: TLabel

    Left = 8

    Top = 56

    Width = 47

    Height = 13

    Caption = 'midl-name'

    end

    object first_name: TEdit

    Left = 64

    Top = 16

    Width = 113

    Height = 21

    TabOrder = 0

    end

    object last_name: TEdit

    Left = 64

    Top = 80

    Width = 113

    Height = 21

    TabOrder = 1

    end

    object nickname: TEdit

    Left = 64

    Top = 112

    Width = 113

    Height = 21

    TabOrder = 2

    end

    object mail: TEdit

    Left = 64

    Top = 144

    Width = 113

    Height = 21

    TabOrder = 3

    end

    object mid_name: TEdit

    Left = 64

    Top = 48

    Width = 113

    Height = 21

    TabOrder = 4

    end

    end

    object Au: TGroupBox

    Left = 8

    Top = 8

    Width = 185

    Height = 193

    Caption = 'Authors'

    TabOrder = 1

    object ListBox1: TListBox

    Left = 8

    Top = 15

    Width = 169

    Height = 170

    ItemHeight = 13

    TabOrder = 0

    OnClick = ListBox1Click

    end

    end

    object Button1: TButton

    Left = 208

    Top = 16

    Width = 75

    Height = 25

    Caption = 'new'

    TabOrder = 2

    OnClick = Button1Click

    end

    object Button2: TButton

    Left = 208

    Top = 56

    Width = 75

    Height = 25

    Caption = 'Add'

    TabOrder = 3

    OnClick = Button2Click

    end

    object Button3: TButton

    Left = 208

    Top = 96

    Width = 75

    Height = 25

    Caption = 'Edit'

    TabOrder = 4

    OnClick = Button3Click

    end

    object Button4: TButton

    Left = 208

    Top = 136

    Width = 75

    Height = 25

    Caption = 'Delete'

    TabOrder = 5

    OnClick = Button4Click

    end

    object BitBtn1: TBitBtn

    Left = 96

    Top = 224

    Width = 75

    Height = 25

    TabOrder = 6

    Kind = bkOK

    end

    object BitBtn2: TBitBtn

    Left = 328

    Top = 224

    Width = 75

    Height = 25

    TabOrder = 7

    Kind = bkCancel

    end

    end

    // конец кода

    authors.pas

    // начало кода

    unit authors;


    interface


    uses

    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

    Dialogs, StdCtrls, Buttons;


    type

    TPerson = class

    fName: string;

    mName: string;

    lName: string;

    nick: string;

    email: string;

    constructor Create;

    end;


    TForm2 = class(TForm)

    GroupBox1: TGroupBox;

    Label2: TLabel;

    Label3: TLabel;

    Label4: TLabel;

    Label5: TLabel;

    Label8: TLabel;

    first_name: TEdit;

    last_name: TEdit;

    nickname: TEdit;

    mail: TEdit;

    mid_name: TEdit;

    Au: TGroupBox;

    ListBox1: TListBox;

    Button1: TButton;

    Button2: TButton;

    Button3: TButton;

    Button4: TButton;

    BitBtn1: TBitBtn;

    BitBtn2: TBitBtn;

    procedure Button1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

    procedure ListBox1Click(Sender: TObject);

    procedure Button3Click(Sender: TObject);

    procedure Button4Click(Sender: TObject);

    private

    { Private declarations }

    public

    { Public declarations }

    end;


    var

    Form2: TForm2;

    implementation


    {$R *.dfm}


    constructor TPerson.Create;

    begin

    fName:= '';

    mName:= '';

    lName:= '';

    nick:= '';

    email:= '';

    end;


    procedure TForm2.Button1Click(Sender: TObject);

    begin // New

    first_name.Text:= '';

    mid_name.Text:= '';

    last_name.Text:= '';

    nickname.Text:= '';

    mail.Text:= '';

    end;


    procedure TForm2.Button2Click(Sender: TObject);

    var

    Person: TPerson;

    begin // Add

    Person:= TPerson.Create;

    with Person do

    begin

    fName:= first_name.Text;

    mName:= mid_name.Text;

    lName:= last_name.Text;

    nick:= nickname.Text;

    email:= mail.Text;

    ListBox1.Items.AddObject(lName+' '+fName,Person);

    end;

    end;


    procedure TForm2.ListBox1Click(Sender: TObject);

    var

    Person: TPerson;

    begin

    with ListBox1 do

    Person:= TPerson(Items.Objects[ItemIndex]);

    with Person do

    begin

    first_name.Text:= fName;

    mid_name.Text:= mName;

    last_name.Text:= lName;

    nickname.Text:= nick;

    mail.Text:= email;

    end;

    end;


    procedure TForm2.Button3Click(Sender: TObject);

    var

    Person: TPerson;

    begin // Edit

    with ListBox1 do

    begin

    if ItemIndex = - 1 then exit;

    Person:= TPerson(Items.Objects[ItemIndex]);

    end;


    with Person do

    begin

    fName:= first_name.Text;

    mName:= mid_name.Text;

    lName:= last_name.Text;

    nick:= nickname.Text;

    email:= mail.Text;

    with ListBox1 do

    Items[ItemIndex]:=lName+' '+fName;

    end;

    end;


    procedure TForm2.Button4Click(Sender: TObject);

    var

    Person: TPerson;

    begin // Delete

    with ListBox1 do

    begin

    if ItemIndex = - 1 then exit;

    Person:= TPerson(Items.Objects[ItemIndex]);

    Person.Free;

    Items.Delete(ItemIndex);

    end;

    end;


    end.

    // конец кода

    dm.pas

    Это просто текстовый файл, без формы.


    // начало кода

    unit dm;


    interface

    type

    gr = array[1..2] of string;

    const

    maxg = 151;

    gg: array[0..maxg] of gr = (// Список жанров

    // Деловая литература

    ('banking', 'Банковское дело'),

    ('accounting', 'Бухучет, налогообложение, аудит'),

    ('global_economy', 'Внешнеэкономическая деятельность'),

    ('paper_work', 'Делопроизводство'),

    ('org_behavior', 'Корпоративная культура'),

    ('personal_finance', 'Личные финансы'),

    ('small_business', 'Малый бизнес'),

    ('marketing', 'Маркетинг, PR, реклама'),

    ('real_estate', 'Недвижимость'),

    ('popular_business', 'О бизнесе популярно'),

    ('industries', 'Отраслевые издания'),

    ('job_hunting', 'Поиск работы, карьера'),

    ('economics_ref', 'Справочники'),

    ('management', 'Управление, подбор персонала'),

    ('stock', 'Ценные бумаги, инвестиции'),

    ('economics', 'Экономика'),

    // Детективы и Триллеры

    ('det_action', 'Боевик'),

    ('detective', 'Детектив'),

    ('det_irony', 'Иронический детектив'),

    ('det_history', 'Исторический детектив'),

    ('det_classic', 'Классический детектив'),

    ('det_crime', 'Криминальный детектив'),

    ('det_hard', 'Крутой детектив'),

    ('det_maniac', 'Маньяки'),

    ('det_political', 'Политический детектив'),

    ('det_police', 'Полицейский детектив'),

    ('thriller', 'Триллер'),

    ('det_espionage', 'Шпионский детектив'),

    // Детское

    ('children', 'Детская литература'),

    ('child_education', 'Детская образовательная литература'),

    ('child_prose', 'Детская проза'),

    ('child_sf', 'Детская фантастика'),

    ('child_det', 'Детские остросюжетные'),

    ('child_adv', 'Детские приключения'),

    ('child_verse', 'Детские стихи'),

    ('child_tale', 'Сказка'),

    // Документальная литература

    ('nonf_biography', 'Биографии и Мемуары'),

    ('nonfiction', 'Документальная литература'),

    ('design', 'Искусство и Дизайн'),

    ('nonf_criticism', 'Критика'),

    ('music', 'Музыка'),

    ('nonf_publicism', 'Публицистика'),

    //Домоводство

    ('home_pets', 'Домашние животные'),

    ('home', 'Домоводство'),

    ('home_health', 'Здоровье'),

    ('home_cooking', 'Кулинария'),

    ('home_entertain', 'Развлечения'),

    ('home_garden', 'Сад и огород'),

    ('home_diy', 'Сделай сам'),

    ('home_sport', 'Спорт'),

    ('home_crafts', 'Хобби и ремесла'),

    ('home_sex', 'Эротика, Секс'),

    // Компьютеры и Интернет

    ('comp_db', 'Базы данных'),

    ('comp_www', 'Интернет'),

    ('comp_hard', 'Компьютерное "железо"'),

    ('computers', 'Околокомпьютерная литература'),

    ('comp_osnet', 'ОС и Сети'),

    ('comp_programming', 'Программирование'),

    ('comp_soft', 'Программы'),

    ('comp_dsp', 'Цифровая обработка сигналов'),

    // Любовные романы

    ('love_history', 'Исторические любовные романы'),

    ('love_short', 'Короткие любовные романы'),

    ('love_sf', 'Любовно-фантастические романы'),

    ('love', 'О любви'),

    ('love_detective', 'Остросюжетные любовные романы'),

    ('love_contemporary', 'Современные любовные романы'),

    ('love_erotica', 'Эротика'),

    // Наука, Образование

    ('sci_medicine_alternative', 'Альтернативная медицина'),

    ('sci_cosmos', 'Астрономия и Космос'),

    ('sci_biology', 'Биология'),

    ('sci_biophys', 'Биофизика'),

    ('sci_biochem', 'Биохимия'),

    ('sci_geo', 'Геология и география'),

    ('sci_state', 'Государство и право'),

    ('sci_business', 'Деловая литература'),

    ('sci_history', 'История'),

    ('sci_culture', 'Культурология'),

    ('sci_philology', 'Литературоведение'),

    ('sci_math', 'Математика'),

    ('sci_medicine', 'Медицина'),

    ('science', 'Научная литература'),

    ('sci_orgchem', 'Органическая химия'),

    ('sci_politics', 'Политика'),

    ('sci_psychology', 'Психология'),

    ('sci_religion', 'Религиоведение'),

    ('sci_tech', 'Технические науки'),

    ('sci_phys', 'Физика'),

    ('sci_physchem', 'Физическая химия'),

    ('sci_philosophy', 'Философия'),

    ('sci_chem', 'Химия'),

    ('sci_economy', 'Экономика'),

    ('sci_juris', 'Юриспруденция'),

    ('sci_linguistic', 'Языкознание'),

    // Периодика

    ('periodic', 'Журналы'),

    //Поэзия, Драматургия

    ('dramaturgy', 'Драматургия'),

    ('poetry', 'Поэзия'),

    // Приключения

    ('adv_western', 'Вестерн'),

    ('adv_history', 'Исторические приключения'),

    ('adv_maritime', 'Морские приключения'),

    ('adventure', 'Приключения'),

    ('adv_indian', 'Приключения про индейцев'),

    ('adv_animal', 'Природа и животные'),

    ('adv_geo', 'Путешествия и география'),

    // Проза

    ('prose_history', 'Историческая проза'),

    ('prose_classic', 'Классическая проза'),

    ('prose_counter', 'Контркультура'),

    ('prose_military', 'О войне'),

    ('prose', 'Проза'),

    ('prose_rus_classic', 'Русская классическая проза'),

    ('prose_su_classics', 'Советская классическая проза'),

    ('prose_contemporary', 'Современная проза'),

    // Прочее

    ('other', 'Неотсортированное'),

    ('notes', 'Партитуры'),

    //Религия и духовность

    ('religion_budda', 'Буддизм'),

    ('religion', 'Религиозная литература'),

    ('religion_rel', 'Религия'),

    ('religion_self', 'Самосовершенствование'),

    ('religion_esoterics', 'Эзотерика'),

    //Справочная литература

    ('geo_guides', 'Путеводители'),

    ('ref_guide', 'Руководства'),

    ('ref_dict', 'Словари'),

    ('reference', 'Справочная литература'),

    ('ref_ref', 'Справочники'),

    ('ref_encyc', 'Энциклопедии'),

    //Старинное

    ('antique_ant', 'Античная литература'),

    ('antique_east', 'Древневосточная литература'),

    ('antique_russian', 'Древнерусская литература'),

    ('antique_european', 'Европейская старинная литература'),

    ('antique_myths', 'Мифы. Легенды. Эпос'),

    ('antique', 'Старинная литература'),

    //Техника

    ('sci_metal', 'Металлургия'),

    ('sci_radio', 'Радиоэлектроника'),

    ('sci_build', 'Строительство и сопромат'),

    ('sci_transport', 'Транспорт и авиация'),

    //Фантастика

    ('sf_history', 'Альтернативная история'),

    ('sf_action', 'Боевая фантастика'),

    ('sf_heroic', 'Героическая фантастика'),

    ('sf_fantasy_city', 'Городское фэнтези'),

    ('sf_detective', 'Детективная фантастика'),

    ('sf_cyberpunk', 'Киберпанк'),

    ('sf_space', 'Космическая фантастика'),

    ('sf', 'Научная Фантастика'),

    ('sf_postapocalyptic', 'Постапокалипсис'),

    ('sf_social', 'Социально-психологическая фантастика'),

    ('sf_horror', 'Ужасы и Мистика'),

    ('sf_fantasy', 'Фэнтези'),

    ('sf_epic', 'Эпическая фантастика'),

    ('sf_humor', 'Юмористическая фантастика'),

    //Юмор

    ('humor_anecdote', 'Анекдоты'),

    ('humor', 'Юмор'),

    ('humor_prose', 'Юмористическая проза'),

    ('humor_verse', 'Юмористические стихи')

    );


    maxI = 18;

    LI: array[0..maxI] of integer = (


    0, // Деловая литература

    16, // Детективы и Триллеры

    28, // Детское

    36,// Документальная литература

    42, //Домоводство

    52, // Компьютеры и Интернет

    60, // Любовные романы

    67, // Наука, Образование

    93, // Периодика

    94, //Поэзия, Драматургия

    96, // Приключения

    106,// Проза

    111,// Прочее

    113, //Религия и духовность

    118, //Справочная литература

    124, //Старинное

    130,//Техника

    134, //Фантастика

    147 //Юмор


    );


    maxL = 23;

    Lg: array[0..maxL] of gr = (

    ('', ''),

    ('en', 'Английский'),

    ('be', 'Белорусский'),

    ('bg', 'Болгарский'),

    ('hu', 'Венгерский'),

    ('nl', 'Голландский'),

    ('el', 'Греческий современный (1453-)'),

    ('da', 'Данийский'),

    ('grc', 'Древнегреческий (до 1453)'),

    ('he', 'Иврит'),

    ('it', 'Итальянский'),

    ('de', 'Немецкий'),

    ('pl', 'Польский'),

    ('pt', 'Португальский'),

    ('ru', 'Русский'),

    ('sk', 'Словакский'),

    ('sl', 'Словенский'),

    ('tr', 'Турецкий'),

    ('uk', 'Украинский'),

    ('fi', 'Финский'),

    ('fr', 'Французский'),

    ('cs', 'Чешский'),

    ('et', 'Эстонский'),

    ('ja', 'Японский')

    );


    implementation


    end.

    // конец кода


    А это - файл проекта

    my_FB2.dpr

    // начало кода

    program my_FB2;


    uses

    Forms,

    Unit1 in 'Unit1.pas' {Form1},

    genres in 'genres.pas' {Form3},

    authors in 'authors.pas' {Form2},

    EditStr in 'EditStr.pas' {EditSt};


    {$R *.res}


    begin

    Application.Initialize;

    Application.CreateForm(TForm1, Form1);

    Application.CreateForm(TForm3, Form3);

    Application.CreateForm(TForm2, Form2);

    Application.CreateForm(TEditSt, EditSt);

    Application.Run;

    end.

    // конец кода

    Попробовал выполнить собственные инструкции, оказалось забыл еще один файл. А так ничего, "поругался" Дельфи на отсутствие ресурсного файла, да ничего он сам его сделает. А забытый, вот он:

    UmFB2.pas

    // начало кода

    unit UmFB2;


    interface

    uses

    Classes, SysUtils, Dialogs;


    Type

    TmyStyle = (

    Norm, Epig, Auth, Sub, Poem, Citat, None,

    ZZ, // пустой тип

    H1, H2, H3, H4, H5 );


    var

    SytleStack : TList;

    // StyleList : TList;

    OutList : TStringList;

    EndNotes_count: integer;

    // Path : string;


    function GetStyle(S:string; var m:TmyStyle):string;

    function GetStr(S:string):string;

    procedure PrintString(St, E : string);


    implementation


    procedure PrintString(St, E : string);

    begin

    if E <> '' then

    OutList.Add(' <'+St+'>'+E +'</'+St+'>');

    end;


    function GetStyle(S:string; var m:TmyStyle):string;

    var

    n : byte;

    ss : string;

    begin

    n := pos('|', S);

    ss := copy(s,1,n-1); // стиль

    case ss[length(ss)] of

    'N' : m := Norm;

    'E' : m := Epig;

    'A' : m := Auth;

    '1' : m := H1;

    '2' : m := H2;

    '3' : m := H3;

    '4' : m := H4;

    '5' : m := H5;

    'S' : m := Sub;

    'P' : m := Poem;

    'C' : m := Citat;

    '-' : m := None;

    end;// case

    delete(s,1,n+1); // текст

    result := S;

    end;


    function GetStr(S:string):string;

    var

    n : byte;

    begin

    n := pos('|', S);

    delete(s,1,n+1); // текст

    result := S;

    end;


    BEGIN

    SytleStack := TList.create;

    OutList := TStringList.Create;

    // StyleList := TList.Create;

    END.

    // конец кода


    Ну вот и весь исходник.


    Успехов.


    w_cat.


    Примечания:



    1

    Эти стихи, не имеют никакого отношения к теме. Ну просто, они мне нравятся.







     

    Главная | В избранное | Наш E-MAIL | Добавить материал | Нашёл ошибку | Наверх