Some conveniences shared by our different forms of index.


§1. Top and tail.

    text_stream index_stream;

    text_stream *IndexUtilities::open_page(text_stream *title, text_stream *leafname) {
        filename *F = Filenames::in_folder(indoc_settings->destination, leafname);
        if (indoc_settings->wrapper == WRAPPER_epub)
            Epub::note_page(indoc_settings->ebook, F, title, I"index");

        text_stream *OUT = &index_stream;
        if (Streams::open_to_file(OUT, F, UTF8_ENC) == FALSE)
            Errors::fatal_with_file("can't write index page file", F);

        TEMPORARY_TEXT(head);
        HTMLUtilities::get_tt_matter(head, 1, 1);
        if (Str::len(head) > 0) {
            wchar_t replacement[1024];
            TEMPORARY_TEXT(rep);
            WRITE_TO(rep, "<title>Inform 7 - %S</title>", title);
            Str::copy_to_wide_string(replacement, rep, 1024);
            DISCARD_TEXT(rep);
            Regexp::replace(head, L"%[SUBHEADING%]", NULL, REP_REPEATING);
            Regexp::replace(head, L"<title>%c*</title>", replacement, REP_REPEATING);
            WRITE("%S", head);
        } else {
            HTMLUtilities::begin_file(OUT, volumes[0]);
            HTMLUtilities::write_title(OUT, title);
            HTML::end_head(OUT);
            HTML::begin_body(OUT, I"paper papertint");
        }
        DISCARD_TEXT(head);

        Nav::render_navigation_index_top(OUT, leafname, title);
        return OUT;
    }

The function IndexUtilities::open_page is used in 3/cai (§9), 3/ei (§3, §5, §6).

§2.

    void IndexUtilities::close_page(OUTPUT_STREAM) {
        TEMPORARY_TEXT(tail);
        HTMLUtilities::get_tt_matter(tail, 1, 0);
        if (Str::len(tail) > 0) WRITE("%S", tail);
        else HTML::end_body(OUT);
        Streams::close(OUT);
    }

The function IndexUtilities::close_page is used in 3/cai (§9), 3/ei (§3, §5, §6).

§3. Alphabetisation. We flatten the casing and remove the singular articles; we count small numbers as words, so that "3 Wise Monkeys" is filed as if it were "Three Wise Monkeys"; with parts of multipart examples, such as "Disappointment Bay 3", we insert a 0 before the 3 so that up to 99 parts can appear and alphabetical sorting will agree with numerical.

    dictionary *alphabetisation_exceptions = NULL;     hash of lemmas with unusual alphabetisations

    void IndexUtilities::alphabetisation_exception(text_stream *term, text_stream *alphabetise_as) {
        if (alphabetisation_exceptions == NULL)
            alphabetisation_exceptions = Dictionaries::new(100, TRUE);
        text_stream *val = Dictionaries::create_text(alphabetisation_exceptions, term);
        Str::copy(val, alphabetise_as);
    }

    void IndexUtilities::improve_alphabetisation(text_stream *sort_key) {
        text_stream *alph = Dictionaries::get_text(alphabetisation_exceptions, sort_key);
        if (Str::len(alph) > 0) {
            Str::copy(sort_key, alph);
            LOOP_THROUGH_TEXT(pos, sort_key)
                Str::put(pos, Characters::tolower(Str::get(pos)));
        } else {
            LOOP_THROUGH_TEXT(pos, sort_key)
                Str::put(pos, Characters::tolower(Str::get(pos)));
            Regexp::replace(sort_key, L"a ", NULL, REP_ATSTART);
            Regexp::replace(sort_key, L"an ", NULL, REP_ATSTART);
            Regexp::replace(sort_key, L"the ", NULL, REP_ATSTART);
            LOOP_THROUGH_TEXT(pos, sort_key)
                Str::put(pos, Characters::tolower(Characters::remove_accent(Str::get(pos))));
            Regexp::replace(sort_key, L"%[ *%]", L"____SQUARES____", REP_REPEATING);
            Regexp::replace(sort_key, L"%[", NULL, REP_REPEATING);
            Regexp::replace(sort_key, L"%]", NULL, REP_REPEATING);
            Regexp::replace(sort_key, L"____SQUARES____", L"[]", REP_REPEATING);
            Regexp::replace(sort_key, L"%(", NULL, REP_REPEATING);
            Regexp::replace(sort_key, L"%)", NULL, REP_REPEATING);
            Regexp::replace(sort_key, L"1 ", L"one ", REP_ATSTART);
            Regexp::replace(sort_key, L"2 ", L"two ", REP_ATSTART);
            Regexp::replace(sort_key, L"3 ", L"three ", REP_ATSTART);
            Regexp::replace(sort_key, L"4 ", L"four ", REP_ATSTART);
            Regexp::replace(sort_key, L"5 ", L"five ", REP_ATSTART);
            Regexp::replace(sort_key, L"6 ", L"six ", REP_ATSTART);
            Regexp::replace(sort_key, L"7 ", L"seven ", REP_ATSTART);
            Regexp::replace(sort_key, L"8 ", L"eight ", REP_ATSTART);
            Regexp::replace(sort_key, L"9 ", L"nine ", REP_ATSTART);
            Regexp::replace(sort_key, L"10 ", L"ten ", REP_ATSTART);
            Regexp::replace(sort_key, L"11 ", L"eleven ", REP_ATSTART);
            Regexp::replace(sort_key, L"12 ", L"twelve ", REP_ATSTART);
            TEMPORARY_TEXT(x);
            Str::copy(x, sort_key);
            Str::clear(sort_key);
            match_results mr = Regexp::create_mr();
            while (Regexp::match(&mr, x, L"(%c*?)(%d+)(%c*)")) {
                WRITE_TO(sort_key, "%S", mr.exp[0]);
                Str::copy(x, mr.exp[2]);
                WRITE_TO(sort_key, "%08d", Str::atoi(mr.exp[1], 0));
            }
            WRITE_TO(sort_key, "%S", x);
            DISCARD_TEXT(x);
        }
    }

The function IndexUtilities::alphabetisation_exception is used in 3/cai (§6, §8).

The function IndexUtilities::improve_alphabetisation is used in 3/cai (§9.1), 3/ei (§2.2).

§4.

    int letters_taken[26];
    void IndexUtilities::note_letter(int c) {
        int i = c - 'A';
        if ((i>=0) && (i<26)) letters_taken[i] = TRUE;
    }
    void IndexUtilities::alphabet_row(OUTPUT_STREAM, int sequence) {
        switch (sequence) {
            case 1:
                for (int i=0; i<26; i++)
                    letters_taken[i] = FALSE;
                break;
            case 2: {
                int faked = FALSE;
                for (int i=0; i<26; i++)
                    if (letters_taken[i] == FALSE) {
                        if (faked == FALSE) { faked = TRUE; HTML_OPEN("p"); }
                        TEMPORARY_TEXT(singleton);
                        PUT_TO(singleton, 'A'+i);
                        HTML::anchor(OUT, singleton);
                        DISCARD_TEXT(singleton);
                    }
                if (faked) { HTML_CLOSE("p"); }
                break;
            }
        }
        if (indoc_settings->navigation->simplified_letter_rows) {
            HTML_OPEN("p");
        } else {
            HTML_OPEN_WITH("table", "class=\"fullwidth\"");
            HTML_OPEN("tr");
            HTML_OPEN_WITH("td", "class=\"letterinrow\"");
        }
        HTMLUtilities::general_link(OUT, I"letterlink", I"#A", I"A"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#B", I"B"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#C", I"C"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#D", I"D"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#E", I"E"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#F", I"F"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#G", I"G"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#H", I"H"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#I", I"I"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#J", I"J"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#K", I"K"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#L", I"L"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#M", I"M"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#N", I"N"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#O", I"O"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#P", I"P"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#Q", I"Q"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#R", I"R"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#S", I"S"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#T", I"T"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#U", I"U"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#V", I"V"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#W", I"W"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#X", I"X"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#Y", I"Y"); <Between 4.1>;
        HTMLUtilities::general_link(OUT, I"letterlink", I"#Z", I"Z");
        if (indoc_settings->navigation->simplified_letter_rows) {
            HTML_CLOSE("p");
        } else {
            HTML_CLOSE("td");
            HTML_CLOSE("tr");
            HTML_CLOSE("table");
        }
    }

The function IndexUtilities::note_letter is used in 3/cai (§9.2), 3/ei (§3.3).

The function IndexUtilities::alphabet_row is used in 3/cai (§9.2), 3/ei (§3).

§4.1. <Between 4.1> =

        if (indoc_settings->navigation->simplified_letter_rows) WRITE(" / ");
        else {
            HTML_CLOSE("td");
            HTML_OPEN_WITH("td", "class=\"letterinrow\"");
        }

This code is used in §4 (25 times).

§5. This is mainly used for the typographically dramatic link letters A, B, C, ... but can also make fatter typographically dramatic headings, if it's stretched in width and a longer text is supplied.

    void IndexUtilities::majuscule_heading(OUTPUT_STREAM, text_stream *display_text, int single_letter) {
        if (indoc_settings->navigation->simplified_letter_rows) {
            if (single_letter == 1) { HTML::begin_div_with_class_S(OUT, I"majuscule"); }
            else { HTML::begin_div_with_class_S(OUT, I"stretchymajuscule"); }
            HTML_OPEN_WITH("span", "class=\"majusculelettering\"");
            WRITE("%S", display_text);
            HTML_CLOSE("span");
            HTML::end_div(OUT);
        } else {
            WRITE("<b>%S</b>", display_text);
        }
    }

The function IndexUtilities::majuscule_heading is used in 3/cai (§9.2.1), 3/ei (§3.3).