Concatenating Files for a Book

During my documentation project, I encountered the need to concatenate multiple Markdown documents into a single comprehensive document. I initially used a FileMaker Script to achieve this and subsequently ran the Markdown conversion to generate a complete HTML file with all the pages combined.

However, I faced some formatting issues during this process. Notably, numerous extra blank lines were being inserted into the text. Upon investigation, I realized that this was due to formatting applied by FileMaker to files with alternate line breaks. FileMaker uses CR (Carriage Return), whereas most pure text editors on Mac use LF (Line Feed). The issue likely arose because LF was converted to CRLF, and when written back, the Markdown converter interpreted the extra CR as blank lines.

To address this, I decided to create an ACF function to handle the concatenation process. This approach provided me with full control over the text within the documents. Additionally, I started by creating a Table of Contents (TOC) section with all the document titles, making it easier to navigate through this lengthy document.

The implementation of this approach was an immediate success. You can view the resulting concatenated document for this manual by clicking the following link: ACF_book.html

Here's a snippet of the ACF function responsible for this operation:

function create_ebook_html ( string book, string html_path, string bookname )

    if ( bookname == "") then
        throw "Missing bookname"; 
    end if
    string s, d; 
    string sql = format ( "SELECT cat.Sorting, doc.Sorting, doc.DocumentRelPath, doc.Title, cat.Category, 
    doc.cCategoryText,doc.PrimaryKey FROM ACF_Documents as doc
LEFT OUTER JOIN ACF_Categories as cat ON cat.PrimaryKey = doc.Category_UUID
LEFT OUTER JOIN Books as bk ON bk.PrimaryKey = doc.BookUUID
WHERE bk.Title='%s'
ORDER BY cat.Sorting, doc.Sorting, doc.Title", book);

    string sf = ACF_Documents::DocumentRelPath; // Any document in the book. We only want the directory path. 
    string sourcePath = regex_replace("^(.+)/(.+\..+)$", sf, "\1")+"/";
    // print sourcePath; 
    // return "Debug";
    int rs = SQL_Query (sql);
    int rc = SQL_getRowCount ( rs ); 
    int md = open ( sourcePath+bookname+".md", "w"); 
    
    write (md, "# "+Books::HeadingTitle+"\n\n"); 
    
    int i,x; 
    array string row; 
    string curcat = "---", cont, anchor;

    // TOC ( Table of Content )
    write ( md, "## TABLE OF CONTENT\n\n");
    for ( i=1, rc )
        row = SQL_GetRow ( rs, i-1); 
        if ( row[6] != curcat ) then // Category headings in the toc. 
            write ( md, "\n###"+row[6]+"\n\n");
            curcat = row[6];
        end if
        write ( md, "- [" +row[4]+"](#"+row[7]+ ")\n");
    end for
    write ( md, "---\n");
    
    // The Main content - from all the MD files.
    curcat = "---";
    for ( i=1, rc )
        row = SQL_GetRow ( rs, i-1); 
        if ( row[6] != curcat ) then
            write ( md, "# "+ row[6]+"\n\n");
            curcat = row[6];
        end if
        x = open (row[3], "r" ); 
        cont = read ( x ); 
        anchor = '<a id="'+row[7]+'"></a>';
        write ( md, anchor+"\n"+cont+"\n\n");
        close ( x );  
        
        write ( md, "<br><hr>[Back to top](#toc_0)\n\n");
        
    end for
    close ( md ) ; 
    sql_close ( rs );
    
    res = EasyConvertMarkdown (sourcePath+bookname+".md", html_path+"/"+bookname+".html", html_path, 
        ACF_Documents::Style,ACF_Documents::Codestyle,  Preferences::ImageTagRemoveText);

        // Copy the neccessary files to a new folder. 
        // Copy file also copies directories. 
    destfolder = html_path + "/" + bookname + "/";
    if ( directory_exists (html_path + "/" + bookname)) then
        res = delete_directory ( html_path + "/" + bookname );
    end if
    res = create_directory (html_path + "/" + bookname ) ; 
    
    res = copy_file ( html_path+"/"+bookname+".html", destfolder+"index.html"); 
    res = copy_file ( html_path+"/images", destfolder+"images"); 
    res = copy_file ( html_path+"/css", destfolder+"css"); 
    res = copy_file ( html_path+"/include", destfolder+"include"); 
    res = create_directory ( html_path+ "/" +bookname + "/themes/markdown" ); 
    
    res = copy_file ( html_path+"/themes/markdown/" +  ACF_Documents::Style, destfolder+"themes/markdown/"+  ACF_Documents::Style); 
    s= html_path+"/themes/code/style/" +  ACF_Documents::Codestyle; 
    d= destfolder+"themes/code/style/"+  ACF_Documents::Codestyle;
    res = create_directory ( destfolder+"themes/code/style"); 
    res = copy_file ( s, d); 
    
    s= html_path+"/themes/code/style/" +  ACF_Documents::Style; 
    d= destfolder+"themes/code/style/"+  ACF_Documents::Style;
    res = copy_file ( s, d); 
    
    $$BookHTML = html_path+"/"+bookname+"/"+"index.html"; 


end 

FileMaker Script

References: