1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-05-17 00:18:39 +03:00
inform7/retrospective/6M62/cBlorb.c

4362 lines
142 KiB
C

/* Tangled output generated by inweb-C: do not edit */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#define OSX_PLATFORM 1
#define WINDOWS_PLATFORM 2
#define UNIX_PLATFORM 3
#define MAX_FILENAME_LENGTH 10240 /* total length of pathname including leaf and extension */
#define MAX_EXTENSION_LENGTH 32 /* extension part of filename, for auxiliary files */
#define MAX_VAR_NAME_LENGTH 32 /* length of name of placeholder variable like "[AUTHOR]" */
#define MAX_TEXT_FILE_LINE_LENGTH 51200 /* for any single line in the project's source text */
#define MAX_SOURCE_TEXT_LINES 2000000000; /* enough for 300 copies of the Linux kernel source -- plenty! */
#define VERSION "cBlorb 1.2"
#define TRUE 1
#define FALSE 0
#define MEMORY_MANAGEMENT \
int allocation_id; /* Numbered from 0 upwards in creation order */\
void *next_structure; /* Next object in double-linked list */\
void *prev_structure; /* Previous object in double-linked list */
#define auxiliary_file_MT 0
#define skein_node_MT 1
#define chunk_metadata_MT 2
#define placeholder_MT 3
#define heading_MT 4
#define table_MT 5
#define segment_MT 6
#define request_MT 7
#define template_MT 8
#define template_path_MT 9
#define rdes_record_MT 10
#define NO_MEMORY_TYPES 11 /* must be 1 more than the highest |_MT| constant above */
#define SAFETY_MARGIN 64
#define BLANK_END_SIZE 128
#define MAX_BLOCKS_ALLOWED 15000
#define MEMORY_GRANULARITY 100*1024*4 /* which must be divisible by 1024 */
#define INTEGRITY_NUMBER 0x12345678 /* a value unlikely to be in memory just by chance */
#define CREATE(type_name) (allocate_##type_name())
#define CREATE_BEFORE(existing, type_name) (allocate_##type_name##_before(existing))
#define DESTROY(this, type_name) (deallocate_##type_name(this))
#define FIRST_OBJECT(type_name) ((type_name *) alloc_status[type_name##_MT].first_in_memory)
#define LAST_OBJECT(type_name) ((type_name *) alloc_status[type_name##_MT].last_in_memory)
#define NEXT_OBJECT(this, type_name) ((type_name *) (this->next_structure))
#define PREV_OBJECT(this, type_name) ((type_name *) (this->prev_structure))
#define NUMBER_CREATED(type_name) (alloc_status[type_name##_MT].objects_count)
#define LOOP_OVER(var, type_name)\
for (var=FIRST_OBJECT(type_name); var != NULL; var = NEXT_OBJECT(var, type_name))
#define LOOP_BACKWARDS_OVER(var, type_name)\
for (var=LAST_OBJECT(type_name); var != NULL; var = PREV_OBJECT(var, type_name))
#define NEW_OBJECT(type_name) ((type_name *) allocate_mem(type_name##_MT, sizeof(type_name)))
#define ALLOCATE_INDIVIDUALLY(type_name) \
type_name *allocate_##type_name(void) {\
alloc_status[type_name##_MT].name_of_type = #type_name;\
type_name *prev_obj = LAST_OBJECT(type_name);\
type_name *new_obj = NEW_OBJECT(type_name);\
new_obj->allocation_id = alloc_status[type_name##_MT].objects_allocated-1;\
new_obj->next_structure = NULL;\
if (prev_obj != NULL)\
prev_obj->next_structure = (void *) new_obj;\
new_obj->prev_structure = prev_obj;\
alloc_status[type_name##_MT].objects_count++;\
return new_obj;\
}\
void deallocate_##type_name(type_name *kill_me) {\
type_name *prev_obj = PREV_OBJECT(kill_me, type_name);\
type_name *next_obj = NEXT_OBJECT(kill_me, type_name);\
if (prev_obj == NULL) {\
alloc_status[type_name##_MT].first_in_memory = next_obj;\
} else {\
prev_obj->next_structure = next_obj;\
}\
if (next_obj == NULL) {\
alloc_status[type_name##_MT].last_in_memory = prev_obj;\
} else {\
next_obj->prev_structure = prev_obj;\
}\
alloc_status[type_name##_MT].objects_count--;\
}\
type_name *allocate_##type_name##_before(type_name *existing) {\
type_name *new_obj = allocate_##type_name();\
deallocate_##type_name(new_obj);\
new_obj->prev_structure = existing->prev_structure;\
if (existing->prev_structure != NULL)\
((type_name *) existing->prev_structure)->next_structure = new_obj;\
else alloc_status[type_name##_MT].first_in_memory = (void *) new_obj;\
new_obj->next_structure = existing;\
existing->prev_structure = new_obj;\
alloc_status[type_name##_MT].objects_count++;\
return new_obj;\
}
#define ALLOCATE_IN_ARRAYS(type_name, NO_TO_ALLOCATE_TOGETHER)\
typedef struct type_name##_array {\
int used;\
struct type_name array[NO_TO_ALLOCATE_TOGETHER];\
MEMORY_MANAGEMENT\
} type_name##_array;\
ALLOCATE_INDIVIDUALLY(type_name##_array)\
type_name##_array *next_##type_name##_array = NULL;\
struct type_name *allocate_##type_name(void) {\
if ((next_##type_name##_array == NULL) ||\
(next_##type_name##_array->used >= NO_TO_ALLOCATE_TOGETHER)) {\
alloc_status[type_name##_array_MT].no_allocated_together = NO_TO_ALLOCATE_TOGETHER;\
next_##type_name##_array = allocate_##type_name##_array();\
next_##type_name##_array->used = 0;\
}\
return &(next_##type_name##_array->array[\
next_##type_name##_array->used++]);\
}
#define FORMAT_PERHAPS_HTML 1
#define FORMAT_PERHAPS_JPEG 2
#define FORMAT_PERHAPS_PNG 3
#define FORMAT_PERHAPS_OGG 4
#define FORMAT_PERHAPS_AIFF 5
#define FORMAT_PERHAPS_MIDI 6
#define FORMAT_PERHAPS_MOD 7
#define FORMAT_PERHAPS_GLULX 8
#define FORMAT_PERHAPS_ZCODE 9
#define FORMAT_UNRECOGNISED 0
#define author_COMMAND 0
#define auxiliary_COMMAND 1
#define base64_COMMAND 2
#define copyright_COMMAND 3
#define cover_COMMAND 4
#define css_COMMAND 5
#define ifiction_COMMAND 6
#define ifiction_public_COMMAND 7
#define ifiction_file_COMMAND 8
#define interpreter_COMMAND 9
#define palette_COMMAND 10
#define palette_16_bit_COMMAND 11
#define palette_32_bit_COMMAND 12
#define picture_scaled_COMMAND 13
#define picture_COMMAND 14
#define picture_text_COMMAND 15
#define picture_noid_COMMAND 16
#define picture_with_alt_text_COMMAND 17
#define placeholder_COMMAND 18
#define project_folder_COMMAND 19
#define release_COMMAND 20
#define release_file_COMMAND 21
#define release_file_from_COMMAND 22
#define release_source_COMMAND 23
#define release_to_COMMAND 24
#define resolution_max_COMMAND 25
#define resolution_min_max_COMMAND 26
#define resolution_min_COMMAND 27
#define resolution_COMMAND 28
#define solution_COMMAND 29
#define solution_public_COMMAND 30
#define sound_music_COMMAND 31
#define sound_repeat_COMMAND 32
#define sound_forever_COMMAND 33
#define sound_song_COMMAND 34
#define sound_COMMAND 35
#define sound_text_COMMAND 36
#define sound_noid_COMMAND 37
#define sound_with_alt_text_COMMAND 38
#define source_COMMAND 39
#define source_public_COMMAND 40
#define status_COMMAND 41
#define status_alternative_COMMAND 42
#define status_instruction_COMMAND 43
#define storyfile_include_COMMAND 44
#define storyfile_COMMAND 45
#define storyfile_leafname_COMMAND 46
#define template_path_COMMAND 47
#define website_COMMAND 48
#define OPS_NO 1
#define OPS_1TEXT 2
#define OPS_2TEXT 3
#define OPS_2TEXT_1NUMBER 4
#define OPS_1NUMBER 5
#define OPS_2NUMBER 6
#define OPS_1NUMBER_1TEXT 7
#define OPS_1NUMBER_2TEXTS 8
#define OPS_1NUMBER_1TEXT_1NUMBER 9
#define OPS_3NUMBER 10
#define OPS_3TEXT 11
#define COPY_REQ 0 /* a miscellaneous file */
#define IFICTION_REQ 1 /* the iFiction record of a project */
#define RELEASE_FILE_REQ 2 /* a template file */
#define RELEASE_SOURCE_REQ 3 /* the source text in HTML form */
#define SOLUTION_REQ 4 /* a solution file generated from the skein */
#define SOURCE_REQ 5 /* the source text of a project */
#define WEBSITE_REQ 6 /* a whole website */
#define INTERPRETER_REQ 7 /* an in-browser interpreter */
#define BASE64_REQ 8 /* a base64-encoded copy of a binary file */
#define INSTRUCTION_REQ 9 /* a release instruction copied to cblorb for reporting only */
#define ALTERNATIVE_REQ 10 /* an unused release instruction copied to cblorb for reporting only */
#define MAX_NODE_ID_LENGTH 32
#define MAX_COMMAND_LENGTH 128
#define MAX_ANNOTATION_LENGTH 128
#define NORMAL_COMMAND 1
#define BRANCH_TO_END_COMMAND 2
#define BRANCH_TO_LINE_COMMAND 3
#define SOURCE_RPL 1
#define SOURCENOTES_RPL 2
#define SOURCELINKS_RPL 3
#define COVER_RPL 4
#define DOWNLOAD_RPL 5
#define AUXILIARY_RPL 6
#define PAGENUMBER_RPL 7
#define PAGEEXTENT_RPL 8
#define ABBREVIATED_HEADING_LENGTH 1000
#define EMPTY_LEVEL -1
#define DULL_LEVEL 0
#define TABLE_LEVEL 1000
#define DOC_LEVEL 1001
#define EXAMPLE_LEVEL 1002
#define DOC_CHAPTER_LEVEL 1003
#define DOC_SECTION_LEVEL 1004
#line 68 "cBlorb/Chapter 1/Memory.w"
typedef struct allocation_status_structure {
/* actually needed for allocation purposes: */
int objects_allocated; /* total number of objects (or arrays) ever allocated */
void *first_in_memory; /* head of doubly linked list */
void *last_in_memory; /* tail of doubly linked list */
/* used only to provide statistics for the debugging log: */
char *name_of_type; /* e.g., |"lexicon_entry_MT"| */
int bytes_allocated; /* total allocation for this type of object, not counting overhead */
int objects_count; /* total number currently in existence (i.e., undeleted) */
int no_allocated_together; /* number of objects in each array of this type of object */
} allocation_status_structure;
#line 151 "cBlorb/Chapter 1/Memory.w"
typedef struct memblock_header {
int block_number;
struct memblock_header *next;
char *the_memory;
} memblock_header;
#line 231 "cBlorb/Chapter 1/Memory.w"
typedef struct memory_frame {
int integrity_check; /* this should always contain the |INTEGRITY_NUMBER| */
struct memory_frame *next_frame; /* next frame in the list of memory frames */
int mem_type; /* type of object stored in this frame */
int allocation_id; /* allocation ID number of object stored in this frame */
} memory_frame;
#line 14 "cBlorb/Chapter 1/Text Files.w"
typedef struct text_file_position {
char text_file_filename[MAX_FILENAME_LENGTH];
int line_count;
int line_position;
int skip_terminator;
int actively_scanning; /* whether we are still interested in the rest of the file */
} text_file_position;
#line 107 "cBlorb/Chapter 1/Blurb Parser.w"
typedef struct blurb_command {
char *explicated; /* plain English form of the command */
char *prototype; /* |sscanf| prototype */
int operands; /* one of the above |OPS_*| codes */
int deprecated;
} blurb_command;
#line 44 "cBlorb/Chapter 2/Blorb Writer.w"
typedef struct chunk_metadata {
char filename[MAX_FILENAME_LENGTH]; /* if the content is stored on disc */
unsigned char data_in_memory[MAX_FILENAME_LENGTH]; /* if the content is stored in memory */
int length_of_data_in_memory; /* in bytes; or $-1$ if the content is stored on disc */
char *chunk_type; /* pointer to a 4-character string */
char *index_entry; /* ditto */
int resource_id; /* meaningful only if this is a chunk which is indexed */
int byte_offset; /* from the start of the chunks, which is not quite the start of the IFF file */
int size; /* in bytes */
MEMORY_MANAGEMENT
} chunk_metadata;
#line 61 "cBlorb/Chapter 2/Blorb Writer.w"
typedef struct resource_list resource_list;
struct resource_list {
int num;
struct resource_list *n;
};
#line 73 "cBlorb/Chapter 2/Blorb Writer.w"
typedef struct rdes_record {
int usage;
int resource_id;
char *description;
MEMORY_MANAGEMENT
} rdes_record;
#line 35 "cBlorb/Chapter 3/Releaser.w"
typedef struct request {
int what_is_requested; /* one of the |*_REQ| values above */
char details1[MAX_FILENAME_LENGTH];
char details2[MAX_FILENAME_LENGTH];
char details3[MAX_FILENAME_LENGTH];
int private; /* is this request private, i.e., not to contribute to a website? */
int outcome_data; /* e.g. number of bytes copied */
MEMORY_MANAGEMENT
} request;
#line 33 "cBlorb/Chapter 3/Solution Deviser.w"
typedef struct skein_node {
char id[MAX_NODE_ID_LENGTH]; /* uniquely identifying ID used within the Skein file */
char command[MAX_COMMAND_LENGTH]; /* text of the command at this node */
char annotation[MAX_ANNOTATION_LENGTH]; /* text of any annotation added by the user */
int relevant; /* is this node within one of the "relevant" lines in the skein? */
struct skein_node *branch_parent; /* the trunk of the branch description, if any, is this way */
int branch_count; /* the leaf of the branch description, if any, is this number */
struct skein_node *parent; /* within the Skein tree: |NULL| for the root only */
struct skein_node *child; /* within the Skein tree: |NULL| if a leaf */
struct skein_node *sibling; /* within the Skein tree: |NULL| if the final option from its parent */
MEMORY_MANAGEMENT
} skein_node;
#line 18 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
typedef struct auxiliary_file {
char relative_URL[MAX_FILENAME_LENGTH];
char full_filename[MAX_FILENAME_LENGTH];
char aux_leafname[MAX_FILENAME_LENGTH];
char aux_subfolder[MAX_FILENAME_LENGTH];
char description[MAX_FILENAME_LENGTH];
char format[MAX_EXTENSION_LENGTH]; /* e.g., "jpg", "pdf" */
MEMORY_MANAGEMENT
} auxiliary_file;
#line 27 "cBlorb/Chapter 3/Placeholders.w"
typedef struct placeholder {
char pl_name[MAX_VAR_NAME_LENGTH];
char pl_contents[MAX_FILENAME_LENGTH]; /* current value */
int reservation; /* one of the |*_RPL| values above, or 0 for unreserved */
int locked; /* currently being expanded: locked to prevent mise-en-abyme */
MEMORY_MANAGEMENT
} placeholder;
#line 15 "cBlorb/Chapter 3/Templates.w"
typedef struct template_path {
char template_repository[MAX_FILENAME_LENGTH]; /* pathname of folder of repository */
MEMORY_MANAGEMENT
} template_path;
#line 23 "cBlorb/Chapter 3/Templates.w"
typedef struct template {
char template_name[MAX_FILENAME_LENGTH]; /* e.g., "Standard" */
struct template_path *template_location;
char latest_use[MAX_FILENAME_LENGTH]; /* filename most recently sought from it */
MEMORY_MANAGEMENT
} template;
#line 20 "cBlorb/Chapter 3/Website Maker.w"
typedef struct table {
int table_line_start; /* line number in the source where the table heading appears */
int table_line_end; /* line number of the blank line which marks the end of the table body */
MEMORY_MANAGEMENT
} table;
#line 26 "cBlorb/Chapter 3/Website Maker.w"
typedef struct heading {
int heading_line; /* line number in the source at which the heading appears */
int heading_level; /* a low number makes this a more significant heading than a high number */
int heading_has_content; /* is there anything other than white space before the next heading? */
struct segment *heading_to_segment; /* which segment contains the heading */
char heading_text[ABBREVIATED_HEADING_LENGTH + 1]; /* truncated if necessary for the contents */
MEMORY_MANAGEMENT
} heading;
#line 66 "cBlorb/Chapter 3/Website Maker.w"
typedef struct segment {
int begins_at; /* line number on which the segment begins */
int ends_at; /* line number of the last line of the segment, or |MAX_SOURCE_TEXT_LINES| if it runs to the end */
int documentation; /* is this in the documentation of an extension? */
struct text_file_position start_position_in_file; /* within the source text */
struct heading *most_recent_heading; /* or |NULL| if there hasn't been one */
struct table *most_recent_table; /* or |NULL| if there hasn't been one */
char segment_url[MAX_FILENAME_LENGTH];
char *link_home;
char *link_contents;
char *link_previous;
char *link_next;
int page_number;
MEMORY_MANAGEMENT
} segment;
#line 87 "cBlorb/Chapter 1/Main.w"
int main(int argc, char *argv[]) ;
#line 244 "cBlorb/Chapter 1/Main.w"
void establish_time(void) ;
#line 255 "cBlorb/Chapter 1/Main.w"
void initialise_time_variables(void) ;
#line 280 "cBlorb/Chapter 1/Main.w"
void print_banner(void) ;
#line 294 "cBlorb/Chapter 1/Main.w"
void print_report(void) ;
#line 89 "cBlorb/Chapter 1/Memory.w"
void start_memory(void) ;
#line 166 "cBlorb/Chapter 1/Memory.w"
void allocate_another_block(void) ;
#line 211 "cBlorb/Chapter 1/Memory.w"
void free_memory(void) ;
#line 255 "cBlorb/Chapter 1/Memory.w"
void check_memory_integrity(void) ;
#line 266 "cBlorb/Chapter 1/Memory.w"
void debug_memory_frames(int from, int to) ;
#line 283 "cBlorb/Chapter 1/Memory.w"
void * allocate_mem(int mem_type, int extent) ;
#line 498 "cBlorb/Chapter 1/Memory.w"
char cblorb_tolower(char c) ;
#line 501 "cBlorb/Chapter 1/Memory.w"
char cblorb_toupper(char c) ;
#line 504 "cBlorb/Chapter 1/Memory.w"
int cblorb_strlen(const char *p) ;
#line 28 "cBlorb/Chapter 1/Text Files.w"
void describe_file_position(char *t, text_file_position *tfp) ;
#line 37 "cBlorb/Chapter 1/Text Files.w"
int tfp_get_line_count(text_file_position *tfp) ;
#line 45 "cBlorb/Chapter 1/Text Files.w"
void tfp_lose_interest(text_file_position *tfp) ;
#line 58 "cBlorb/Chapter 1/Text Files.w"
void set_error_position(text_file_position *tfp) ;
#line 62 "cBlorb/Chapter 1/Text Files.w"
void error(char *erm) ;
#line 69 "cBlorb/Chapter 1/Text Files.w"
void error_1(char *erm, char *s) ;
#line 76 "cBlorb/Chapter 1/Text Files.w"
void errorf_1s(char *erm, char *s1) ;
#line 82 "cBlorb/Chapter 1/Text Files.w"
void errorf_2s(char *erm, char *s1, char *s2) ;
#line 88 "cBlorb/Chapter 1/Text Files.w"
void fatal(char *erm) ;
#line 97 "cBlorb/Chapter 1/Text Files.w"
void fatal_fs(char *erm, char *fn) ;
#line 106 "cBlorb/Chapter 1/Text Files.w"
void warning_fs(char *erm, char *fn) ;
#line 115 "cBlorb/Chapter 1/Text Files.w"
void spool_error(char *err) ;
#line 129 "cBlorb/Chapter 1/Text Files.w"
void file_read(char *filename, char *message, int serious, void (iterator)(char *, text_file_position *), text_file_position *start_at) ;
#line 234 "cBlorb/Chapter 1/Text Files.w"
char * trim_white_space(char *original) ;
#line 246 "cBlorb/Chapter 1/Text Files.w"
void extract_word(char *fword, char *line, int size, int word) ;
#line 266 "cBlorb/Chapter 1/Text Files.w"
int white_space(int c) ;
#line 279 "cBlorb/Chapter 1/Text Files.w"
char * get_filename_extension(char *filename) ;
#line 301 "cBlorb/Chapter 1/Text Files.w"
int infer_format_from_filename_extension(char *filename) ;
#line 330 "cBlorb/Chapter 1/Text Files.w"
char * get_filename_leafname(char *filename) ;
#line 336 "cBlorb/Chapter 1/Text Files.w"
int file_exists(char *filename) ;
#line 342 "cBlorb/Chapter 1/Text Files.w"
long int file_size(char *filename) ;
#line 356 "cBlorb/Chapter 1/Text Files.w"
int copy_file(char *from, char *to, int suppress_error) ;
#line 15 "cBlorb/Chapter 1/Blurb Parser.w"
void parse_blurb_file(char *in) ;
#line 191 "cBlorb/Chapter 1/Blurb Parser.w"
void summarise_blurb(void) ;
#line 208 "cBlorb/Chapter 1/Blurb Parser.w"
void interpret(char *command, text_file_position *tf) ;
#line 374 "cBlorb/Chapter 1/Blurb Parser.w"
void qualify_placeholder(char *openUrl_path, char *fileUrl_path, char *original) ;
#line 88 "cBlorb/Chapter 2/Blorb Writer.w"
void four_word(FILE *F, int n) ;
#line 95 "cBlorb/Chapter 2/Blorb Writer.w"
void two_word(FILE *F, int n) ;
#line 100 "cBlorb/Chapter 2/Blorb Writer.w"
void one_byte(FILE *F, int n) ;
#line 104 "cBlorb/Chapter 2/Blorb Writer.w"
void s_four_word(unsigned char *F, int n) ;
#line 111 "cBlorb/Chapter 2/Blorb Writer.w"
void s_two_word(unsigned char *F, int n) ;
#line 116 "cBlorb/Chapter 2/Blorb Writer.w"
void s_one_byte(unsigned char *F, int n) ;
#line 135 "cBlorb/Chapter 2/Blorb Writer.w"
void add_chunk_to_blorb(char *id, int resource_num, char *supplied_filename, char *index, unsigned char *data, int length) ;
#line 219 "cBlorb/Chapter 2/Blorb Writer.w"
int chunk_type_is_legal(char *type) ;
#line 228 "cBlorb/Chapter 2/Blorb Writer.w"
int index_entry_is_legal(char *entry) ;
#line 243 "cBlorb/Chapter 2/Blorb Writer.w"
int resource_seen(resource_list **list, int value) ;
#line 262 "cBlorb/Chapter 2/Blorb Writer.w"
int chunk_type_is_already_an_IFF(char *type) ;
#line 270 "cBlorb/Chapter 2/Blorb Writer.w"
void author_chunk(char *t) ;
#line 278 "cBlorb/Chapter 2/Blorb Writer.w"
void copyright_chunk(char *t) ;
#line 287 "cBlorb/Chapter 2/Blorb Writer.w"
void frontispiece_chunk(int pn) ;
#line 297 "cBlorb/Chapter 2/Blorb Writer.w"
void release_chunk(int rn) ;
#line 309 "cBlorb/Chapter 2/Blorb Writer.w"
void picture_chunk(int n, char *fn, char *alt) ;
#line 337 "cBlorb/Chapter 2/Blorb Writer.w"
void picture_chunk_text(char *name, char *fn) ;
#line 355 "cBlorb/Chapter 2/Blorb Writer.w"
void sound_chunk(int n, char *fn, char *alt) ;
#line 376 "cBlorb/Chapter 2/Blorb Writer.w"
void sound_chunk_text(char *name, char *fn) ;
#line 392 "cBlorb/Chapter 2/Blorb Writer.w"
void add_rdes_record(int usage, int n, char *alt) ;
#line 404 "cBlorb/Chapter 2/Blorb Writer.w"
void rdes_chunk(void) ;
#line 430 "cBlorb/Chapter 2/Blorb Writer.w"
void executable_chunk(char *fn) ;
#line 446 "cBlorb/Chapter 2/Blorb Writer.w"
void metadata_chunk(char *fn) ;
#line 453 "cBlorb/Chapter 2/Blorb Writer.w"
void write_blorb_file(char *out) ;
#line 51 "cBlorb/Chapter 3/Releaser.w"
request * request_0(int kind, int privacy) ;
#line 63 "cBlorb/Chapter 3/Releaser.w"
request * request_1(int kind, char *text1, int privacy) ;
#line 69 "cBlorb/Chapter 3/Releaser.w"
request * request_2(int kind, char *text1, char *text2, int privacy) ;
#line 76 "cBlorb/Chapter 3/Releaser.w"
request * request_3(int kind, char *text1, char *text2, char *text3, int privacy) ;
#line 87 "cBlorb/Chapter 3/Releaser.w"
void request_copy(char *from, char *to, char *subfolder) ;
#line 97 "cBlorb/Chapter 3/Releaser.w"
void any_last_requests(void) ;
#line 118 "cBlorb/Chapter 3/Releaser.w"
void create_requested_material(void) ;
#line 275 "cBlorb/Chapter 3/Releaser.w"
void read_requested_file(char *filename, text_file_position *tfp) ;
#line 301 "cBlorb/Chapter 3/Releaser.w"
void read_requested_ifile(char *manifestline, text_file_position *tfp) ;
#line 388 "cBlorb/Chapter 3/Releaser.w"
void release_file_into_website(char *name, char *t, char *sub) ;
#line 428 "cBlorb/Chapter 3/Releaser.w"
void add_links_to_requested_resources(FILE *COPYTO) ;
#line 462 "cBlorb/Chapter 3/Releaser.w"
void declare_where_blorb_should_be_copied(char *path) ;
#line 476 "cBlorb/Chapter 3/Releaser.w"
void report_requested_material(char *ph) ;
#line 662 "cBlorb/Chapter 3/Releaser.w"
int count_requests_of_type(int t) ;
#line 62 "cBlorb/Chapter 3/Solution Deviser.w"
void walkthrough(char *Skein_filename, char *walkthrough_filename) ;
#line 82 "cBlorb/Chapter 3/Solution Deviser.w"
void build_skein_tree(char *Skein_filename) ;
#line 90 "cBlorb/Chapter 3/Solution Deviser.w"
void read_skein_pass_1(char *line, text_file_position *tfp) ;
#line 91 "cBlorb/Chapter 3/Solution Deviser.w"
void read_skein_pass_2(char *line, text_file_position *tfp) ;
#line 101 "cBlorb/Chapter 3/Solution Deviser.w"
void read_skein_line(char *line, int pass) ;
#line 180 "cBlorb/Chapter 3/Solution Deviser.w"
int find_node_ID_in_tag(char *line, char *tag, char *write_to, int max_length, int abort_not_trim) ;
#line 202 "cBlorb/Chapter 3/Solution Deviser.w"
int find_text_of_tag(char *line, char *tag, char *write_to, int max_length, int abort_not_trim) ;
#line 225 "cBlorb/Chapter 3/Solution Deviser.w"
skein_node * find_node_with_ID(char *id) ;
#line 236 "cBlorb/Chapter 3/Solution Deviser.w"
void convert_string_to_upper_case(char *p) ;
#line 244 "cBlorb/Chapter 3/Solution Deviser.w"
void undo_XML_escapes_in_string(char *p) ;
#line 280 "cBlorb/Chapter 3/Solution Deviser.w"
void identify_relevant_lines(void) ;
#line 315 "cBlorb/Chapter 3/Solution Deviser.w"
void prune_irrelevant_lines(void) ;
#line 338 "cBlorb/Chapter 3/Solution Deviser.w"
void write_solution_file(char *walkthrough_filename) ;
#line 354 "cBlorb/Chapter 3/Solution Deviser.w"
void recursively_solve(FILE *SOL, skein_node *skn, skein_node *last_branch) ;
#line 412 "cBlorb/Chapter 3/Solution Deviser.w"
void write_command(FILE *SOL, skein_node *cmd_skn, int form) ;
#line 435 "cBlorb/Chapter 3/Solution Deviser.w"
void write_branch_name(FILE *SOL, skein_node *skn) ;
#line 38 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void create_auxiliary_file(char *filename, char *description, char *subfolder) ;
#line 67 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void expand_AUXILIARY_variable(FILE *COPYTO) ;
#line 84 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void expand_DOWNLOAD_variable(FILE *COPYTO) ;
#line 94 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void download_link(FILE *COPYTO, char *desc, char *filename, char *relative_url, char *form) ;
#line 131 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void expand_COVER_variable(FILE *COPYTO) ;
#line 144 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void request_copy_of_auxiliaries(void) ;
#line 42 "cBlorb/Chapter 3/Placeholders.w"
void initialise_placeholders(void) ;
#line 70 "cBlorb/Chapter 3/Placeholders.w"
placeholder * find_placeholder(char *name) ;
#line 78 "cBlorb/Chapter 3/Placeholders.w"
char * read_placeholder(char *name) ;
#line 88 "cBlorb/Chapter 3/Placeholders.w"
void set_placeholder_to_number(char *var, int v) ;
#line 101 "cBlorb/Chapter 3/Placeholders.w"
void set_placeholder_to(char *var, char *text, int reservation) ;
#line 104 "cBlorb/Chapter 3/Placeholders.w"
void append_to_placeholder(char *var, char *text) ;
#line 111 "cBlorb/Chapter 3/Placeholders.w"
void set_placeholder_to_inner(char *var, char *text, int reservation, int extend) ;
#line 147 "cBlorb/Chapter 3/Placeholders.w"
void copy_placeholder_to(char *var, FILE *COPYTO) ;
#line 37 "cBlorb/Chapter 3/Templates.w"
void new_template_path(char *pathname) ;
#line 51 "cBlorb/Chapter 3/Templates.w"
template_path * seek_file_in_template_paths(char *name, char *leafname) ;
#line 71 "cBlorb/Chapter 3/Templates.w"
template * find_template(char *name) ;
#line 101 "cBlorb/Chapter 3/Templates.w"
char * find_file_in_named_template(char *name, char *needed) ;
#line 124 "cBlorb/Chapter 3/Templates.w"
char * try_single_template(template *t, char *needed) ;
#line 110 "cBlorb/Chapter 3/Website Maker.w"
void open_style(FILE *write_to, char *new) ;
#line 128 "cBlorb/Chapter 3/Website Maker.w"
void close_style(FILE *write_to, char *old) ;
#line 154 "cBlorb/Chapter 3/Website Maker.w"
void change_style(FILE *write_to, char *new) ;
#line 166 "cBlorb/Chapter 3/Website Maker.w"
void open_code(FILE *write_to) ;
#line 172 "cBlorb/Chapter 3/Website Maker.w"
void close_code(FILE *write_to) ;
#line 182 "cBlorb/Chapter 3/Website Maker.w"
void open_code_paragraph(FILE *write_to, int indentation) ;
#line 204 "cBlorb/Chapter 3/Website Maker.w"
void close_code_paragraph(FILE *write_to) ;
#line 216 "cBlorb/Chapter 3/Website Maker.w"
void open_table_cell(FILE *write_to) ;
#line 224 "cBlorb/Chapter 3/Website Maker.w"
void close_table_cell(FILE *write_to) ;
#line 236 "cBlorb/Chapter 3/Website Maker.w"
void web_copy(char *from, char *to) ;
#line 249 "cBlorb/Chapter 3/Website Maker.w"
void copy_html_line(char *line, text_file_position *tfp) ;
#line 298 "cBlorb/Chapter 3/Website Maker.w"
void web_copy_source(char *template, char *website_pathname) ;
#line 322 "cBlorb/Chapter 3/Website Maker.w"
void scan_source_text(void) ;
#line 358 "cBlorb/Chapter 3/Website Maker.w"
void scan_source_line(char *line, text_file_position *tfp) ;
#line 470 "cBlorb/Chapter 3/Website Maker.w"
void write_source_text_pages(char *template, char *website_pathname) ;
#line 570 "cBlorb/Chapter 3/Website Maker.w"
void expand_PAGENUMBER_variable(FILE *COPYTO) ;
#line 582 "cBlorb/Chapter 3/Website Maker.w"
void expand_PAGEEXTENT_variable(FILE *COPYTO) ;
#line 593 "cBlorb/Chapter 3/Website Maker.w"
void expand_SOURCELINKS_variable(FILE *COPYTO) ;
#line 632 "cBlorb/Chapter 3/Website Maker.w"
void expand_SOURCE_or_SOURCENOTES_variable(FILE *write_to, int SN) ;
#line 701 "cBlorb/Chapter 3/Website Maker.w"
void source_write_iterator(char *line, text_file_position *tfp) ;
#line 715 "cBlorb/Chapter 3/Website Maker.w"
int write_source_line(char *line, text_file_position *tfp) ;
#line 1027 "cBlorb/Chapter 3/Website Maker.w"
void typeset_contents_listing(int source_contents) ;
#line 29 "cBlorb/Chapter 3/Base64.w"
void encode_as_base64(char *in_filename, char *out_filename, char *top, char *tail) ;
#line 16 "cBlorb/Chapter 1/Main.w"
#line 45 "cBlorb/Chapter 1/Main.w"
char SEP_CHAR = '/'; /* local file-system filename separator */
char *FONT_TAG = "size=2"; /* contents of a |<font>| tag */
char *JAVASCRIPT_PRELUDE = "javascript:window.Project."; /* calling prefix */
int escape_openUrl = FALSE, escape_fileUrl = FALSE;
int reverse_slash_openUrl = FALSE, reverse_slash_fileUrl = FALSE;
#line 54 "cBlorb/Chapter 1/Main.w"
int trace_mode = FALSE; /* print diagnostics to |stdout| while running? */
int error_count = 0; /* number of error messages produced so far */
int current_year_AD = 0; /* e.g., 2008 */
int blorb_file_size = 0; /* size in bytes of the blorb file written */
int no_pictures_included = 0; /* number of picture resources included in the blorb */
int no_sounds_included = 0; /* number of sound resources included in the blorb */
int HTML_pages_created = 0; /* number of pages created in the website, if any */
int source_HTML_pages_created = 0; /* number of those holding source */
int sound_resource_num = 3; /* current sound resource number we're working on */
int picture_resource_num = 1; /* current picture resource number we're working on */
int use_css_code_styles = FALSE; /* use |<span class="X">| markings when setting code */
char project_folder[MAX_FILENAME_LENGTH]; /* pathname of I7 project folder, if any */
char release_folder[MAX_FILENAME_LENGTH]; /* pathname of folder for website to write, if any */
char status_template[MAX_FILENAME_LENGTH]; /* filename of report HTML page template, if any */
char status_file[MAX_FILENAME_LENGTH]; /* filename of report HTML page to write, if any */
int cover_exists = FALSE; /* an image is specified as cover art */
int default_cover_used = FALSE; /* but it's only the default supplied by Inform */
int cover_is_in_JPEG_format = TRUE; /* as opposed to |PNG| format */
#line 21 "cBlorb/Chapter 1/Text Files.w"
#line 28 "cBlorb/Chapter 2/Blorb Writer.w"
int total_size_of_Blorb_chunks = 0; /* ditto, but not counting the |FORM| header or the |RIdx| chunk */
int no_indexed_chunks = 0;
#line 55 "cBlorb/Chapter 2/Blorb Writer.w"
#line 66 "cBlorb/Chapter 2/Blorb Writer.w"
resource_list *sound_resource = NULL;
resource_list *pict_resource = NULL;
#line 79 "cBlorb/Chapter 2/Blorb Writer.w"
#line 29 "cBlorb/Chapter 3/Releaser.w"
int website_requested = FALSE; /* has a |WEBSITE_REQ| been made? */
#line 44 "cBlorb/Chapter 3/Releaser.w"
#line 45 "cBlorb/Chapter 3/Solution Deviser.w"
#line 50 "cBlorb/Chapter 3/Solution Deviser.w"
skein_node *root_skn = NULL; /* only |NULL| when the tree is empty */
#line 27 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
#line 34 "cBlorb/Chapter 3/Placeholders.w"
#line 19 "cBlorb/Chapter 3/Templates.w"
#line 29 "cBlorb/Chapter 3/Templates.w"
#line 25 "cBlorb/Chapter 3/Website Maker.w"
#line 34 "cBlorb/Chapter 3/Website Maker.w"
#line 81 "cBlorb/Chapter 3/Website Maker.w"
#line 87 "cBlorb/Chapter 1/Main.w"
int main(int argc, char *argv[]) {
int platform, produce_help;
char blurb_filename[MAX_FILENAME_LENGTH];
char blorb_filename[MAX_FILENAME_LENGTH];
{
#line 115 "cBlorb/Chapter 1/Main.w"
platform = OSX_PLATFORM;
produce_help = FALSE;
release_folder[0] = 0;
project_folder[0] = 0;
status_file[0] = 0;
status_template[0] = 0;
strcpy(blurb_filename, "Release.blurb");
strcpy(blorb_filename, "story.zblorb");
}
#line 92 "cBlorb/Chapter 1/Main.w"
;
{
#line 127 "cBlorb/Chapter 1/Main.w"
int arg, names;
for (arg = 1, names = 0; arg < argc; arg++) {
char *p = argv[arg];
if (cblorb_strlen(p) >= MAX_FILENAME_LENGTH) {
fprintf(stderr, "cblorb: command line argument %d too long\n", arg+1);
return 1;
}
{
#line 152 "cBlorb/Chapter 1/Main.w"
if (strcmp(p, "-help") == 0) { produce_help = TRUE; continue; }
if (strcmp(p, "-osx") == 0) { platform = OSX_PLATFORM; continue; }
if (strcmp(p, "-windows") == 0) { platform = WINDOWS_PLATFORM; continue; }
if (strcmp(p, "-unix") == 0) { platform = UNIX_PLATFORM; continue; }
if (strcmp(p, "-trace") == 0) { trace_mode = TRUE; continue; }
if (strcmp(p, "-project") == 0) {
arg++; if (arg == argc)
{
#line 221 "cBlorb/Chapter 1/Main.w"
{
#line 227 "cBlorb/Chapter 1/Main.w"
printf("usage: cblorb -platform [-options] [blurbfile [blorbfile]]\n\n");
printf(" Where -platform should be -osx (default), -windows, or -unix\n");
printf(" As an alternative to giving filenames for the blurb and blorb,\n");
printf(" -project Whatever.inform\n");
printf(" sets blurbfile and blorbfile names to the natural choices.\n");
printf(" The other possible options are:\n");
printf(" -help ... print this usage summary\n");
printf(" -trace ... print diagnostic information during run\n");
}
#line 221 "cBlorb/Chapter 1/Main.w"
;
return 1;
}
#line 158 "cBlorb/Chapter 1/Main.w"
;
strcpy(project_folder, argv[arg]);
continue;
}
if (p[0] == '-')
{
#line 221 "cBlorb/Chapter 1/Main.w"
{
#line 227 "cBlorb/Chapter 1/Main.w"
printf("usage: cblorb -platform [-options] [blurbfile [blorbfile]]\n\n");
printf(" Where -platform should be -osx (default), -windows, or -unix\n");
printf(" As an alternative to giving filenames for the blurb and blorb,\n");
printf(" -project Whatever.inform\n");
printf(" sets blurbfile and blorbfile names to the natural choices.\n");
printf(" The other possible options are:\n");
printf(" -help ... print this usage summary\n");
printf(" -trace ... print diagnostic information during run\n");
}
#line 221 "cBlorb/Chapter 1/Main.w"
;
return 1;
}
#line 162 "cBlorb/Chapter 1/Main.w"
;
names++;
switch (names) {
case 1: strcpy(blurb_filename, p); break;
case 2: strcpy(blorb_filename, p); break;
default:
{
#line 221 "cBlorb/Chapter 1/Main.w"
{
#line 227 "cBlorb/Chapter 1/Main.w"
printf("usage: cblorb -platform [-options] [blurbfile [blorbfile]]\n\n");
printf(" Where -platform should be -osx (default), -windows, or -unix\n");
printf(" As an alternative to giving filenames for the blurb and blorb,\n");
printf(" -project Whatever.inform\n");
printf(" sets blurbfile and blorbfile names to the natural choices.\n");
printf(" The other possible options are:\n");
printf(" -help ... print this usage summary\n");
printf(" -trace ... print diagnostic information during run\n");
}
#line 221 "cBlorb/Chapter 1/Main.w"
;
return 1;
}
#line 167 "cBlorb/Chapter 1/Main.w"
;
}
}
#line 134 "cBlorb/Chapter 1/Main.w"
;
}
{
#line 201 "cBlorb/Chapter 1/Main.w"
if (platform == OSX_PLATFORM) {
FONT_TAG = "face=\"lucida grande,geneva,arial,tahoma,verdana,helvetica,helv\" size=2";
escape_openUrl = TRUE; /* OS X requires |openUrl| to escape, and |fileUrl| not to */
}
if (platform == WINDOWS_PLATFORM) {
SEP_CHAR = '\\';
JAVASCRIPT_PRELUDE = "javascript:external.Project.";
reverse_slash_openUrl = TRUE; reverse_slash_fileUrl = TRUE;
}
}
#line 137 "cBlorb/Chapter 1/Main.w"
;
if (project_folder[0] != 0) {
if (names > 0)
{
#line 221 "cBlorb/Chapter 1/Main.w"
{
#line 227 "cBlorb/Chapter 1/Main.w"
printf("usage: cblorb -platform [-options] [blurbfile [blorbfile]]\n\n");
printf(" Where -platform should be -osx (default), -windows, or -unix\n");
printf(" As an alternative to giving filenames for the blurb and blorb,\n");
printf(" -project Whatever.inform\n");
printf(" sets blurbfile and blorbfile names to the natural choices.\n");
printf(" The other possible options are:\n");
printf(" -help ... print this usage summary\n");
printf(" -trace ... print diagnostic information during run\n");
}
#line 221 "cBlorb/Chapter 1/Main.w"
;
return 1;
}
#line 140 "cBlorb/Chapter 1/Main.w"
;
sprintf(blurb_filename, "%s%cRelease.blurb", project_folder, SEP_CHAR);
sprintf(blorb_filename, "%s%cBuild%coutput.zblorb", project_folder, SEP_CHAR, SEP_CHAR);
}
if (trace_mode)
printf("! Blurb in: <%s>\n! Blorb out: <%s>\n",
blurb_filename, blorb_filename);
}
#line 93 "cBlorb/Chapter 1/Main.w"
;
start_memory();
establish_time();
initialise_placeholders();
print_banner();
if (produce_help) {
{
#line 214 "cBlorb/Chapter 1/Main.w"
printf("This is cblorb, a component of Inform 7 for packaging up IF materials.\n\n");
{
#line 227 "cBlorb/Chapter 1/Main.w"
printf("usage: cblorb -platform [-options] [blurbfile [blorbfile]]\n\n");
printf(" Where -platform should be -osx (default), -windows, or -unix\n");
printf(" As an alternative to giving filenames for the blurb and blorb,\n");
printf(" -project Whatever.inform\n");
printf(" sets blurbfile and blorbfile names to the natural choices.\n");
printf(" The other possible options are:\n");
printf(" -help ... print this usage summary\n");
printf(" -trace ... print diagnostic information during run\n");
}
#line 215 "cBlorb/Chapter 1/Main.w"
;
summarise_blurb();
}
#line 100 "cBlorb/Chapter 1/Main.w"
; return 0; }
parse_blurb_file(blurb_filename);
write_blorb_file(blorb_filename);
create_requested_material();
print_report();
free_memory();
if (error_count > 0) return 1;
return 0;
}
#line 241 "cBlorb/Chapter 1/Main.w"
time_t the_present;
struct tm *here_and_now;
void establish_time(void) {
the_present = time(NULL);
here_and_now = localtime(&the_present);
}
#line 255 "cBlorb/Chapter 1/Main.w"
void initialise_time_variables(void) {
char datestamp[100], infocom[100], timestamp[100];
char *weekdays[] = { "Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday" };
char *months[] = { "January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December" };
set_placeholder_to_number("YEAR", here_and_now->tm_year+1900);
sprintf(datestamp, "%s %d %s %d", weekdays[here_and_now->tm_wday],
here_and_now->tm_mday, months[here_and_now->tm_mon], here_and_now->tm_year+1900);
sprintf(infocom, "%02d%02d%02d",
here_and_now->tm_year-100, here_and_now->tm_mon + 1, here_and_now->tm_mday);
sprintf(timestamp, "%02d:%02d.%02d", here_and_now->tm_hour,
here_and_now->tm_min, here_and_now->tm_sec);
set_placeholder_to("DATESTAMP", datestamp, 0);
set_placeholder_to("INFOCOMDATESTAMP", infocom, 0);
set_placeholder_to("TIMESTAMP", timestamp, 0);
}
#line 280 "cBlorb/Chapter 1/Main.w"
void print_banner(void) {
printf("! %s [executing on %s at %s]\n",
VERSION, read_placeholder("DATESTAMP"), read_placeholder("TIMESTAMP"));
printf("! The blorb spell (safely protect a small object ");
printf("as though in a strong box).\n");
}
#line 294 "cBlorb/Chapter 1/Main.w"
void print_report(void) {
if (error_count > 0) printf("! Completed: %d error(s)\n", error_count);
{
#line 305 "cBlorb/Chapter 1/Main.w"
if (error_count > 0) {
set_placeholder_to("CBLORBSTATUS", "Failed", 0);
set_placeholder_to("CBLORBSTATUSIMAGE", "inform:/outcome_images/cblorb_failed.png", 0);
set_placeholder_to("CBLORBSTATUSTEXT",
"Inform translated your source text as usual, to manufacture a 'story "
"file': all of that worked fine. But the Release then went wrong, for "
"the following reason:<p><ul>[CBLORBERRORS]</ul>", 0
);
} else {
set_placeholder_to("CBLORBERRORS", "No problems occurred", 0);
set_placeholder_to("CBLORBSTATUS", "Succeeded", 0);
set_placeholder_to("CBLORBSTATUSIMAGE", "file://[SMALLCOVER]", 0);
set_placeholder_to("CBLORBSTATUSTEXT",
"All went well. I've put the released material into the 'Release' subfolder "
"of the Materials folder for the project: you can take a look with "
"the menu option <b>Release &gt; Open Materials Folder</b> or by clicking "
"the blue folders above.<p>"
"Releases can range in size from a single blorb file to a medium-sized website. "
"Here's what we currently have:<p>", 0
);
report_requested_material("CBLORBSTATUSTEXT");
}
if (blorb_file_size > 0) {
set_placeholder_to_number("BLORBFILESIZE", blorb_file_size/1024);
set_placeholder_to_number("BLORBFILEPICTURES", no_pictures_included);
set_placeholder_to_number("BLORBFILESOUNDS", no_sounds_included);
printf("! Completed: wrote blorb file of size %d bytes ", blorb_file_size);
printf("(%d picture(s), %d sound(s))\n", no_pictures_included, no_sounds_included);
} else {
set_placeholder_to_number("BLORBFILESIZE", 0);
set_placeholder_to_number("BLORBFILEPICTURES", 0);
set_placeholder_to_number("BLORBFILESOUNDS", 0);
printf("! Completed: no blorb output requested\n");
}
}
#line 296 "cBlorb/Chapter 1/Main.w"
;
if (status_template[0]) web_copy(status_template, status_file);
}
#line 81 "cBlorb/Chapter 1/Memory.w"
#line 87 "cBlorb/Chapter 1/Memory.w"
allocation_status_structure alloc_status[NO_MEMORY_TYPES];
void start_memory(void) {
int i;
for (i=0; i<NO_MEMORY_TYPES; i++) {
alloc_status[i].first_in_memory = NULL;
alloc_status[i].last_in_memory = NULL;
alloc_status[i].objects_allocated = 0;
alloc_status[i].objects_count = 0;
alloc_status[i].bytes_allocated = 0;
alloc_status[i].no_allocated_together = 1;
alloc_status[i].name_of_type = "unused";
}
}
#line 142 "cBlorb/Chapter 1/Memory.w"
int no_blocks_allocated = 0;
int total_objects_allocated = 0; /* a much larger number, used only for the debugging log */
#line 156 "cBlorb/Chapter 1/Memory.w"
memblock_header *first_memblock_header = NULL; /* head of list of memory blocks */
memblock_header *current_memblock_header = NULL; /* tail of list of memory blocks */
int used_in_current_memblock = 0; /* number of bytes so far used in the tail memory block */
#line 166 "cBlorb/Chapter 1/Memory.w"
void allocate_another_block(void) {
unsigned char *cp;
memblock_header *mh;
{
#line 183 "cBlorb/Chapter 1/Memory.w"
int i;
if (no_blocks_allocated++ >= MAX_BLOCKS_ALLOWED)
fatal(
"the memory manager has halted cblorb, which seems to be generating "
"endless structures. Presumably it is trapped in a loop");
check_memory_integrity();
cp = (unsigned char *) (malloc(MEMORY_GRANULARITY));
if (cp == NULL) fatal("Run out of memory: malloc failed");
for (i=0; i<MEMORY_GRANULARITY; i++) cp[i] = 0;
}
#line 170 "cBlorb/Chapter 1/Memory.w"
;
mh = (memblock_header *) cp;
used_in_current_memblock = sizeof(memblock_header) + SAFETY_MARGIN;
mh->the_memory = (void *) (cp + used_in_current_memblock);
{
#line 197 "cBlorb/Chapter 1/Memory.w"
if (current_memblock_header == NULL) {
mh->block_number = 0;
first_memblock_header = mh;
} else {
mh->block_number = current_memblock_header->block_number + 1;
current_memblock_header->next = mh;
}
current_memblock_header = mh;
}
#line 176 "cBlorb/Chapter 1/Memory.w"
;
}
#line 211 "cBlorb/Chapter 1/Memory.w"
void free_memory(void) {
memblock_header *mh = first_memblock_header;
while (mh != NULL) {
memblock_header *next_mh = mh->next;
void *p = (void *) mh;
free(p);
mh = next_mh;
}
}
#line 237 "cBlorb/Chapter 1/Memory.w"
#line 243 "cBlorb/Chapter 1/Memory.w"
memory_frame *first_memory_frame = NULL; /* earliest memory frame ever allocated */
memory_frame *last_memory_frame = NULL; /* most recent memory frame allocated */
#line 254 "cBlorb/Chapter 1/Memory.w"
int calls_to_cmi = 0;
void check_memory_integrity(void) {
int c;
memory_frame *mf;
c = calls_to_cmi++;
if (!((c<10) || (c == 100) || (c == 1000) || (c == 10000))) return;
for (c = 0, mf = first_memory_frame; mf; c++, mf = mf->next_frame)
if (mf->integrity_check != INTEGRITY_NUMBER)
fatal("Memory manager failed integrity check");
}
void debug_memory_frames(int from, int to) {
int c;
memory_frame *mf;
for (c = 0, mf = first_memory_frame; (mf) && (c <= to); c++, mf = mf->next_frame)
if (c >= from) {
char *desc = "corrupt";
if (mf->integrity_check == INTEGRITY_NUMBER)
desc = alloc_status[mf->mem_type].name_of_type;
}
}
#line 283 "cBlorb/Chapter 1/Memory.w"
void *allocate_mem(int mem_type, int extent) {
unsigned char *cp;
memory_frame *mf;
int bytes_free_in_current_memblock, extent_without_overheads = extent;
extent += sizeof(memory_frame); /* each allocation is preceded by a memory frame */
extent += SAFETY_MARGIN; /* each allocation is followed by |SAFETY_MARGIN| null bytes */
{
#line 316 "cBlorb/Chapter 1/Memory.w"
if (current_memblock_header == NULL) allocate_another_block();
bytes_free_in_current_memblock = MEMORY_GRANULARITY - (used_in_current_memblock + extent);
if (bytes_free_in_current_memblock < BLANK_END_SIZE) {
allocate_another_block();
if (extent+BLANK_END_SIZE >= MEMORY_GRANULARITY)
fatal("Memory manager failed because granularity too low");
}
}
#line 291 "cBlorb/Chapter 1/Memory.w"
;
cp = ((unsigned char *) (current_memblock_header->the_memory)) + used_in_current_memblock;
used_in_current_memblock += extent;
mf = (memory_frame *) cp; /* the new memory frame, */
cp = cp + sizeof(memory_frame); /* following which is the actual allocated data */
mf->integrity_check = INTEGRITY_NUMBER;
mf->allocation_id = alloc_status[mem_type].objects_allocated;
mf->mem_type = mem_type;
{
#line 327 "cBlorb/Chapter 1/Memory.w"
mf->next_frame = NULL;
if (first_memory_frame == NULL) first_memory_frame = mf;
else last_memory_frame->next_frame = mf;
last_memory_frame = mf;
}
#line 303 "cBlorb/Chapter 1/Memory.w"
;
{
#line 335 "cBlorb/Chapter 1/Memory.w"
if (alloc_status[mem_type].first_in_memory == NULL)
alloc_status[mem_type].first_in_memory = (void *) cp;
alloc_status[mem_type].last_in_memory = (void *) cp;
alloc_status[mem_type].objects_allocated++;
alloc_status[mem_type].bytes_allocated += extent_without_overheads;
}
#line 304 "cBlorb/Chapter 1/Memory.w"
;
total_objects_allocated++;
return (void *) cp;
}
#line 480 "cBlorb/Chapter 1/Memory.w"
ALLOCATE_INDIVIDUALLY(auxiliary_file)
ALLOCATE_INDIVIDUALLY(skein_node)
ALLOCATE_INDIVIDUALLY(chunk_metadata)
ALLOCATE_INDIVIDUALLY(placeholder)
ALLOCATE_INDIVIDUALLY(heading)
ALLOCATE_INDIVIDUALLY(table)
ALLOCATE_INDIVIDUALLY(rdes_record)
ALLOCATE_INDIVIDUALLY(segment)
ALLOCATE_INDIVIDUALLY(request)
ALLOCATE_INDIVIDUALLY(template)
ALLOCATE_INDIVIDUALLY(template_path)
#line 498 "cBlorb/Chapter 1/Memory.w"
char cblorb_tolower(char c) {
return (char) tolower((int) c);
}
char cblorb_toupper(char c) {
return (char) toupper((int) c);
}
int cblorb_strlen(const char *p) {
return (int) strlen(p);
}
#line 28 "cBlorb/Chapter 1/Text Files.w"
void describe_file_position(char *t, text_file_position *tfp) {
*t = 0;
if (tfp == NULL) return;
sprintf(t, "%s, line %d: ", tfp->text_file_filename, tfp->line_count);
}
#line 37 "cBlorb/Chapter 1/Text Files.w"
int tfp_get_line_count(text_file_position *tfp) {
if (tfp == NULL) return 0;
return tfp->line_count;
}
#line 45 "cBlorb/Chapter 1/Text Files.w"
void tfp_lose_interest(text_file_position *tfp) {
tfp->actively_scanning = FALSE;
}
#line 57 "cBlorb/Chapter 1/Text Files.w"
text_file_position *error_position = NULL;
void set_error_position(text_file_position *tfp) {
error_position = tfp;
}
void error(char *erm) {
char err[MAX_FILENAME_LENGTH];
describe_file_position(err, error_position);
sprintf(err+cblorb_strlen(err), "Error: %s\n", erm);
spool_error(err);
}
void error_1(char *erm, char *s) {
char err[MAX_FILENAME_LENGTH];
describe_file_position(err, error_position);
sprintf(err+cblorb_strlen(err), "Error: %s: '%s'\n", erm, s);
spool_error(err);
}
void errorf_1s(char *erm, char *s1) {
char err[MAX_FILENAME_LENGTH];
sprintf(err, erm, s1);
spool_error(err);
}
void errorf_2s(char *erm, char *s1, char *s2) {
char err[MAX_FILENAME_LENGTH];
sprintf(err, erm, s1, s2);
spool_error(err);
}
void fatal(char *erm) {
char err[MAX_FILENAME_LENGTH];
describe_file_position(err, error_position);
sprintf(err+cblorb_strlen(err), "Fatal error: %s\n", erm);
spool_error(err);
print_report();
exit(1);
}
void fatal_fs(char *erm, char *fn) {
char err[MAX_FILENAME_LENGTH];
describe_file_position(err, error_position);
sprintf(err+cblorb_strlen(err), "Fatal error: %s: filename '%s'\n", erm, fn);
spool_error(err);
print_report();
exit(1);
}
void warning_fs(char *erm, char *fn) {
char err[MAX_FILENAME_LENGTH];
describe_file_position(err, error_position);
fprintf(stderr, "%sWarning: %s: filename '%s'\n", err, erm, fn);
}
#line 115 "cBlorb/Chapter 1/Text Files.w"
void spool_error(char *err) {
append_to_placeholder("CBLORBERRORS", "<li>");
append_to_placeholder("CBLORBERRORS", err);
append_to_placeholder("CBLORBERRORS", "</li>");
fprintf(stderr, "%s", err);
error_count++;
}
#line 129 "cBlorb/Chapter 1/Text Files.w"
void file_read(char *filename, char *message, int serious,
void (iterator)(char *, text_file_position *), text_file_position *start_at) {
FILE *HANDLE;
text_file_position tfp;
{
#line 142 "cBlorb/Chapter 1/Text Files.w"
if (cblorb_strlen(filename) >= MAX_FILENAME_LENGTH) {
if (serious) fatal_fs("filename too long", filename);
error_1("filename too long", filename);
return;
}
HANDLE = fopen(filename, "rb");
if (HANDLE == NULL) {
if (message == NULL) return;
if (serious) fatal_fs(message, filename);
else { error_1(message, filename); return; }
}
}
#line 133 "cBlorb/Chapter 1/Text Files.w"
;
{
#line 160 "cBlorb/Chapter 1/Text Files.w"
if (start_at == NULL) {
tfp.line_count = 1;
tfp.line_position = 0;
tfp.skip_terminator = 'X';
} else {
tfp = *start_at;
if (fseek(HANDLE, (long int) (tfp.line_position), SEEK_SET)) {
if (serious) fatal_fs("unable to seek position in file", filename);
error_1("unable to seek position in file", filename);
return;
}
}
tfp.actively_scanning = TRUE;
strcpy(tfp.text_file_filename, filename);
}
#line 134 "cBlorb/Chapter 1/Text Files.w"
;
{
#line 179 "cBlorb/Chapter 1/Text Files.w"
char line[MAX_TEXT_FILE_LINE_LENGTH+1];
int i = 0, c = ' ';
int warned = FALSE;
while ((c != EOF) && (tfp.actively_scanning)) {
c = fgetc(HANDLE);
if ((c == EOF) || (c == '\x0a') || (c == '\x0d')) {
line[i] = 0;
if ((i > 0) || (c != tfp.skip_terminator)) {
{
#line 211 "cBlorb/Chapter 1/Text Files.w"
iterator(line, &tfp);
tfp.line_count++;
}
#line 187 "cBlorb/Chapter 1/Text Files.w"
;
if (c == '\x0a') tfp.skip_terminator = '\x0d';
if (c == '\x0d') tfp.skip_terminator = '\x0a';
} else tfp.skip_terminator = 'X';
{
#line 225 "cBlorb/Chapter 1/Text Files.w"
tfp.line_position = (int) (ftell(HANDLE));
if (tfp.line_position == -1) {
if (serious) fatal_fs("unable to determine position in file", filename);
error_1("unable to determine position in file", filename);
}
}
#line 191 "cBlorb/Chapter 1/Text Files.w"
;
i = 0;
} else {
if (i < MAX_TEXT_FILE_LINE_LENGTH) line[i++] = (char) c;
else {
if (serious) fatal_fs("line too long", filename);
if (warned == FALSE) {
warning_fs("line too long (truncating it)", filename);
warned = TRUE;
}
}
}
}
if ((i > 0) && (tfp.actively_scanning))
{
#line 211 "cBlorb/Chapter 1/Text Files.w"
iterator(line, &tfp);
tfp.line_count++;
}
#line 205 "cBlorb/Chapter 1/Text Files.w"
;
}
#line 135 "cBlorb/Chapter 1/Text Files.w"
;
fclose(HANDLE);
}
#line 234 "cBlorb/Chapter 1/Text Files.w"
char *trim_white_space(char *original) {
int i;
for (i=0; white_space(original[i]); i++) ;
original += i;
for (i=cblorb_strlen(original)-1; ((i>=0) && (white_space(original[i]))); i--)
original[i] = 0;
return original;
}
#line 246 "cBlorb/Chapter 1/Text Files.w"
void extract_word(char *fword, char *line, int size, int word) {
int i = 0;
fword[0] = 0;
while (word > 0) {
word--;
while (white_space(line[i])) i++;
int j = 0;
while ((line[i]) && (!white_space(line[i]))) {
if (j < size-1) fword[j++] = cblorb_tolower(line[i]);
i++;
}
fword[j] = 0;
if (line[i] == 0) break;
}
if (word > 0) fword[0] = 0;
}
#line 266 "cBlorb/Chapter 1/Text Files.w"
int white_space(int c) { if ((c == ' ') || (c == '\t')) return TRUE; return FALSE; }
#line 279 "cBlorb/Chapter 1/Text Files.w"
char *get_filename_extension(char *filename) {
int i = cblorb_strlen(filename) - 1;
while ((i>=0) && ((filename[i] == '.') || (filename[i] == ' '))) i--;
while ((i>=0) && (filename[i] != '.') && (filename[i] != SEP_CHAR)) i--;
if ((i<0) || (filename[i] == SEP_CHAR)) return filename + cblorb_strlen(filename);
return filename + i;
}
#line 301 "cBlorb/Chapter 1/Text Files.w"
int infer_format_from_filename_extension(char *filename) {
char *p = get_filename_extension(filename);
if (p[0] == '.') p++;
char normalised[8];
int i;
for (i=0; (p[i]) && (p[i] != '.') && (p[i] != ' ') && (i<7); i++)
normalised[i] = cblorb_tolower(p[i]);
normalised[i] = 0;
if (strcmp(normalised, "html") == 0) return FORMAT_PERHAPS_HTML;
if (strcmp(normalised, "htm") == 0) return FORMAT_PERHAPS_HTML;
if (strcmp(normalised, "jpg") == 0) return FORMAT_PERHAPS_JPEG;
if (strcmp(normalised, "jpeg") == 0) return FORMAT_PERHAPS_JPEG;
if (strcmp(normalised, "png") == 0) return FORMAT_PERHAPS_PNG;
if (strcmp(normalised, "ogg") == 0) return FORMAT_PERHAPS_OGG;
if (strcmp(normalised, "aiff") == 0) return FORMAT_PERHAPS_AIFF;
if (strcmp(normalised, "aif") == 0) return FORMAT_PERHAPS_AIFF;
if (strcmp(normalised, "midi") == 0) return FORMAT_PERHAPS_MIDI;
if (strcmp(normalised, "mid") == 0) return FORMAT_PERHAPS_MIDI;
if (strcmp(normalised, "mod") == 0) return FORMAT_PERHAPS_MOD;
if ((normalised[0] == 'z') && (isdigit(normalised[1])) && (normalised[2] == 0))
return FORMAT_PERHAPS_ZCODE;
if ((normalised[0]) && (normalised[cblorb_strlen(normalised)-1] == 'x'))
return FORMAT_PERHAPS_GLULX;
return FORMAT_UNRECOGNISED;
}
#line 330 "cBlorb/Chapter 1/Text Files.w"
char *get_filename_leafname(char *filename) {
int i = cblorb_strlen(filename) - 1;
while ((i>=0) && (filename[i] != SEP_CHAR)) i--;
return filename + i + 1;
}
int file_exists(char *filename) {
FILE *TEST = fopen(filename, "r");
if (TEST) { fclose(TEST); return TRUE; }
return FALSE;
}
long int file_size(char *filename) {
FILE *TEST_FILE = fopen(filename, "rb");
if (TEST_FILE) {
if (fseek(TEST_FILE, 0, SEEK_END) == 0) {
long int file_size = ftell(TEST_FILE);
if (file_size == -1L) fatal_fs("ftell failed on linked file", filename);
fclose(TEST_FILE);
return file_size;
} else fatal_fs("fseek failed on linked file", filename);
fclose(TEST_FILE);
}
return -1L;
}
int copy_file(char *from, char *to, int suppress_error) {
if ((from == NULL) || (to == NULL) || (strcmp(from, to) == 0))
fatal("files confused in copier");
FILE *FROM = fopen(from, "rb");
if (FROM == NULL) {
if (suppress_error == FALSE) fatal_fs("unable to read file", from);
return -1;
}
FILE *TO = fopen(to, "wb");
if (TO == NULL) {
fatal_fs("unable to write to file", to);
return -1;
}
int size = 0;
while (TRUE) {
int c = fgetc(FROM);
if (c == EOF) break;
size++;
putc(c, TO);
}
fclose(FROM); fclose(TO);
return size;
}
#line 15 "cBlorb/Chapter 1/Blurb Parser.w"
void parse_blurb_file(char *in) {
file_read(in, "can't open blurb file", TRUE, interpret, 0);
set_error_position(NULL);
}
#line 113 "cBlorb/Chapter 1/Blurb Parser.w"
#line 124 "cBlorb/Chapter 1/Blurb Parser.w"
blurb_command syntaxes[] = {
{ "author \"name\"", "author \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ "auxiliary \"filename\" \"description\" \"subfolder\"",
"auxiliary \"%[^\"]\" \"%[^\"]\" \"%[^\"]\" %n", OPS_3TEXT, FALSE },
{ "base64 \"filename\" to \"filename\"",
"base64 \"%[^\"]\" to \"%[^\"]\" %n", OPS_2TEXT, FALSE },
{ "copyright \"message\"", "copyright \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ "cover \"filename\"", "cover \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ "css", "css %n", OPS_NO, FALSE },
{ "ifiction", "ifiction %n", OPS_NO, FALSE },
{ "ifiction public", "ifiction public %n", OPS_NO, FALSE },
{ "ifiction \"filename\" include", "ifiction \"%[^\"]\" include %n", OPS_1TEXT, FALSE },
{ "interpreter \"interpreter-name\" \"vm-letter\"",
"interpreter \"%[^\"]\" \"%[gz]\" %n", OPS_2TEXT, FALSE },
{ "palette { details }", "palette {%[^}]} %n", OPS_1TEXT, TRUE },
{ "palette 16 bit", "palette 16 bit %n", OPS_NO, TRUE },
{ "palette 32 bit", "palette 32 bit %n", OPS_NO, TRUE },
{ "picture ID \"filename\" scale ...",
"picture %20[A-Za-z0-9_] \"%[^\"]\" scale %s %n", OPS_3TEXT, TRUE },
{ "picture N \"filename\"", "picture %d \"%[^\"]\" %n", OPS_1NUMBER_1TEXT, FALSE },
{ "picture ID \"filename\"", "picture %20[A-Za-z0-9_] \"%[^\"]\" %n", OPS_2TEXT, FALSE },
{ "picture \"filename\"", "picture \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ "picture N \"filename\" \"alt-text\"", "picture %d \"%[^\"]\" \"%[^\"]\" %n", OPS_1NUMBER_2TEXTS, FALSE },
{ "placeholder [name] = \"text\"", "placeholder [%[A-Z]] = \"%[^\"]\" %n", OPS_2TEXT, FALSE },
{ "project folder \"pathname\"", "project folder \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ "release \"text\"", "release \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ "release file \"filename\"", "release file \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ "release file \"filename\" from \"template\"",
"release file \"%[^\"]\" from \"%[^\"]\" %n", OPS_2TEXT, FALSE },
{ "release source \"filename\" using \"filename\" from \"template\"",
"release source \"%[^\"]\" using \"%[^\"]\" from \"%[^\"]\" %n", OPS_3TEXT, FALSE },
{ "release to \"pathname\"", "release to \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ "resolution NxN max NxN", "resolution %d max %d %n", OPS_2NUMBER, TRUE },
{ "resolution NxN min NxN max NxN", "resolution %d min %d max %d %n", OPS_3NUMBER, TRUE },
{ "resolution NxN min NxN", "resolution %d min %d %n", OPS_2NUMBER, TRUE },
{ "resolution NxN", "resolution %d %n", OPS_1NUMBER, TRUE },
{ "solution", "solution %n", OPS_NO, FALSE },
{ "solution public", "solution public %n", OPS_NO, FALSE },
{ "sound ID \"filename\" music", "sound %20[A-Za-z0-9_] \"%[^\"]\" music %n", OPS_2TEXT, TRUE },
{ "sound ID \"filename\" repeat N",
"sound %20[A-Za-z0-9_] \"%[^\"]\" repeat %d %n", OPS_2TEXT_1NUMBER, TRUE },
{ "sound ID \"filename\" repeat forever",
"sound %20[A-Za-z0-9_] \"%[^\"]\" repeat forever %n", OPS_2TEXT, TRUE },
{ "sound ID \"filename\" song", "sound %20[A-Za-z0-9_] \"%[^\"]\" song %n", OPS_2TEXT, TRUE },
{ "sound N \"filename\"", "sound %d \"%[^\"]\" %n", OPS_1NUMBER_1TEXT, FALSE },
{ "sound ID \"filename\"", "sound %20[A-Za-z0-9_] \"%[^\"]\" %n", OPS_2TEXT, FALSE },
{ "sound \"filename\"", "sound \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ "sound N \"filename\" \"alt-text\"", "sound %d \"%[^\"]\" \"%[^\"]\" %n", OPS_1NUMBER_2TEXTS, FALSE },
{ "source", "source %n", OPS_NO, FALSE },
{ "source public", "source public %n", OPS_NO, FALSE },
{ "status \"template\" \"filename\"", "status \"%[^\"]\" \"%[^\"]\" %n", OPS_2TEXT, FALSE },
{ "status alternative ||link to Inform documentation||",
"status alternative ||%[^|]|| %n", OPS_1TEXT, FALSE },
{ "status instruction ||link to Inform source text||",
"status instruction ||%[^|]|| %n", OPS_1TEXT, FALSE },
{ "storyfile \"filename\" include", "storyfile \"%[^\"]\" include %n", OPS_1TEXT, FALSE },
{ "storyfile \"filename\"", "storyfile \"%[^\"]\" %n", OPS_1TEXT, TRUE },
{ "storyfile leafname \"leafname\"", "storyfile leafname \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ "template path \"folder\"", "template path \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ "website \"template\"", "website \"%[^\"]\" %n", OPS_1TEXT, FALSE },
{ NULL, NULL, OPS_NO, FALSE }
};
#line 191 "cBlorb/Chapter 1/Blurb Parser.w"
void summarise_blurb(void) {
int t;
printf("\nThe blurbfile is a script of commands, one per line, in these forms:\n");
for (t=0; syntaxes[t].prototype; t++)
if (syntaxes[t].deprecated == FALSE)
printf(" %s\n", syntaxes[t].explicated);
printf("\nThe following syntaxes, though legal in Blorb 2001, are not supported:\n");
for (t=0; syntaxes[t].prototype; t++)
if (syntaxes[t].deprecated == TRUE)
printf(" %s\n", syntaxes[t].explicated);
}
#line 208 "cBlorb/Chapter 1/Blurb Parser.w"
void interpret(char *command, text_file_position *tf) {
set_error_position(tf);
if (command == NULL) fatal("null blurb line");
command = trim_white_space(command);
if (command[0] == 0) return; /* thus skip a line containing only blank space */
if (command[0] == '!') return; /* thus skip a comment line */
if (trace_mode) fprintf(stdout, "! %03d: %s\n", tfp_get_line_count(tf), command);
int outcome = -1; /* which of the legal command syntaxes is used */
char text1[MAX_TEXT_FILE_LINE_LENGTH], text2[MAX_TEXT_FILE_LINE_LENGTH],
text3[MAX_TEXT_FILE_LINE_LENGTH];
text1[0] = 0; text2[0] = 0; text3[0] = 0;
int num1 = 0, num2 = 0, num3 = 0;
{
#line 232 "cBlorb/Chapter 1/Blurb Parser.w"
int t;
for (t=0; syntaxes[t].prototype; t++) {
char *pr = syntaxes[t].prototype;
int nm = -1; /* number of characters matched */
switch (syntaxes[t].operands) {
case OPS_NO: sscanf(command, pr, &nm); break;
case OPS_1TEXT: sscanf(command, pr, text1, &nm); break;
case OPS_2TEXT: sscanf(command, pr, text1, text2, &nm); break;
case OPS_2TEXT_1NUMBER: sscanf(command, pr, text1, text2, &num1, &nm); break;
case OPS_1NUMBER: sscanf(command, pr, &num1, &nm); break;
case OPS_2NUMBER: sscanf(command, pr, &num1, &num2, &nm); break;
case OPS_1NUMBER_1TEXT: sscanf(command, pr, &num1, text1, &nm); break;
case OPS_1NUMBER_2TEXTS: sscanf(command, pr, &num1, text1, text2, &nm); break;
case OPS_1NUMBER_1TEXT_1NUMBER: sscanf(command, pr, &num1, text1, &num2, &nm); break;
case OPS_3NUMBER: sscanf(command, pr, &num1, &num2, &num3, &nm); break;
case OPS_3TEXT: sscanf(command, pr, text1, text2, text3, &nm); break;
default: fatal("unknown operand type");
}
if (nm == cblorb_strlen(command)) { outcome = t; break; }
}
if ((cblorb_strlen(text1) >= MAX_FILENAME_LENGTH-1) ||
(cblorb_strlen(text2) >= MAX_FILENAME_LENGTH-1) ||
(cblorb_strlen(text3) >= MAX_FILENAME_LENGTH-1)) {
error("string too long"); return;
}
if (outcome == -1) {
error_1("not a valid blurb command", command);
return;
}
if (syntaxes[outcome].deprecated) {
error_1("this Blurb syntax is no longer supported", syntaxes[outcome].explicated);
return;
}
}
#line 223 "cBlorb/Chapter 1/Blurb Parser.w"
;
{
#line 271 "cBlorb/Chapter 1/Blurb Parser.w"
switch (outcome) {
case author_COMMAND:
set_placeholder_to("AUTHOR", text1, 0);
author_chunk(text1);
break;
case auxiliary_COMMAND: create_auxiliary_file(text1, text2, text3); break;
case base64_COMMAND:
request_2(BASE64_REQ, text1, text2, FALSE); break;
case copyright_COMMAND: copyright_chunk(text1); break;
case cover_COMMAND:
{
#line 331 "cBlorb/Chapter 1/Blurb Parser.w"
set_placeholder_to("BIGCOVER", text1, 0);
cover_exists = TRUE;
cover_is_in_JPEG_format = TRUE;
if ((text1[cblorb_strlen(text1)-3] == 'p') || (text1[cblorb_strlen(text1)-3] == 'P'))
cover_is_in_JPEG_format = FALSE;
frontispiece_chunk(1);
char *leaf = get_filename_leafname(text1);
if (strcmp(leaf, "DefaultCover.jpg") == 0) default_cover_used = TRUE;
if (cover_is_in_JPEG_format) strcpy(leaf, "Small Cover.jpg");
else strcpy(leaf, "Small Cover.png");
set_placeholder_to("SMALLCOVER", text1, 0);
}
#line 280 "cBlorb/Chapter 1/Blurb Parser.w"
; break;
case css_COMMAND: use_css_code_styles = TRUE; break;
case ifiction_file_COMMAND: metadata_chunk(text1); break;
case ifiction_COMMAND: request_1(IFICTION_REQ, "", TRUE); break;
case ifiction_public_COMMAND: request_1(IFICTION_REQ, "", FALSE); break;
case interpreter_COMMAND:
set_placeholder_to("INTERPRETERVMIS", text2, 0);
request_1(INTERPRETER_REQ, text1, FALSE); break;
case picture_COMMAND: picture_chunk(num1, text1, ""); break;
case picture_text_COMMAND: picture_chunk_text(text1, text2); break;
case picture_noid_COMMAND: picture_chunk_text("", text1); break;
case picture_with_alt_text_COMMAND: picture_chunk(num1, text1, text2); break;
case placeholder_COMMAND: set_placeholder_to(text1, text2, 0); break;
case project_folder_COMMAND: strcpy(project_folder, text1); break;
case release_COMMAND:
set_placeholder_to_number("RELEASE", num1);
release_chunk(num1);
break;
case release_file_COMMAND:
request_3(COPY_REQ, text1, get_filename_leafname(text1), "--", FALSE); break;
case release_file_from_COMMAND:
request_2(RELEASE_FILE_REQ, text1, text2, FALSE); break;
case release_to_COMMAND:
strcpy(release_folder, text1);
{
#line 355 "cBlorb/Chapter 1/Blurb Parser.w"
set_placeholder_to("MATERIALSFOLDERPATH", text1, 0);
int k = cblorb_strlen(text1);
while ((k>=0) && (text1[k] != SEP_CHAR)) k--;
if (k>0) { *(read_placeholder("MATERIALSFOLDERPATH")+k)=0; k--; }
while ((k>=0) && (text1[k] != SEP_CHAR)) k--; k++;
set_placeholder_to("MATERIALSFOLDER", text1 + k, 0);
char *L = read_placeholder("MATERIALSFOLDER");
while (*L) { if (*L == SEP_CHAR) *L = 0; L++; }
qualify_placeholder("MATERIALSFOLDERPATHOPEN", "MATERIALSFOLDERPATHFILE",
"MATERIALSFOLDERPATH");
}
#line 304 "cBlorb/Chapter 1/Blurb Parser.w"
;
break;
case release_source_COMMAND:
request_3(RELEASE_SOURCE_REQ, text1, text2, text3, FALSE); break;
case solution_COMMAND: request_1(SOLUTION_REQ, "", TRUE); break;
case solution_public_COMMAND: request_1(SOLUTION_REQ, "", FALSE); break;
case sound_COMMAND: sound_chunk(num1, text1, ""); break;
case sound_text_COMMAND: sound_chunk_text(text1, text2); break;
case sound_noid_COMMAND: sound_chunk_text("", text1); break;
case sound_with_alt_text_COMMAND: sound_chunk(num1, text1, text2); break;
case source_COMMAND: request_1(SOURCE_REQ, "", TRUE); break;
case source_public_COMMAND: request_1(SOURCE_REQ, "", FALSE); break;
case status_COMMAND: strcpy(status_template, text1); strcpy(status_file, text2); break;
case status_alternative_COMMAND: request_1(ALTERNATIVE_REQ, text1, FALSE); break;
case status_instruction_COMMAND: request_1(INSTRUCTION_REQ, text1, FALSE); break;
case storyfile_include_COMMAND: executable_chunk(text1); break;
case storyfile_leafname_COMMAND: set_placeholder_to("STORYFILE", text1, 0); break;
case template_path_COMMAND: new_template_path(text1); break;
case website_COMMAND: request_1(WEBSITE_REQ, text1, FALSE); break;
default: error_1("***", command); fatal("*** command unimplemented ***\n");
}
}
#line 224 "cBlorb/Chapter 1/Blurb Parser.w"
;
}
#line 374 "cBlorb/Chapter 1/Blurb Parser.w"
void qualify_placeholder(char *openUrl_path, char *fileUrl_path, char *original) {
int i;
char *p = read_placeholder(original);
for (i=0; p[i]; i++) {
char oU_glyph[8], fU_glyph[8];
sprintf(oU_glyph, "%c", p[i]); sprintf(fU_glyph, "%c", p[i]);
if (p[i] == ' ') {
if (escape_openUrl) sprintf(oU_glyph, "%%2520");
if (escape_fileUrl) sprintf(fU_glyph, "%%2520");
}
if (p[i] == '\\') {
if (reverse_slash_openUrl) sprintf(oU_glyph, "/");
if (reverse_slash_fileUrl) sprintf(fU_glyph, "/");
}
append_to_placeholder(openUrl_path, oU_glyph);
append_to_placeholder(fileUrl_path, fU_glyph);
}
}
#line 88 "cBlorb/Chapter 2/Blorb Writer.w"
void four_word(FILE *F, int n) {
fputc((n / 0x1000000)%0x100, F);
fputc((n / 0x10000)%0x100, F);
fputc((n / 0x100)%0x100, F);
fputc((n)%0x100, F);
}
void two_word(FILE *F, int n) {
fputc((n / 0x100)%0x100, F);
fputc((n)%0x100, F);
}
void one_byte(FILE *F, int n) {
fputc((n)%0x100, F);
}
void s_four_word(unsigned char *F, int n) {
F[0] = (unsigned char) (n / 0x1000000)%0x100;
F[1] = (unsigned char) (n / 0x10000)%0x100;
F[2] = (unsigned char) (n / 0x100)%0x100;
F[3] = (unsigned char) (n)%0x100;
}
void s_two_word(unsigned char *F, int n) {
F[0] = (unsigned char) (n / 0x100)%0x100;
F[1] = (unsigned char) (n)%0x100;
}
void s_one_byte(unsigned char *F, int n) {
F[0] = (unsigned char) (n)%0x100;
}
#line 127 "cBlorb/Chapter 2/Blorb Writer.w"
chunk_metadata *current_chunk = NULL;
#line 135 "cBlorb/Chapter 2/Blorb Writer.w"
void add_chunk_to_blorb(char *id, int resource_num, char *supplied_filename, char *index,
unsigned char *data, int length) {
if (chunk_type_is_legal(id) == FALSE)
fatal("tried to complete non-Blorb chunk");
if (index_entry_is_legal(index) == FALSE)
fatal("tried to include mis-indexed chunk");
current_chunk = CREATE(chunk_metadata);
{
#line 163 "cBlorb/Chapter 2/Blorb Writer.w"
if (data) {
strcpy(current_chunk->filename, "(not from a file)");
current_chunk->length_of_data_in_memory = length;
int i;
for (i=0; i<length; i++) current_chunk->data_in_memory[i] = data[i];
} else {
strcpy(current_chunk->filename, supplied_filename);
current_chunk->length_of_data_in_memory = -1;
}
}
#line 144 "cBlorb/Chapter 2/Blorb Writer.w"
;
current_chunk->chunk_type = id;
current_chunk->index_entry = index;
if (current_chunk->index_entry) no_indexed_chunks++;
current_chunk->byte_offset = total_size_of_Blorb_chunks;
current_chunk->resource_id = resource_num;
{
#line 176 "cBlorb/Chapter 2/Blorb Writer.w"
int size;
if (data) {
size = length;
} else {
size = (int) file_size(supplied_filename);
}
if (chunk_type_is_already_an_IFF(current_chunk->chunk_type) == FALSE)
size += 8; /* allow 8 further bytes for the chunk header to be added later */
current_chunk->size = size;
}
#line 152 "cBlorb/Chapter 2/Blorb Writer.w"
;
{
#line 192 "cBlorb/Chapter 2/Blorb Writer.w"
total_size_of_Blorb_chunks += current_chunk->size;
if ((current_chunk->size) % 2 == 1) total_size_of_Blorb_chunks++;
}
#line 153 "cBlorb/Chapter 2/Blorb Writer.w"
;
if (trace_mode)
printf("! Begun chunk %s: fn is <%s> (innate size %d)\n",
current_chunk->chunk_type, current_chunk->filename, current_chunk->size);
}
#line 205 "cBlorb/Chapter 2/Blorb Writer.w"
char *legal_Blorb_chunk_types[] = {
"AUTH", "(c) ", "Fspc", "RelN", "IFmd", /* miscellaneous identifying data */
"JPEG", "PNG ", /* images in different formats */
"AIFF", "OGGV", "MIDI", "MOD ", /* sound effects in different formats */
"ZCOD", "GLUL", /* story files in different formats */
"RDes", /* resource descriptions (added to the standard in March 2014) */
NULL };
char *legal_Blorb_index_entries[] = {
"Pict", "Snd ", "Exec", NULL };
#line 219 "cBlorb/Chapter 2/Blorb Writer.w"
int chunk_type_is_legal(char *type) {
int i;
if (type == NULL) return FALSE;
for (i=0; legal_Blorb_chunk_types[i]; i++)
if (strcmp(type, legal_Blorb_chunk_types[i]) == 0)
return TRUE;
return FALSE;
}
int index_entry_is_legal(char *entry) {
int i;
if (entry == NULL) return TRUE;
for (i=0; legal_Blorb_index_entries[i]; i++)
if (strcmp(entry, legal_Blorb_index_entries[i]) == 0)
return TRUE;
return FALSE;
}
#line 243 "cBlorb/Chapter 2/Blorb Writer.w"
int resource_seen(resource_list **list, int value) {
resource_list *p;
for(p = *list; p; p = p->n) {
if (p->num == value) return TRUE;
}
p = *list;
*list = malloc(sizeof(resource_list));
if (*list == NULL)
fatal("Run out of memory: malloc failed");
(*list)->num = value;
(*list)->n = p;
return FALSE;
}
#line 262 "cBlorb/Chapter 2/Blorb Writer.w"
int chunk_type_is_already_an_IFF(char *type) {
if (strcmp(type, "AIFF")==0) return TRUE;
return FALSE;
}
#line 270 "cBlorb/Chapter 2/Blorb Writer.w"
void author_chunk(char *t) {
if (trace_mode) printf("! Author: <%s>\n", t);
add_chunk_to_blorb("AUTH", 0, NULL, NULL, (unsigned char *) t, cblorb_strlen(t));
}
#line 278 "cBlorb/Chapter 2/Blorb Writer.w"
void copyright_chunk(char *t) {
if (trace_mode) printf("! Copyright declaration: <%s>\n", t);
add_chunk_to_blorb("(c) ", 0, NULL, NULL, (unsigned char *) t, cblorb_strlen(t));
}
#line 287 "cBlorb/Chapter 2/Blorb Writer.w"
void frontispiece_chunk(int pn) {
if (trace_mode) printf("! Frontispiece is image %d\n", pn);
unsigned char data[4];
s_four_word(data, pn);
add_chunk_to_blorb("Fspc", 0, NULL, NULL, data, 4);
}
#line 297 "cBlorb/Chapter 2/Blorb Writer.w"
void release_chunk(int rn) {
if (trace_mode) printf("! Release number is %d\n", rn);
unsigned char data[2];
s_two_word(data, rn);
add_chunk_to_blorb("RelN", 0, NULL, NULL, data, 2);
}
#line 309 "cBlorb/Chapter 2/Blorb Writer.w"
void picture_chunk(int n, char *fn, char *alt) {
char *type = "PNG ";
int form = infer_format_from_filename_extension(fn);
if (form == FORMAT_PERHAPS_JPEG) type = "JPEG";
else if (form == FORMAT_PERHAPS_PNG) type = "PNG ";
else error_1("image file has unknown file extension "
"(expected e.g. '.png' for PNG, '.jpeg' for JPEG)", fn);
if (n < 1) fatal("Picture resource number is less than 1");
if (resource_seen(&pict_resource, n)) fatal("Duplicate Picture resource number");
add_chunk_to_blorb(type, n, fn, "Pict", NULL, 0);
if ((alt) && (alt[0])) add_rdes_record(1, n, alt);
no_pictures_included++;
}
#line 337 "cBlorb/Chapter 2/Blorb Writer.w"
void picture_chunk_text(char *name, char *fn) {
if (name[0] == 0) {
printf("! Null picture ID, using %d\n", picture_resource_num);
} else {
printf("Constant PICTURE_%s = %d;\n", name, picture_resource_num);
}
picture_resource_num++;
picture_chunk(picture_resource_num, fn, "");
}
#line 355 "cBlorb/Chapter 2/Blorb Writer.w"
void sound_chunk(int n, char *fn, char *alt) {
char *type = "AIFF";
int form = infer_format_from_filename_extension(fn);
if (form == FORMAT_PERHAPS_OGG) type = "OGGV";
else if (form == FORMAT_PERHAPS_MIDI) type = "MIDI";
else if (form == FORMAT_PERHAPS_MOD) type = "MOD ";
else if (form == FORMAT_PERHAPS_AIFF) type = "AIFF";
else error_1("sound file has unknown file extension "
"(expected e.g. '.ogg', '.midi', '.mod' or '.aiff', as appropriate)", fn);
if (n < 3) fatal("Sound resource number is less than 3");
if (resource_seen(&sound_resource, n)) fatal("Duplicate Sound resource number");
add_chunk_to_blorb(type, n, fn, "Snd ", NULL, 0);
if ((alt) && (alt[0])) add_rdes_record(2, n, alt);
no_sounds_included++;
}
#line 376 "cBlorb/Chapter 2/Blorb Writer.w"
void sound_chunk_text(char *name, char *fn) {
if (name[0] == 0) {
printf("! Null sound ID, using %d\n", sound_resource_num);
} else {
printf("Constant SOUND_%s = %d;\n", name, sound_resource_num);
}
sound_resource_num++;
sound_chunk(sound_resource_num, fn, "");
}
#line 390 "cBlorb/Chapter 2/Blorb Writer.w"
size_t size_of_rdes_chunk = 0;
void add_rdes_record(int usage, int n, char *alt) {
size_t S = strlen(alt);
char *p = malloc(S+1);
if (p == NULL) fatal("Run out of memory: malloc failed");
strcpy(p, alt);
rdes_record *rr = CREATE(rdes_record);
rr->usage = usage;
rr->resource_id = n;
rr->description = p;
size_of_rdes_chunk += 12 + S;
}
void rdes_chunk(void) {
if (size_of_rdes_chunk > 0) {
unsigned char *rdes_data = (unsigned char *) malloc(size_of_rdes_chunk + 9);
if (rdes_data == NULL) fatal("Run out of memory: malloc failed");
size_t pos = 4;
s_four_word(rdes_data, NUMBER_CREATED(rdes_record));
rdes_record *rr;
LOOP_OVER(rr, rdes_record) {
if (rr->usage == 1) strcpy((char *) (rdes_data + pos), "Pict");
else if (rr->usage == 2) strcpy((char *) (rdes_data + pos), "Snd ");
else s_four_word(rdes_data + pos, 0);
s_four_word(rdes_data + pos + 4, rr->resource_id);
s_four_word(rdes_data + pos + 8, cblorb_strlen(rr->description));
strcpy((char *) (rdes_data + pos + 12), rr->description);
pos += 12 + strlen(rr->description);
}
if (pos != size_of_rdes_chunk + 4) fatal("misconstructed rdes");
add_chunk_to_blorb("RDes", 0, NULL, NULL, rdes_data, (int) pos);
}
}
#line 430 "cBlorb/Chapter 2/Blorb Writer.w"
void executable_chunk(char *fn) {
char *type = "ZCOD";
int form = infer_format_from_filename_extension(fn);
if (form == FORMAT_PERHAPS_GLULX) type = "GLUL";
else if (form == FORMAT_PERHAPS_ZCODE) type = "ZCOD";
else error_1("story file has unknown file extension "
"(expected e.g. '.z5' for Z-code, '.ulx' for Glulx)", fn);
add_chunk_to_blorb(type, 0, fn, "Exec", NULL, 0);
}
#line 446 "cBlorb/Chapter 2/Blorb Writer.w"
void metadata_chunk(char *fn) {
add_chunk_to_blorb("IFmd", 0, fn, NULL, NULL, 0);
}
#line 453 "cBlorb/Chapter 2/Blorb Writer.w"
void write_blorb_file(char *out) {
rdes_chunk();
if (NUMBER_CREATED(chunk_metadata) == 0) return;
FILE *IFF = fopen(out, "wb");
if (IFF == NULL) fatal_fs("can't open blorb file for output", out);
int RIdx_size, first_byte_after_index;
{
#line 484 "cBlorb/Chapter 2/Blorb Writer.w"
int FORM_header_size = 12;
int RIdx_header_size = 12;
int index_entry_size = 12;
RIdx_size = RIdx_header_size + index_entry_size*no_indexed_chunks;
first_byte_after_index = FORM_header_size + RIdx_size;
blorb_file_size = first_byte_after_index + total_size_of_Blorb_chunks;
}
#line 461 "cBlorb/Chapter 2/Blorb Writer.w"
;
{
#line 499 "cBlorb/Chapter 2/Blorb Writer.w"
fprintf(IFF, "FORM");
four_word(IFF, blorb_file_size - 8); /* offset to end of |FORM| after the 8 bytes so far */
fprintf(IFF, "IFRS"); /* magic text identifying the IFF as a Blorb */
fprintf(IFF, "RIdx");
four_word(IFF, RIdx_size - 8); /* offset to end of |RIdx| after the 8 bytes so far */
four_word(IFF, no_indexed_chunks); /* i.e., number of entries in the index */
chunk_metadata *chunk;
LOOP_OVER(chunk, chunk_metadata)
if (chunk->index_entry) {
fprintf(IFF, "%s", chunk->index_entry);
four_word(IFF, chunk->resource_id);
four_word(IFF, first_byte_after_index + chunk->byte_offset);
}
}
#line 462 "cBlorb/Chapter 2/Blorb Writer.w"
;
if (trace_mode)
{
#line 564 "cBlorb/Chapter 2/Blorb Writer.w"
printf("! Chunk table:\n");
chunk_metadata *chunk;
LOOP_OVER(chunk, chunk_metadata)
printf("! Chunk %s %06x %s %d <%s>\n",
chunk->chunk_type, chunk->size,
(chunk->index_entry)?(chunk->index_entry):"unindexed",
chunk->resource_id,
chunk->filename);
printf("! End of chunk table\n");
}
#line 463 "cBlorb/Chapter 2/Blorb Writer.w"
;
chunk_metadata *chunk;
LOOP_OVER(chunk, chunk_metadata)
{
#line 520 "cBlorb/Chapter 2/Blorb Writer.w"
int bytes_to_copy;
char *type = chunk->chunk_type;
if (chunk_type_is_already_an_IFF(type) == FALSE) {
fprintf(IFF, "%s", type);
four_word(IFF, chunk->size - 8); /* offset to end of chunk after the 8 bytes so far */
bytes_to_copy = chunk->size - 8; /* since here the chunk size included 8 extra */
} else {
bytes_to_copy = chunk->size; /* whereas here the chunk size was genuinely the file size */
}
if (chunk->length_of_data_in_memory >= 0)
{
#line 555 "cBlorb/Chapter 2/Blorb Writer.w"
int i;
for (i=0; i<bytes_to_copy; i++) {
int j = (int) (chunk->data_in_memory[i]);
one_byte(IFF, j);
}
}
#line 531 "cBlorb/Chapter 2/Blorb Writer.w"
else
{
#line 540 "cBlorb/Chapter 2/Blorb Writer.w"
FILE *CHUNKSUB = fopen(chunk->filename, "rb");
if (CHUNKSUB == NULL) fatal_fs("unable to read data", chunk->filename);
else {
int i;
for (i=0; i<bytes_to_copy; i++) {
int j = fgetc(CHUNKSUB);
if (j == EOF) fatal_fs("chunk ran out incomplete", chunk->filename);
one_byte(IFF, j);
}
fclose(CHUNKSUB);
}
}
#line 533 "cBlorb/Chapter 2/Blorb Writer.w"
;
if ((bytes_to_copy % 2) == 1) one_byte(IFF, 0); /* as we allowed for above */
}
#line 466 "cBlorb/Chapter 2/Blorb Writer.w"
;
fclose(IFF);
}
#line 51 "cBlorb/Chapter 3/Releaser.w"
request *request_0(int kind, int privacy) {
request *req = CREATE(request);
req->what_is_requested = kind;
req->details1[0] = 0;
req->details2[0] = 0;
req->details3[0] = 0;
req->private = privacy;
req->outcome_data = 0;
if (kind == WEBSITE_REQ) website_requested = TRUE;
return req;
}
request *request_1(int kind, char *text1, int privacy) {
request *req = request_0(kind, privacy);
strcpy(req->details1, text1);
return req;
}
request *request_2(int kind, char *text1, char *text2, int privacy) {
request *req = request_0(kind, privacy);
strcpy(req->details1, text1);
strcpy(req->details2, text2);
return req;
}
request *request_3(int kind, char *text1, char *text2, char *text3, int privacy) {
request *req = request_0(kind, privacy);
strcpy(req->details1, text1);
strcpy(req->details2, text2);
strcpy(req->details3, text3);
return req;
}
#line 87 "cBlorb/Chapter 3/Releaser.w"
void request_copy(char *from, char *to, char *subfolder) {
request_3(COPY_REQ, from, to, subfolder, FALSE);
}
#line 97 "cBlorb/Chapter 3/Releaser.w"
void any_last_requests(void) {
request_copy_of_auxiliaries();
if (default_cover_used == FALSE) {
char *BIGCOVER = read_placeholder("BIGCOVER");
if (BIGCOVER) {
if (cover_is_in_JPEG_format) request_copy(BIGCOVER, "Cover.jpg", "--");
else request_copy(BIGCOVER, "Cover.png", "--");
}
if (website_requested) {
char *SMALLCOVER = read_placeholder("SMALLCOVER");
if (SMALLCOVER) {
if (cover_is_in_JPEG_format) request_copy(SMALLCOVER, "Small Cover.jpg", "--");
else request_copy(SMALLCOVER, "Small Cover.png", "--");
}
}
}
}
#line 118 "cBlorb/Chapter 3/Releaser.w"
void create_requested_material(void) {
if (release_folder[0] == 0) return;
printf("! Release folder: <%s>\n", release_folder);
if (blorb_file_size > 0) declare_where_blorb_should_be_copied(release_folder);
any_last_requests();
request *req;
LOOP_OVER(req, request) {
switch (req->what_is_requested) {
case ALTERNATIVE_REQ: break;
case BASE64_REQ:
{
#line 194 "cBlorb/Chapter 3/Releaser.w"
encode_as_base64(req->details1, req->details2,
read_placeholder("BASESIXTYFOURTOP"), read_placeholder("BASESIXTYFOURTAIL"));
}
#line 127 "cBlorb/Chapter 3/Releaser.w"
; break;
case COPY_REQ:
{
#line 172 "cBlorb/Chapter 3/Releaser.w"
char write_to[MAX_FILENAME_LENGTH];
if (strcmp(req->details3, "--") == 0) {
sprintf(write_to, "%s%c%s", release_folder, SEP_CHAR, req->details2);
} else {
sprintf(write_to, "%s%c%s%c%s", release_folder, SEP_CHAR, req->details3,
SEP_CHAR, req->details2);
}
int size = copy_file(req->details1, write_to, TRUE);
req->outcome_data = size;
if (size == -1) {
int i;
for (i = cblorb_strlen(req->details1); i>0; i--)
if ((req->details1)[i] == SEP_CHAR) { i++; break; }
errorf_1s(
"You asked to release along with a file called '%s', which ought "
"to be in the Materials folder for the project. But I can't find "
"it there.", (req->details1)+i);
}
}
#line 128 "cBlorb/Chapter 3/Releaser.w"
; break;
case IFICTION_REQ:
{
#line 163 "cBlorb/Chapter 3/Releaser.w"
char iFiction_filename[MAX_FILENAME_LENGTH];
sprintf(iFiction_filename, "%s%cMetadata.iFiction", project_folder, SEP_CHAR);
char write_to[MAX_FILENAME_LENGTH];
sprintf(write_to, "%s%ciFiction.xml", release_folder, SEP_CHAR);
copy_file(iFiction_filename, write_to, FALSE);
}
#line 129 "cBlorb/Chapter 3/Releaser.w"
; break;
case INSTRUCTION_REQ: break;
case INTERPRETER_REQ:
{
#line 221 "cBlorb/Chapter 3/Releaser.w"
set_placeholder_to("INTERPRETER", req->details1, 0);
char *t = read_placeholder("INTERPRETER");
char *from = find_file_in_named_template(t, "(manifest).txt");
if (from) { /* i.e., if the "(manifest).txt" file exists */
file_read(from, "can't open (manifest) file", FALSE, read_requested_ifile, 0);
}
}
#line 131 "cBlorb/Chapter 3/Releaser.w"
; break;
case RELEASE_FILE_REQ:
{
#line 200 "cBlorb/Chapter 3/Releaser.w"
release_file_into_website(req->details1, req->details2, NULL);
}
#line 132 "cBlorb/Chapter 3/Releaser.w"
; break;
case RELEASE_SOURCE_REQ:
{
#line 205 "cBlorb/Chapter 3/Releaser.w"
set_placeholder_to("SOURCEPREFIX", "source", 0);
set_placeholder_to("SOURCELOCATION", req->details1, 0);
set_placeholder_to("TEMPLATE", req->details3, 0);
char *HTML_template = find_file_in_named_template(req->details3, req->details2);
if (HTML_template == NULL) error_1("can't find HTML template file", req->details2);
if (trace_mode) printf("! Web page %s from template %s\n", HTML_template, req->details3);
web_copy_source(HTML_template, release_folder);
}
#line 133 "cBlorb/Chapter 3/Releaser.w"
; break;
case SOLUTION_REQ:
{
#line 144 "cBlorb/Chapter 3/Releaser.w"
char Skein_filename[MAX_FILENAME_LENGTH];
sprintf(Skein_filename, "%s%cSkein.skein", project_folder, SEP_CHAR);
char solution_filename[MAX_FILENAME_LENGTH];
sprintf(solution_filename, "%s%csolution.txt", release_folder, SEP_CHAR);
walkthrough(Skein_filename, solution_filename);
}
#line 134 "cBlorb/Chapter 3/Releaser.w"
; break;
case SOURCE_REQ:
{
#line 153 "cBlorb/Chapter 3/Releaser.w"
char source_text_filename[MAX_FILENAME_LENGTH];
sprintf(source_text_filename, "%s%cSource%cstory.ni",
project_folder, SEP_CHAR, SEP_CHAR);
char write_to[MAX_FILENAME_LENGTH];
sprintf(write_to, "%s%csource.txt", release_folder, SEP_CHAR);
copy_file(source_text_filename, write_to, FALSE);
}
#line 135 "cBlorb/Chapter 3/Releaser.w"
; break;
case WEBSITE_REQ:
{
#line 233 "cBlorb/Chapter 3/Releaser.w"
set_placeholder_to("TEMPLATE", req->details1, 0);
char *t = read_placeholder("TEMPLATE");
if (use_css_code_styles) {
char *from = find_file_in_named_template(t, "style.css");
if (from) {
char CSS_filename[MAX_FILENAME_LENGTH];
sprintf(CSS_filename, "%s%cstyle.css", release_folder, SEP_CHAR);
copy_file(from, CSS_filename, FALSE);
}
}
release_file_into_website("index.html", t, NULL);
request *req;
LOOP_OVER(req, request)
if (req->private == FALSE)
switch (req->what_is_requested) {
case INTERPRETER_REQ:
release_file_into_website("play.html", t, NULL); break;
case SOURCE_REQ:
set_placeholder_to("SOURCEPREFIX", "source", 0);
char source_text[MAX_FILENAME_LENGTH];
sprintf(source_text, "%s%cSource%cstory.ni",
project_folder, SEP_CHAR, SEP_CHAR);
set_placeholder_to("SOURCELOCATION", source_text, 0);
release_file_into_website("source.html", t, NULL); break;
}
{
#line 264 "cBlorb/Chapter 3/Releaser.w"
char *from = find_file_in_named_template(t, "(extras).txt");
if (from) { /* i.e., if the "(extras).txt" file exists */
file_read(from, "can't open (extras) file", FALSE, read_requested_file, 0);
}
}
#line 258 "cBlorb/Chapter 3/Releaser.w"
;
}
#line 136 "cBlorb/Chapter 3/Releaser.w"
; break;
}
}
}
#line 275 "cBlorb/Chapter 3/Releaser.w"
void read_requested_file(char *filename, text_file_position *tfp) {
filename = trim_white_space(filename);
if (filename[0] == 0) return;
release_file_into_website(filename, read_placeholder("TEMPLATE"), NULL);
}
#line 299 "cBlorb/Chapter 3/Releaser.w"
char current_placeholder[MAX_VAR_NAME_LENGTH];
int cp_written = FALSE;
void read_requested_ifile(char *manifestline, text_file_position *tfp) {
if (cp_written == FALSE) { cp_written = TRUE; current_placeholder[0] = 0; }
manifestline = trim_white_space(manifestline);
if (manifestline[0] == '[')
{
#line 325 "cBlorb/Chapter 3/Releaser.w"
if (manifestline[cblorb_strlen(manifestline)-1] == ']') {
if (cblorb_strlen(manifestline) >= MAX_VAR_NAME_LENGTH) {
error_1("placeholder name too long in manifest file", manifestline);
return;
}
strcpy(current_placeholder, manifestline+1);
current_placeholder[cblorb_strlen(current_placeholder)-1] = 0;
return;
}
error_1("placeholder name lacks ']' in manifest file", manifestline);
return;
}
#line 304 "cBlorb/Chapter 3/Releaser.w"
;
if (current_placeholder[0] == 0)
{
#line 341 "cBlorb/Chapter 3/Releaser.w"
if ((manifestline[0] == '!') || (manifestline[0] == 0)) return;
release_file_into_website(manifestline, read_placeholder("INTERPRETER"), "interpreter");
}
#line 306 "cBlorb/Chapter 3/Releaser.w"
else
{
#line 350 "cBlorb/Chapter 3/Releaser.w"
if (strcmp(current_placeholder, "INTERPRETERVM") == 0)
{
#line 367 "cBlorb/Chapter 3/Releaser.w"
char *vm_used = read_placeholder("INTERPRETERVMIS");
int i, capable = FALSE;
for (i=0; manifestline[i]; i++)
if (vm_used[0] == manifestline[i]) capable = TRUE;
if (capable == FALSE) {
char *format = "Z-machine";
if (vm_used[0] == 'g') format = "Glulx";
errorf_2s(
"You asked to release along with a copy of the '%s' in-browser "
"interpreter, but this can't handle story files which use the "
"%s story file format. (The format can be changed on Inform's "
"Settings panel for a project.)",
read_placeholder("INTERPRETER"), format);
}
}
#line 351 "cBlorb/Chapter 3/Releaser.w"
;
if (read_placeholder(current_placeholder))
append_to_placeholder(current_placeholder, "\n");
append_to_placeholder(current_placeholder, manifestline);
}
#line 308 "cBlorb/Chapter 3/Releaser.w"
;
}
#line 388 "cBlorb/Chapter 3/Releaser.w"
void release_file_into_website(char *name, char *t, char *sub) {
char write_to[MAX_FILENAME_LENGTH];
if (sub) sprintf(write_to, "%s%c%s%c%s",
release_folder, SEP_CHAR, sub, SEP_CHAR, name);
else sprintf(write_to, "%s%c%s", release_folder, SEP_CHAR, name);
char *from = find_file_in_named_template(t, name);
if (from == NULL) {
error_1("unable to find file in website template", name);
return;
}
if (infer_format_from_filename_extension(name) == FORMAT_PERHAPS_HTML)
{
#line 411 "cBlorb/Chapter 3/Releaser.w"
set_placeholder_to("TEMPLATE", t, 0);
if (trace_mode) printf("! Web page %s from template %s\n", name, t);
if (strcmp(name, "source.html") == 0)
web_copy_source(from, release_folder);
else
web_copy(from, write_to);
}
#line 401 "cBlorb/Chapter 3/Releaser.w"
else
{
#line 421 "cBlorb/Chapter 3/Releaser.w"
if (trace_mode) printf("! Binary file %s from template %s\n", name, t);
copy_file(from, write_to, FALSE);
}
#line 403 "cBlorb/Chapter 3/Releaser.w"
;
}
#line 428 "cBlorb/Chapter 3/Releaser.w"
void add_links_to_requested_resources(FILE *COPYTO) {
request *req;
LOOP_OVER(req, request)
if (req->private == FALSE)
switch (req->what_is_requested) {
case WEBSITE_REQ: break;
case INTERPRETER_REQ:
fprintf(COPYTO, "<li>");
download_link(COPYTO, "Play In-Browser", NULL, "play.html", "link");
fprintf(COPYTO, "</li>");
break;
case SOURCE_REQ:
fprintf(COPYTO, "<li>");
download_link(COPYTO, "Source Text", NULL, "source.html", "link");
fprintf(COPYTO, "</li>");
break;
case SOLUTION_REQ:
fprintf(COPYTO, "<li>");
download_link(COPYTO, "Solution", NULL, "solution.txt", "link");
fprintf(COPYTO, "</li>");
break;
case IFICTION_REQ:
fprintf(COPYTO, "<li>");
download_link(COPYTO, "Library Card", NULL, "iFiction.xml", "link");
fprintf(COPYTO, "</li>");
break;
}
}
#line 462 "cBlorb/Chapter 3/Releaser.w"
void declare_where_blorb_should_be_copied(char *path) {
char *leaf = read_placeholder("STORYFILE");
if (leaf == NULL) leaf = "Story";
printf("Copy blorb to: [[%s%c%s]]\n", path, SEP_CHAR, leaf);
}
#line 476 "cBlorb/Chapter 3/Releaser.w"
void report_requested_material(char *ph) {
if (release_folder[0] == 0) return; /* this should never happen */
int launch_website = FALSE, launch_play = FALSE;
append_to_placeholder(ph, "<ul>");
{
#line 500 "cBlorb/Chapter 3/Releaser.w"
if ((no_pictures_included > 1) || (no_sounds_included > 0))
append_to_placeholder(ph,
"<li>The blorb file <b>[STORYFILE]</b> ([BLORBFILESIZE]K in size, "
"including [BLORBFILEPICTURES] figures(s) and [BLORBFILESOUNDS] "
"sound(s))</li>");
else
append_to_placeholder(ph,
"<li>The blorb file <b>[STORYFILE]</b> ([BLORBFILESIZE]K in size)</li>");
}
#line 482 "cBlorb/Chapter 3/Releaser.w"
;
{
#line 512 "cBlorb/Chapter 3/Releaser.w"
if (count_requests_of_type(WEBSITE_REQ) > 0) {
append_to_placeholder(ph,
"<li>A website (generated from the [TEMPLATE] template) of ");
char pcount[32];
sprintf(pcount, "%d page%s", HTML_pages_created, (HTML_pages_created!=1)?"s":"");
append_to_placeholder(ph, pcount);
append_to_placeholder(ph, "</li>");
launch_website = TRUE;
}
}
#line 483 "cBlorb/Chapter 3/Releaser.w"
;
{
#line 525 "cBlorb/Chapter 3/Releaser.w"
if (count_requests_of_type(INTERPRETER_REQ) > 0) {
launch_play = TRUE;
append_to_placeholder(ph,
"<li>A play-in-browser page (generated from the [INTERPRETER] interpreter)</li>");
}
}
#line 484 "cBlorb/Chapter 3/Releaser.w"
;
{
#line 534 "cBlorb/Chapter 3/Releaser.w"
if (count_requests_of_type(IFICTION_REQ) > 0)
append_to_placeholder(ph,
"<li>The library card (stored as an iFiction record)</li>");
}
#line 485 "cBlorb/Chapter 3/Releaser.w"
;
{
#line 541 "cBlorb/Chapter 3/Releaser.w"
if (count_requests_of_type(SOLUTION_REQ) > 0)
append_to_placeholder(ph,
"<li>A solution file</li>");
}
#line 486 "cBlorb/Chapter 3/Releaser.w"
;
{
#line 548 "cBlorb/Chapter 3/Releaser.w"
if (count_requests_of_type(SOURCE_REQ) > 0) {
if (source_HTML_pages_created > 0) {
append_to_placeholder(ph, "<li>The source text (as plain text and as ");
char pcount[32];
sprintf(pcount, "%d web page%s",
source_HTML_pages_created, (source_HTML_pages_created!=1)?"s":"");
append_to_placeholder(ph, pcount);
append_to_placeholder(ph, ")</li>");
}
}
if (count_requests_of_type(RELEASE_SOURCE_REQ) > 0)
append_to_placeholder(ph,
"<li>The source text (as part of the website)</li>");
}
#line 487 "cBlorb/Chapter 3/Releaser.w"
;
{
#line 565 "cBlorb/Chapter 3/Releaser.w"
if (count_requests_of_type(COPY_REQ) > 0) {
append_to_placeholder(ph, "<li>The following additional file(s):<ul>");
request *req;
LOOP_OVER(req, request)
if (req->what_is_requested == COPY_REQ) {
char *leafname = req->details2;
append_to_placeholder(ph, "<li>");
append_to_placeholder(ph, leafname);
if (req->outcome_data >= 4096) {
char filesize[32];
sprintf(filesize, " (%dK)", req->outcome_data/1024);
append_to_placeholder(ph, filesize);
} else if (req->outcome_data >= 0) {
char filesize[32];
sprintf(filesize, " (%d byte%s)",
req->outcome_data, (req->outcome_data!=1)?"s":"");
append_to_placeholder(ph, filesize);
}
if (strcmp(req->details3, "--") != 0) {
append_to_placeholder(ph, " to subfolder ");
append_to_placeholder(ph, req->details3);
}
append_to_placeholder(ph, "</li>");
}
append_to_placeholder(ph, "</ul></li>");
}
}
#line 488 "cBlorb/Chapter 3/Releaser.w"
;
append_to_placeholder(ph, "</ul>");
if ((launch_website) || (launch_play))
{
#line 599 "cBlorb/Chapter 3/Releaser.w"
append_to_placeholder(ph, "<p><center>");
if (launch_website) {
append_to_placeholder(ph,
"<a href=\"[JAVASCRIPTPRELUDE]"
"openUrl('file://[**MATERIALSFOLDERPATHOPEN]/Release/index.html')\">"
"<img src='inform:/outcome_images/browse.png' border=0></a> home page");
}
if ((launch_website) && (launch_play))
append_to_placeholder(ph, " : ");
if (launch_play) {
append_to_placeholder(ph,
"<a href=\"[JAVASCRIPTPRELUDE]"
"openUrl('file://[**MATERIALSFOLDERPATHOPEN]/Release/play.html')\">"
"<img src='inform:/outcome_images/browse.png' border=0></a> play-in-browser page");
}
append_to_placeholder(ph, "</center></p>");
}
#line 491 "cBlorb/Chapter 3/Releaser.w"
;
{
#line 623 "cBlorb/Chapter 3/Releaser.w"
request *req;
int count = 0;
LOOP_OVER(req, request)
if (req->what_is_requested == INSTRUCTION_REQ) {
if (count == 0)
append_to_placeholder(ph, "<p>The source text gives release instructions ");
else
append_to_placeholder(ph, " and ");
append_to_placeholder(ph, req->details1);
append_to_placeholder(ph, " here");
count++;
}
if (count > 0)
append_to_placeholder(ph, ".</p>");
}
#line 493 "cBlorb/Chapter 3/Releaser.w"
;
{
#line 644 "cBlorb/Chapter 3/Releaser.w"
request *req;
int count = 0;
LOOP_OVER(req, request)
if (req->what_is_requested == ALTERNATIVE_REQ) {
if (count == 0)
append_to_placeholder(ph,
"<p>Here are some other possibilities you might want to consider:<p><ul>");
append_to_placeholder(ph, "<li>");
append_to_placeholder(ph, req->details1);
append_to_placeholder(ph, "</li>");
count++;
}
if (count > 0)
append_to_placeholder(ph, "</ul></p>");
}
#line 494 "cBlorb/Chapter 3/Releaser.w"
;
}
#line 662 "cBlorb/Chapter 3/Releaser.w"
int count_requests_of_type(int t) {
request *req;
int count = 0;
LOOP_OVER(req, request)
if (req->what_is_requested == t)
count++;
return count;
}
#line 62 "cBlorb/Chapter 3/Solution Deviser.w"
void walkthrough(char *Skein_filename, char *walkthrough_filename) {
build_skein_tree(Skein_filename);
if (root_skn == NULL) {
error("there appear to be no threads in the Skein");
return;
}
identify_relevant_lines();
if (root_skn->relevant == FALSE) {
error("no threads in the Skein have been marked '***'");
return;
}
prune_irrelevant_lines();
write_solution_file(walkthrough_filename);
}
#line 80 "cBlorb/Chapter 3/Solution Deviser.w"
skein_node *current_skein_node = NULL;
void build_skein_tree(char *Skein_filename) {
root_skn = NULL;
current_skein_node = NULL;
file_read(Skein_filename, "can't open skein file", FALSE, read_skein_pass_1, 0);
current_skein_node = NULL;
file_read(Skein_filename, "can't open skein file", FALSE, read_skein_pass_2, 0);
}
void read_skein_pass_1(char *line, text_file_position *tfp) { read_skein_line(line, 1); }
void read_skein_pass_2(char *line, text_file_position *tfp) { read_skein_line(line, 2); }
#line 101 "cBlorb/Chapter 3/Solution Deviser.w"
void read_skein_line(char *line, int pass) {
char node_id[MAX_NODE_ID_LENGTH];
find_node_ID_in_tag(line, "item", node_id, MAX_NODE_ID_LENGTH, TRUE);
if (pass == 1) {
if (node_id[0])
{
#line 131 "cBlorb/Chapter 3/Solution Deviser.w"
current_skein_node = CREATE(skein_node);
if (root_skn == NULL) root_skn = current_skein_node;
strcpy(current_skein_node->id, node_id);
strcpy(current_skein_node->command, "");
strcpy(current_skein_node->annotation, "");
current_skein_node->branch_count = -1;
current_skein_node->branch_parent = NULL;
current_skein_node->parent = NULL;
current_skein_node->child = NULL;
current_skein_node->sibling = NULL;
current_skein_node->relevant = FALSE;
if (trace_mode) printf("Creating knot with ID '%s'\n", node_id);
}
#line 106 "cBlorb/Chapter 3/Solution Deviser.w"
;
if (current_skein_node) {
{
#line 159 "cBlorb/Chapter 3/Solution Deviser.w"
char *p = current_skein_node->command;
if (find_text_of_tag(line, "command", p, MAX_COMMAND_LENGTH, FALSE)) {
if (trace_mode) printf("Raw command '%s'\n", p);
undo_XML_escapes_in_string(p);
convert_string_to_upper_case(p);
if (trace_mode) printf("Processed command '%s'\n", p);
}
}
#line 108 "cBlorb/Chapter 3/Solution Deviser.w"
;
{
#line 170 "cBlorb/Chapter 3/Solution Deviser.w"
char *p = current_skein_node->annotation;
if (find_text_of_tag(line, "annotation", p, MAX_ANNOTATION_LENGTH, FALSE)) {
if (trace_mode) printf("Raw annotation '%s'\n", p);
undo_XML_escapes_in_string(p);
if (trace_mode) printf("Processed annotation '%s'\n", p);
}
}
#line 109 "cBlorb/Chapter 3/Solution Deviser.w"
;
}
} else {
if (node_id[0]) current_skein_node = find_node_with_ID(node_id);
if (current_skein_node) {
char child_node_id[MAX_NODE_ID_LENGTH];
find_node_ID_in_tag(line, "child", child_node_id, MAX_NODE_ID_LENGTH, TRUE);
if (child_node_id[0]) {
skein_node *new_child = find_node_with_ID(child_node_id);
if (new_child == NULL) {
error("the skein file is malformed (B)");
return;
}
{
#line 147 "cBlorb/Chapter 3/Solution Deviser.w"
new_child->parent = current_skein_node;
if (current_skein_node->child == NULL) {
current_skein_node->child = new_child;
} else {
skein_node *familial = current_skein_node->child;
while (familial->sibling) familial = familial->sibling;
familial->sibling = new_child;
}
}
#line 122 "cBlorb/Chapter 3/Solution Deviser.w"
;
}
}
}
}
#line 180 "cBlorb/Chapter 3/Solution Deviser.w"
int find_node_ID_in_tag(char *line, char *tag,
char *write_to, int max_length, int abort_not_trim) {
char portion1[MAX_TEXT_FILE_LINE_LENGTH], portion2[MAX_TEXT_FILE_LINE_LENGTH];
char prototype[64];
strcpy(prototype, "%[^<]<");
strcat(prototype, tag);
strcat(prototype, " nodeId=\"%[^\"]\"");
write_to[0] = 0;
if (sscanf(line, prototype, portion1, portion2) == 2) {
if ((cblorb_strlen(portion2) >= max_length-1) && (abort_not_trim)) {
error("the skein file is malformed (C)");
return FALSE;
}
strncpy(write_to, portion2, (size_t) max_length-1); write_to[max_length-1] = 0;
return TRUE;
}
return FALSE;
}
#line 202 "cBlorb/Chapter 3/Solution Deviser.w"
int find_text_of_tag(char *line, char *tag,
char *write_to, int max_length, int abort_not_trim) {
char portion1[MAX_TEXT_FILE_LINE_LENGTH], portion2[MAX_TEXT_FILE_LINE_LENGTH],
portion3[MAX_TEXT_FILE_LINE_LENGTH];
char prototype[64];
strcpy(prototype, "%[^>]>%[^<]</");
strcat(prototype, tag);
strcat(prototype, "%s");
if (sscanf(line, prototype, portion1, portion2, portion3) == 3) {
if ((cblorb_strlen(portion2) >= max_length-1) && (abort_not_trim)) {
error("the skein file is malformed (C)");
return FALSE;
}
strncpy(write_to, portion2, (size_t) max_length-1); write_to[max_length-1] = 0;
if (trace_mode) printf("found %s = '%s'\n", tag, portion2);
return TRUE;
}
return FALSE;
}
#line 225 "cBlorb/Chapter 3/Solution Deviser.w"
skein_node *find_node_with_ID(char *id) {
skein_node *skn;
LOOP_OVER(skn, skein_node)
if (strcmp(id, skn->id) == 0)
return skn;
return NULL;
}
#line 236 "cBlorb/Chapter 3/Solution Deviser.w"
void convert_string_to_upper_case(char *p) {
int i;
for (i=0; p[i]; i++) p[i]=cblorb_toupper(p[i]);
}
#line 244 "cBlorb/Chapter 3/Solution Deviser.w"
void undo_XML_escapes_in_string(char *p) {
int i = 0, j = 0;
while (p[i]) {
if (p[i] == '&') {
char xml_escape[16];
int k=0;
while ((p[i+k] != 0) && (p[i+k] != ';') && (k<14)) {
xml_escape[k] = cblorb_tolower(p[i+k]); k++;
}
xml_escape[k] = p[i+k]; k++; xml_escape[k] = 0;
{
#line 264 "cBlorb/Chapter 3/Solution Deviser.w"
char c = 0;
if (strcmp(xml_escape, "&lt;") == 0) c = '<';
if (strcmp(xml_escape, "&gt;") == 0) c = '>';
if (strcmp(xml_escape, "&amp;") == 0) c = '&';
if (strcmp(xml_escape, "&apos;") == 0) c = '\'';
if (strcmp(xml_escape, "&quot;") == 0) c = '\"';
if (c) { p[j++] = c; i += cblorb_strlen(xml_escape); continue; }
}
#line 254 "cBlorb/Chapter 3/Solution Deviser.w"
;
}
p[j++] = p[i++];
}
p[j++] = 0;
}
#line 280 "cBlorb/Chapter 3/Solution Deviser.w"
void identify_relevant_lines(void) {
skein_node *skn;
LOOP_OVER(skn, skein_node) {
char *p = skn->annotation;
if (trace_mode) printf("Knot %s is annotated '%s'\n", skn->id, p);
if ((p[0] == '*') && (p[1] == '*') && (p[2] == '*')) {
int i = 3, j; while (p[i] == ' ') i++;
for (j=0; p[i]; i++) p[j++] = p[i]; p[j] = 0;
skein_node *knot;
for (knot = skn; knot; knot = knot->parent) {
knot->relevant = TRUE;
if (trace_mode) printf("Knot %s is relevant\n", knot->id);
}
}
}
}
#line 315 "cBlorb/Chapter 3/Solution Deviser.w"
void prune_irrelevant_lines(void) {
skein_node *skn;
LOOP_OVER(skn, skein_node)
if ((skn->relevant == FALSE) && (skn->parent))
{
#line 325 "cBlorb/Chapter 3/Solution Deviser.w"
if (skn->parent->child == skn) {
skn->parent->child = skn->sibling;
} else {
skein_node *skn2 = skn->parent->child;
while ((skn2) && (skn2->sibling != skn)) skn2 = skn2->sibling;
if ((skn2) && (skn2->sibling == skn)) skn2->sibling = skn->sibling;
}
skn->parent = NULL;
skn->sibling = NULL;
}
#line 319 "cBlorb/Chapter 3/Solution Deviser.w"
;
}
#line 338 "cBlorb/Chapter 3/Solution Deviser.w"
void write_solution_file(char *walkthrough_filename) {
FILE *SOL = fopen(walkthrough_filename, "w");
if (SOL == NULL)
fatal_fs("unable to open destination for solution text file",
walkthrough_filename);
fprintf(SOL, "Solution to \""); copy_placeholder_to("TITLE", SOL);
fprintf(SOL, "\" by "); copy_placeholder_to("AUTHOR", SOL); fprintf(SOL, "\n\n");
recursively_solve(SOL, root_skn, NULL);
fclose(SOL);
}
#line 354 "cBlorb/Chapter 3/Solution Deviser.w"
void recursively_solve(FILE *SOL, skein_node *skn, skein_node *last_branch) {
{
#line 369 "cBlorb/Chapter 3/Solution Deviser.w"
while ((skn->child == NULL) || (skn->child->sibling == NULL)) {
if (skn->child == NULL) return;
if (skn->child->sibling == NULL) {
skn = skn->child;
write_command(SOL, skn, NORMAL_COMMAND);
}
}
}
#line 355 "cBlorb/Chapter 3/Solution Deviser.w"
;
{
#line 381 "cBlorb/Chapter 3/Solution Deviser.w"
fprintf(SOL, "Choice:\n");
int branch_counter = 1;
skein_node *option;
for (option = skn->child; option; option = option->sibling)
if (option->child == NULL) {
write_command(SOL, option, BRANCH_TO_END_COMMAND);
} else {
option->branch_count = branch_counter++;
option->branch_parent = last_branch;
write_command(SOL, option, BRANCH_TO_LINE_COMMAND);
}
}
#line 356 "cBlorb/Chapter 3/Solution Deviser.w"
;
{
#line 396 "cBlorb/Chapter 3/Solution Deviser.w"
skein_node *option;
for (option = skn->child; option; option = option->sibling)
if (option->child) {
fprintf(SOL, "\nBranch (");
write_branch_name(SOL, option);
fprintf(SOL, ")\n");
recursively_solve(SOL, option, option);
}
}
#line 357 "cBlorb/Chapter 3/Solution Deviser.w"
;
}
#line 412 "cBlorb/Chapter 3/Solution Deviser.w"
void write_command(FILE *SOL, skein_node *cmd_skn, int form) {
if (form != NORMAL_COMMAND) fprintf(SOL, " ");
fprintf(SOL, "%s", cmd_skn->command);
if (form != NORMAL_COMMAND) {
fprintf(SOL, " -> ");
if (form == BRANCH_TO_LINE_COMMAND) {
fprintf(SOL, "go to branch (");
write_branch_name(SOL, cmd_skn);
fprintf(SOL, ")");
}
else fprintf(SOL, "end");
}
if (cmd_skn->annotation[0]) fprintf(SOL, " ... %s", cmd_skn->annotation);
fprintf(SOL, "\n");
}
#line 435 "cBlorb/Chapter 3/Solution Deviser.w"
void write_branch_name(FILE *SOL, skein_node *skn) {
if (skn->branch_parent) {
write_branch_name(SOL, skn->branch_parent);
fprintf(SOL, ".");
}
fprintf(SOL, "%d", skn->branch_count);
}
#line 38 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void create_auxiliary_file(char *filename, char *description, char *subfolder) {
auxiliary_file *aux = CREATE(auxiliary_file);
strcpy(aux->description, description);
strcpy(aux->full_filename, filename);
char *ext = get_filename_extension(filename);
char *leaf = get_filename_leafname(filename);
if (ext[0] == '.') {
strcpy(aux->relative_URL, filename);
if (cblorb_strlen(ext + 1) >= MAX_EXTENSION_LENGTH - 1) {
error("auxiliary file has overlong extension"); return;
}
strcpy(aux->format, ext + 1);
int k; for (k=0; aux->format[k]; k++) aux->format[k] = cblorb_tolower(aux->format[k]);
} else {
strcpy(aux->format, "link");
sprintf(aux->relative_URL, "%s%cindex.html", filename, SEP_CHAR);
}
strcpy(aux->aux_leafname, leaf);
strcpy(aux->aux_subfolder, subfolder);
printf("! Auxiliary file: <%s> = <%s>\n", filename, description);
}
#line 67 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void expand_AUXILIARY_variable(FILE *COPYTO) {
auxiliary_file *aux;
LOOP_OVER(aux, auxiliary_file) {
if (strcmp(aux->description, "--") != 0) {
fprintf(COPYTO, "<li>");
download_link(COPYTO,
aux->description, aux->full_filename, aux->aux_leafname, aux->format);
fprintf(COPYTO, "</li>");
}
}
add_links_to_requested_resources(COPYTO);
}
#line 84 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void expand_DOWNLOAD_variable(FILE *COPYTO) {
char target_pathname[MAX_FILENAME_LENGTH]; /* eventual pathname of Blorb file written */
sprintf(target_pathname, "%s%c%s", release_folder, SEP_CHAR, read_placeholder("STORYFILE"));
download_link(COPYTO, "Story File", target_pathname, read_placeholder("STORYFILE"), "Blorb");
}
#line 94 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void download_link(FILE *COPYTO, char *desc, char *filename, char *relative_url, char *form) {
int size_up = TRUE;
if (strcmp(form, "link") == 0) size_up = FALSE;
fprintf(COPYTO, "<a href=\"%s\">%s</a> ", relative_url, desc);
open_style(COPYTO, "filetype");
fprintf(COPYTO, "(%s", form);
if (size_up) {
long int size = -1L;
if (strcmp(desc, "Story File") == 0) size = (long int) blorb_file_size;
else size = file_size(filename);
if (size != -1L)
{
#line 115 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
char *units = "&nbsp;bytes";
long int remainder = 0;
if (size > 1024L) { remainder = size % 1024L; size /= 1024L; units = "KB"; }
if (size > 1024L) { remainder = size % 1024L; size /= 1024L; units = "MB"; }
if (size > 1024L) { remainder = size % 1024L; size /= 1024L; units = "GB"; }
if (size > 1024L) { remainder = size % 1024L; size /= 1024L; units = "TB"; }
fprintf(COPYTO, ",&nbsp;%d", (int) size);
if ((size < 100L) && (remainder >= 103L)) fprintf(COPYTO, ".%d", (int) (remainder/103L));
fprintf(COPYTO, "%s", units);
}
#line 104 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
}
fprintf(COPYTO, ")");
close_style(COPYTO, "filetype");
}
#line 131 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void expand_COVER_variable(FILE *COPYTO) {
if (cover_exists) {
char *format = "png"; if (cover_is_in_JPEG_format) format = "jpg";
fprintf(COPYTO, "<a href=\"Cover.%s\"><img src=\"Small Cover.%s\" border=\"1\"></a>",
format, format);
}
}
#line 144 "cBlorb/Chapter 3/Links and Auxiliary Files.w"
void request_copy_of_auxiliaries(void) {
auxiliary_file *aux;
LOOP_OVER(aux, auxiliary_file)
if (strcmp(aux->format, "link") != 0) {
if (trace_mode)
printf("! COPY <%s> as <%s>\n", aux->full_filename, aux->aux_leafname);
request_copy(aux->full_filename, aux->aux_leafname, aux->aux_subfolder);
}
}
#line 42 "cBlorb/Chapter 3/Placeholders.w"
void initialise_placeholders(void) {
set_placeholder_to("SOURCE", "", SOURCE_RPL);
set_placeholder_to("SOURCENOTES", "", SOURCENOTES_RPL);
set_placeholder_to("SOURCELINKS", "", SOURCELINKS_RPL);
set_placeholder_to("COVER", "", COVER_RPL);
set_placeholder_to("DOWNLOAD", "", DOWNLOAD_RPL);
set_placeholder_to("AUXILIARY", "", AUXILIARY_RPL);
set_placeholder_to("PAGENUMBER", "", PAGENUMBER_RPL);
set_placeholder_to("PAGEEXTENT", "", PAGEEXTENT_RPL);
set_placeholder_to("CBLORBERRORS", "", 0);
set_placeholder_to("INBROWSERPLAY", "", 0);
set_placeholder_to("INTERPRETERSCRIPTS", "", 0);
set_placeholder_to("OTHERCREDITS", "", 0);
set_placeholder_to("BLURB", "", 0);
set_placeholder_to("TEMPLATE", "Standard", 0);
set_placeholder_to("GENERATOR", VERSION, 0);
set_placeholder_to("BASE64_TOP", "", 0);
set_placeholder_to("BASE64_TAIL", "", 0);
set_placeholder_to("JAVASCRIPTPRELUDE", JAVASCRIPT_PRELUDE, 0);
set_placeholder_to("FONTTAG", FONT_TAG, 0);
initialise_time_variables();
}
#line 70 "cBlorb/Chapter 3/Placeholders.w"
placeholder *find_placeholder(char *name) {
placeholder *wv;
LOOP_OVER(wv, placeholder)
if (strcmp(wv->pl_name, name) == 0)
return wv;
return NULL;
}
char *read_placeholder(char *name) {
placeholder *wv = find_placeholder(name);
if (wv) return wv->pl_contents;
return NULL;
}
#line 88 "cBlorb/Chapter 3/Placeholders.w"
void set_placeholder_to_number(char *var, int v) {
char temp_digits[64];
sprintf(temp_digits, "%d", v);
set_placeholder_to(var, temp_digits, 0);
}
#line 101 "cBlorb/Chapter 3/Placeholders.w"
void set_placeholder_to(char *var, char *text, int reservation) {
set_placeholder_to_inner(var, text, reservation, FALSE);
}
void append_to_placeholder(char *var, char *text) {
set_placeholder_to_inner(var, text, 0, TRUE);
}
#line 111 "cBlorb/Chapter 3/Placeholders.w"
void set_placeholder_to_inner(char *var, char *text, int reservation, int extend) {
if (cblorb_strlen(var) >= MAX_VAR_NAME_LENGTH-1) { error("variable name too long"); return; }
if (trace_mode) printf("! [%s] <-- \"%s\"\n", var, (text)?text:"");
placeholder *wv = find_placeholder(var);
if ((wv) && (reservation > 0)) { error("tried to set reserved variable"); return; }
if (wv == NULL) {
wv = CREATE(placeholder);
if (trace_mode) printf("! Creating [%s]\n", var);
strcpy(wv->pl_name, var);
(wv->pl_contents)[0] = 0;
wv->reservation = reservation;
}
int L = cblorb_strlen(text) + 1;
if (extend) L += cblorb_strlen(wv->pl_contents);
if (L >= MAX_FILENAME_LENGTH) { error("placeholder text too long"); return; }
if (wv->pl_contents != text) {
if (extend) strcat(wv->pl_contents, text);
else strcpy(wv->pl_contents, text);
}
}
#line 146 "cBlorb/Chapter 3/Placeholders.w"
int escape_quotes_mode = 0;
void copy_placeholder_to(char *var, FILE *COPYTO) {
int multiparagraph_mode = FALSE, eqm = escape_quotes_mode;
if (var[0] == '*') { var++; escape_quotes_mode = 1; }
if (var[0] == '*') { var++; escape_quotes_mode = 2; }
if (strcmp(var, "BLURB") == 0) multiparagraph_mode = TRUE;
placeholder *wv = find_placeholder(var);
if ((wv == NULL) || (wv->locked)) {
fprintf(COPYTO, "[%s]", var);
} else {
wv->locked = TRUE;
if (multiparagraph_mode) fprintf(COPYTO, "<p>");
switch (wv->reservation) {
case 0:
{
#line 185 "cBlorb/Chapter 3/Placeholders.w"
int i; char *p = wv->pl_contents;
for (i=0; p[i]; i++) {
if ((p[i] == '<') && (p[i+1] == 'b') && (p[i+2] == 'r') &&
(p[i+3] == '/') && (p[i+4] == '>') && (multiparagraph_mode)) {
fprintf(COPYTO, "</p><p>"); i += 4; continue;
}
if (p[i] == '[') {
char inner_name[MAX_VAR_NAME_LENGTH+1];
int j = i+1, k = 0, expanded = FALSE; inner_name[0] = 0;
for (; p[j]; j++) {
if ((p[j] == '[') || (p[j] == ' ')) break;
if (p[j] == ']') {
i = j;
copy_placeholder_to(inner_name, COPYTO);
expanded = TRUE;
break;
}
inner_name[k++] = p[j]; inner_name[k] = 0;
if (k >= MAX_VAR_NAME_LENGTH) break;
}
if (expanded) continue;
}
if (((p[i] == '\x0a') || (p[i] == '\x0d') || (p[i] == '\x7f')) &&
(multiparagraph_mode)) {
fprintf(COPYTO, "<p>"); continue;
}
if ((escape_quotes_mode == 1) && (p[i] == '\'')) fprintf(COPYTO, "&#39;");
else if ((escape_quotes_mode == 2) && (p[i] == '\'')) fprintf(COPYTO, "%%2527");
else fprintf(COPYTO, "%c", p[i]);
}
}
#line 159 "cBlorb/Chapter 3/Placeholders.w"
; break;
case SOURCE_RPL: expand_SOURCE_or_SOURCENOTES_variable(COPYTO, FALSE); break;
case SOURCENOTES_RPL: expand_SOURCE_or_SOURCENOTES_variable(COPYTO, TRUE); break;
case SOURCELINKS_RPL: expand_SOURCELINKS_variable(COPYTO); break;
case COVER_RPL: expand_COVER_variable(COPYTO); break;
case DOWNLOAD_RPL: expand_DOWNLOAD_variable(COPYTO); break;
case AUXILIARY_RPL: expand_AUXILIARY_variable(COPYTO); break;
case PAGENUMBER_RPL: expand_PAGENUMBER_variable(COPYTO); break;
case PAGEEXTENT_RPL: expand_PAGEEXTENT_variable(COPYTO); break;
}
if (multiparagraph_mode) fprintf(COPYTO, "</p>");
wv->locked = FALSE;
escape_quotes_mode = eqm;
}
}
#line 36 "cBlorb/Chapter 3/Templates.w"
int no_template_paths = 0;
void new_template_path(char *pathname) {
template_path *tp = CREATE(template_path);
strcpy(tp->template_repository, pathname);
if (trace_mode)
printf("! Template search path %d: <%s>\n", ++no_template_paths, pathname);
}
#line 51 "cBlorb/Chapter 3/Templates.w"
template_path *seek_file_in_template_paths(char *name, char *leafname) {
template_path *tp;
LOOP_OVER(tp, template_path) {
char possible[MAX_FILENAME_LENGTH];
sprintf(possible, "%s%c%s%c%s",
tp->template_repository, SEP_CHAR, name, SEP_CHAR, leafname);
if (file_exists(possible)) return tp;
}
return NULL;
}
#line 71 "cBlorb/Chapter 3/Templates.w"
template *find_template(char *name) {
template *t;
{
#line 91 "cBlorb/Chapter 3/Templates.w"
LOOP_OVER(t, template)
if (strcmp(name, t->template_name) == 0)
return t;
}
#line 73 "cBlorb/Chapter 3/Templates.w"
;
template_path *tp = seek_file_in_template_paths(name, "index.html");
if (tp == NULL) tp = seek_file_in_template_paths(name, "source.html");
if (tp == NULL) tp = seek_file_in_template_paths(name, "style.css");
if (tp == NULL) tp = seek_file_in_template_paths(name, "(extras).txt");
if (tp == NULL) tp = seek_file_in_template_paths(name, "(manifest).txt");
if (tp) {
t = CREATE(template);
strcpy(t->template_name, name);
t->template_location = tp;
return t;
}
return NULL;
}
#line 100 "cBlorb/Chapter 3/Templates.w"
int template_doesnt_exist = FALSE;
char *find_file_in_named_template(char *name, char *needed) {
template *t = find_template(name), *Standard = find_template("Standard");
if (t == NULL) {
if (template_doesnt_exist == FALSE) {
errorf_1s(
"Websites and play-in-browser interpreter web pages are created "
"using named templates. (Basic examples are built into the Inform "
"application. You can also create your own, putting them in the "
"'Templates' subfolder of the project's Materials folder.) Each "
"template has a name. On this Release, I tried to use the "
"'%s' template, but couldn't find a copy of it anywhere.", name);
}
template_doesnt_exist = TRUE;
}
char *path = try_single_template(t, needed);
if ((path == NULL) && (Standard))
path = try_single_template(Standard, needed);
return path;
}
#line 124 "cBlorb/Chapter 3/Templates.w"
char *try_single_template(template *t, char *needed) {
if (t == NULL) return NULL;
sprintf(t->latest_use, "%s%c%s%c%s",
t->template_location->template_repository, SEP_CHAR, t->template_name, SEP_CHAR, needed);
if (trace_mode) printf("! Trying <%s>\n", t->latest_use);
if (file_exists(t->latest_use)) return t->latest_use;
return NULL;
}
#line 110 "cBlorb/Chapter 3/Website Maker.w"
void open_style(FILE *write_to, char *new) {
if (new == NULL) return;
if (use_css_code_styles) {
fprintf(write_to, "<span class=\"%s\">", new);
} else {
if (strcmp(new, "columnhead") == 0) fprintf(write_to, "<u>");
if (strcmp(new, "comment") == 0) fprintf(write_to, "<font color=#404040>");
if (strcmp(new, "filetype") == 0) fprintf(write_to, "<small>");
if (strcmp(new, "heading") == 0) fprintf(write_to, "<b>");
if (strcmp(new, "i6code") == 0) fprintf(write_to, "<font color=#909090>");
if (strcmp(new, "notecue") == 0) fprintf(write_to, "<font color=#404040><sup>");
if (strcmp(new, "notesheading") == 0) fprintf(write_to, "<i>");
if (strcmp(new, "notetext") == 0) fprintf(write_to, "<font color=#404040>");
if (strcmp(new, "quote") == 0) fprintf(write_to, "<font color=#000080>");
if (strcmp(new, "substitution") == 0) fprintf(write_to, "<font color=#000080>");
}
}
void close_style(FILE *write_to, char *old) {
if (old == NULL) return;
if (use_css_code_styles) {
fprintf(write_to, "</span>");
} else {
if (strcmp(old, "columnhead") == 0) fprintf(write_to, "</u>");
if (strcmp(old, "comment") == 0) fprintf(write_to, "</font>");
if (strcmp(old, "filetype") == 0) fprintf(write_to, "</small>");
if (strcmp(old, "heading") == 0) fprintf(write_to, "</b>");
if (strcmp(old, "i6code") == 0) fprintf(write_to, "</font>");
if (strcmp(old, "notecue") == 0) fprintf(write_to, "</sup></font>");
if (strcmp(old, "notesheading") == 0) fprintf(write_to, "</i>");
if (strcmp(old, "notetext") == 0) fprintf(write_to, "</font>");
if (strcmp(old, "quote") == 0) fprintf(write_to, "</font>");
if (strcmp(old, "substitution") == 0) fprintf(write_to, "</font>");
}
}
#line 152 "cBlorb/Chapter 3/Website Maker.w"
char *current_style = NULL;
void change_style(FILE *write_to, char *new) {
if (current_style) close_style(write_to, current_style);
open_style(write_to, new);
current_style = new;
}
#line 166 "cBlorb/Chapter 3/Website Maker.w"
void open_code(FILE *write_to) {
if (use_css_code_styles == FALSE) {
fprintf(write_to, "<p>");
}
}
void close_code(FILE *write_to) {
if (use_css_code_styles == FALSE) {
fprintf(write_to, "</p>");
}
}
#line 182 "cBlorb/Chapter 3/Website Maker.w"
void open_code_paragraph(FILE *write_to, int indentation) {
if (use_css_code_styles) {
char *classname = "";
switch (indentation) {
case 0: classname = "indent0"; break;
case 1: classname = "indent1"; break;
case 2: classname = "indent2"; break;
case 3: classname = "indent3"; break;
case 4: classname = "indent4"; break;
case 5: classname = "indent5"; break;
case 6: classname = "indent6"; break;
case 7: classname = "indent7"; break;
case 8: classname = "indent8"; break;
default: classname = "indent9"; break;
}
fprintf(write_to, "<p class=\"%s\">", classname);
} else {
int i;
for (i=0; i<indentation; i++) fprintf(write_to, "&nbsp;&nbsp;&nbsp;&nbsp;");
}
}
void close_code_paragraph(FILE *write_to) {
if (use_css_code_styles) {
fprintf(write_to, "</p>");
} else {
fprintf(write_to, "<br>");
}
}
#line 216 "cBlorb/Chapter 3/Website Maker.w"
void open_table_cell(FILE *write_to) {
if (use_css_code_styles) {
fprintf(write_to, "<td>");
} else {
fprintf(write_to, "<td halign=\"left\" valign=\"top\">");
}
}
void close_table_cell(FILE *write_to) {
if (use_css_code_styles) {
fprintf(write_to, "</td>");
} else {
fprintf(write_to, "&nbsp;&nbsp;</td>");
}
}
#line 235 "cBlorb/Chapter 3/Website Maker.w"
FILE *COPYTO = NULL;
void web_copy(char *from, char *to) {
if ((from == NULL) || (to == NULL) || (strcmp(from, to) == 0))
fatal("files confused in website maker");
HTML_pages_created++;
COPYTO = fopen(to, "w");
if (COPYTO == NULL) { error_1("unable to open file to be written for web site", to); return; }
file_read(from, "can't open template file", FALSE, copy_html_line, 0);
fclose(COPYTO);
}
#line 249 "cBlorb/Chapter 3/Website Maker.w"
void copy_html_line(char *line, text_file_position *tfp) {
int i;
for (i=0; line[i]; i++) {
{
#line 262 "cBlorb/Chapter 3/Website Maker.w"
if (line[i] == '[') {
int j;
for (j=i+1; (line[j] && line[j]!=']'); j++) ;
if (line[j] == ']') {
line[j] = 0; copy_placeholder_to(line+i+1, COPYTO); line[j] = ']';
i = j;
continue;
}
}
}
#line 252 "cBlorb/Chapter 3/Website Maker.w"
;
{
#line 277 "cBlorb/Chapter 3/Website Maker.w"
if ((line[i] == '<') && (line[i+1] == '/') && (line[i+2] == 'h') &&
(line[i+3] == 'e') && (line[i+4] == 'a') && (line[i+5] == 'd') &&
(line[i+6] == '>'))
copy_placeholder_to("INTERPRETERSCRIPTS", COPYTO);
}
#line 253 "cBlorb/Chapter 3/Website Maker.w"
;
fprintf(COPYTO, "%c", line[i]);
}
fprintf(COPYTO, "\n");
}
#line 296 "cBlorb/Chapter 3/Website Maker.w"
char source_text[MAX_FILENAME_LENGTH];
void web_copy_source(char *template, char *website_pathname) {
strcpy(source_text, read_placeholder("SOURCELOCATION"));
scan_source_text();
write_source_text_pages(template, website_pathname);
}
#line 308 "cBlorb/Chapter 3/Website Maker.w"
int within_a_table; /* are we inside a Table declaration in the source text? */
int scan_quoted_matter; /* are we inside double-quoted matter in the source text? */
int scan_comment_nesting; /* level of nesting of comments in source text: 0 means "not in a comment" */
text_file_position *latest_line_position; /* |ftell|-reported byte offset of the start of the current line in the source */
table *current_table; /* the Table which started most recently, or |NULL| if none has */
heading *current_heading; /* the heading seen most recently, or |NULL| if none has been */
segment *current_segment; /* the segment which started most recently, or |NULL| if none has */
int position_of_documentation_bar; /* line count of the |---- Documentation ----| line, if there is one */
#line 322 "cBlorb/Chapter 3/Website Maker.w"
void scan_source_text(void) {
within_a_table = FALSE;
scan_comment_nesting = 0;
scan_quoted_matter = FALSE;
latest_line_position = NULL;
current_table = NULL;
current_heading = NULL;
current_segment = NULL;
position_of_documentation_bar = MAX_SOURCE_TEXT_LINES;
file_read(source_text, "can't open source text of project", TRUE, scan_source_line, NULL);
{
#line 343 "cBlorb/Chapter 3/Website Maker.w"
int minhl = 10;
heading *h;
LOOP_OVER(h, heading)
if (h->heading_level < DOC_LEVEL)
if (h->heading_level < minhl)
minhl = h->heading_level;
LOOP_OVER(h, heading)
if (h->heading_level < DOC_LEVEL)
h->heading_level -= minhl;
}
#line 333 "cBlorb/Chapter 3/Website Maker.w"
;
}
#line 358 "cBlorb/Chapter 3/Website Maker.w"
void scan_source_line(char *line, text_file_position *tfp) {
int lc = tfp_get_line_count(tfp), lv = DULL_LEVEL;
latest_line_position = tfp;
if (scan_quoted_matter == FALSE)
{
#line 386 "cBlorb/Chapter 3/Website Maker.w"
char fword[32];
extract_word(fword, line, 32, 1);
if (fword[0] == 0) lv = EMPTY_LEVEL;
if (strcmp(fword, "table") == 0) lv = TABLE_LEVEL;
if (lc > position_of_documentation_bar) {
if (strcmp(fword, "chapter:") == 0) lv = DOC_CHAPTER_LEVEL;
if (strcmp(fword, "section:") == 0) lv = DOC_SECTION_LEVEL;
if (strcmp(fword, "example:") == 0) lv = EXAMPLE_LEVEL;
} else {
if (strcmp(fword, "volume") == 0) lv = 1;
if (strcmp(fword, "book") == 0) lv = 2;
if (strcmp(fword, "part") == 0) lv = 3;
if (strcmp(fword, "chapter") == 0) lv = 4;
if (strcmp(fword, "section") == 0) lv = 5;
if (strcmp(fword, "----") == 0) {
extract_word(fword, line, 32, 2);
if (strcmp(fword, "documentation") == 0) {
extract_word(fword, line, 32, 3);
if (strcmp(fword, "----") == 0) lv = DOC_LEVEL;
}
}
}
}
#line 362 "cBlorb/Chapter 3/Website Maker.w"
;
if ((scan_comment_nesting > 0) && (lv != EMPTY_LEVEL)) lv = DULL_LEVEL;
{
#line 412 "cBlorb/Chapter 3/Website Maker.w"
int i;
for (i=0; line[i]; i++) {
if (line[i] == '[') scan_comment_nesting++;
if (line[i] == ']') scan_comment_nesting--;
if ((scan_comment_nesting == 0) && (line[i] == '\"'))
scan_quoted_matter = (scan_quoted_matter)?FALSE:TRUE;
}
}
#line 364 "cBlorb/Chapter 3/Website Maker.w"
;
if ((lv == DULL_LEVEL) && (current_heading)) current_heading->heading_has_content = TRUE;
if ((lv == EMPTY_LEVEL) && (within_a_table))
{
#line 432 "cBlorb/Chapter 3/Website Maker.w"
current_table->table_line_end = lc;
within_a_table = FALSE;
return;
}
#line 366 "cBlorb/Chapter 3/Website Maker.w"
;
if (lv == TABLE_LEVEL)
{
#line 423 "cBlorb/Chapter 3/Website Maker.w"
current_table = CREATE(table);
current_table->table_line_start = lc;
current_table->table_line_end = MAX_SOURCE_TEXT_LINES;
within_a_table = TRUE;
return;
}
#line 367 "cBlorb/Chapter 3/Website Maker.w"
;
if ((lv == EMPTY_LEVEL) || (lv == DULL_LEVEL)) return;
if (lv == DOC_LEVEL) position_of_documentation_bar = lc;
{
#line 439 "cBlorb/Chapter 3/Website Maker.w"
heading *new_h = CREATE(heading);
strncpy(new_h->heading_text, line, ABBREVIATED_HEADING_LENGTH);
(new_h->heading_text)[ABBREVIATED_HEADING_LENGTH] = 0;
new_h->heading_level = lv;
new_h->heading_line = lc;
new_h->heading_has_content = FALSE;
if ((current_heading == NULL) || (current_heading->heading_has_content) ||
(lv == DOC_LEVEL)) {
if (current_segment) current_segment->ends_at = lc - 1;
current_segment = CREATE(segment);
current_segment->begins_at = lc;
current_segment->ends_at = MAX_SOURCE_TEXT_LINES;
current_segment->start_position_in_file = *latest_line_position;
current_segment->most_recent_heading = current_heading;
current_segment->most_recent_table = current_table;
current_segment->documentation = FALSE;
if (lc >= position_of_documentation_bar) current_segment->documentation = TRUE;
}
new_h->heading_to_segment = current_segment;
current_heading = new_h;
}
#line 370 "cBlorb/Chapter 3/Website Maker.w"
;
}
#line 467 "cBlorb/Chapter 3/Website Maker.w"
segment *segment_being_written = NULL;
int no_doc_files = 0, no_src_files = 0;
void write_source_text_pages(char *template, char *website_pathname) {
char contents_page[MAX_FILENAME_LENGTH];
sprintf(contents_page, "%s%c%s.html", website_pathname, SEP_CHAR,
read_placeholder("SOURCEPREFIX"));
char *contents_leafname = get_filename_leafname(contents_page);
{
#line 486 "cBlorb/Chapter 3/Website Maker.w"
segment *seg;
LOOP_OVER(seg, segment) {
segment_being_written = seg;
if (seg->documentation) {
sprintf(seg->segment_url, "doc_%d.html", no_doc_files++);
seg->page_number = no_doc_files;
} else {
sprintf(seg->segment_url, "%s_%d.html",
read_placeholder("SOURCEPREFIX"), no_src_files++);
seg->page_number = no_src_files;
}
}
}
#line 475 "cBlorb/Chapter 3/Website Maker.w"
;
{
#line 502 "cBlorb/Chapter 3/Website Maker.w"
segment *seg, *first_doc_seg = NULL, *first_src_seg = NULL;
LOOP_OVER(seg, segment) {
if (seg->documentation) {
seg->link_home = NULL;
seg->link_contents = NULL;
seg->link_previous = NULL;
seg->link_next = NULL;
if (first_doc_seg == NULL) first_doc_seg = seg;
} else {
seg->link_home = NULL;
seg->link_contents = NULL;
seg->link_previous = NULL;
seg->link_next = NULL;
if (first_src_seg == NULL) {
first_src_seg = seg;
seg->link_previous = contents_leafname;
}
}
}
LOOP_OVER(seg, segment) {
if (seg->documentation) {
seg->link_home = "index.html";
seg->link_contents = first_doc_seg->segment_url;
} else {
seg->link_home = "index.html";
seg->link_contents = contents_leafname;
}
segment *before = seg;
while (TRUE) {
before = PREV_OBJECT(before, segment);
if (before == NULL) break;
if (before->documentation == seg->documentation) {
seg->link_previous = before->segment_url; break;
}
}
segment *after = seg;
while (TRUE) {
after = NEXT_OBJECT(after, segment);
if (after == NULL) break;
if (after->documentation == seg->documentation) {
seg->link_next = after->segment_url; break;
}
}
}
}
#line 476 "cBlorb/Chapter 3/Website Maker.w"
;
{
#line 550 "cBlorb/Chapter 3/Website Maker.w"
segment_being_written = NULL;
source_HTML_pages_created++;
web_copy(template, contents_page);
}
#line 477 "cBlorb/Chapter 3/Website Maker.w"
;
{
#line 557 "cBlorb/Chapter 3/Website Maker.w"
segment *seg;
LOOP_OVER(seg, segment) {
char segment_page[MAX_FILENAME_LENGTH];
sprintf(segment_page, "%s%c%s", website_pathname, SEP_CHAR, seg->segment_url);
segment_being_written = seg;
source_HTML_pages_created++;
web_copy(template, segment_page);
segment_being_written = NULL;
}
}
#line 478 "cBlorb/Chapter 3/Website Maker.w"
;
}
#line 570 "cBlorb/Chapter 3/Website Maker.w"
void expand_PAGENUMBER_variable(FILE *COPYTO) {
int p = 1;
if (segment_being_written) {
p = segment_being_written->page_number;
if (segment_being_written->documentation == FALSE) p++; /* allow for header page */
}
fprintf(COPYTO, "%d", p);
}
#line 582 "cBlorb/Chapter 3/Website Maker.w"
void expand_PAGEEXTENT_variable(FILE *COPYTO) {
int n = no_src_files + 1;
if ((segment_being_written) && (segment_being_written->documentation))
n = no_doc_files;
if (n == 0) n = 1;
fprintf(COPYTO, "%d", n);
}
#line 593 "cBlorb/Chapter 3/Website Maker.w"
void expand_SOURCELINKS_variable(FILE *COPYTO) {
segment *seg = segment_being_written;
if (seg) {
if (seg->link_home)
fprintf(COPYTO, "<li><a href=\"%s\">Home page</a></li>", seg->link_home);
if (seg->link_contents)
fprintf(COPYTO, "<li><a href=\"%s\">Beginning</a></li>", seg->link_contents);
if (seg->link_previous)
fprintf(COPYTO, "<li><a href=\"%s\">Previous</a></li>", seg->link_previous);
if (seg->link_next)
fprintf(COPYTO, "<li><a href=\"%s\">Next</a></li>", seg->link_next);
} else {
fprintf(COPYTO, "<li><a href=\"index.html\">Home page</a></li>");
fprintf(COPYTO, "<li><a href=\"%s.txt\">Complete text</a></li>",
read_placeholder("SOURCEPREFIX"));
}
}
#line 617 "cBlorb/Chapter 3/Website Maker.w"
FILE *SPAGE = NULL; /* where the output is going */
int SOURCENOTES_mode = FALSE; /* |TRUE| for "[SOURCENOTES]", |FALSE| for "[SOURCE]" */
int quoted_matter = FALSE; /* are we inside double-quoted matter in the source text? */
int i6_matter = FALSE; /* are we inside verbatim I6 code in the source text? */
int comment_nesting = 0; /* nesting level of comments in source text being read: 0 for not in a comment */
int footnote_comment_level = 0; /* ditto, but where the outermost comment is a footnote marker */
int carry_over_indentation = -1; /* indentation carried over for para breaks in quoted text */
int next_footnote_number = 1; /* number to assign to the next footnote which comes up */
heading *latest_heading = NULL; /* a heading which is always behind the current position */
table *latest_table = NULL; /* a table which is always behind the current position */
#line 632 "cBlorb/Chapter 3/Website Maker.w"
void expand_SOURCE_or_SOURCENOTES_variable(FILE *write_to, int SN) {
if (SN)
{
#line 660 "cBlorb/Chapter 3/Website Maker.w"
if (next_footnote_number == 1) return; /* there were no footnotes at all */
fprintf(write_to, "<p>");
open_style(write_to, "notesheading");
if (next_footnote_number == 2) fprintf(write_to, "Note"); /* just one */
else fprintf(write_to, "Notes"); /* more than one */
close_style(write_to, "notesheading");
fprintf(write_to, "</p>\n");
}
#line 633 "cBlorb/Chapter 3/Website Maker.w"
;
open_code(write_to);
{
#line 643 "cBlorb/Chapter 3/Website Maker.w"
next_footnote_number = 1;
SPAGE = write_to;
SOURCENOTES_mode = SN;
quoted_matter = FALSE;
i6_matter = FALSE;
comment_nesting = 0;
footnote_comment_level = 0;
carry_over_indentation = -1;
current_style = NULL;
latest_heading = FIRST_OBJECT(heading);
latest_table = FIRST_OBJECT(table);
}
#line 635 "cBlorb/Chapter 3/Website Maker.w"
;
{
#line 684 "cBlorb/Chapter 3/Website Maker.w"
text_file_position *start = NULL;
if (segment_being_written)
{
#line 692 "cBlorb/Chapter 3/Website Maker.w"
start = &(segment_being_written->start_position_in_file);
if (segment_being_written->most_recent_heading)
latest_heading = segment_being_written->most_recent_heading;
if (segment_being_written->most_recent_table)
latest_table = segment_being_written->most_recent_table;
}
#line 685 "cBlorb/Chapter 3/Website Maker.w"
;
file_read(source_text, "can't open source text", TRUE, source_write_iterator, start);
}
#line 636 "cBlorb/Chapter 3/Website Maker.w"
;
close_code(write_to);
}
#line 701 "cBlorb/Chapter 3/Website Maker.w"
void source_write_iterator(char *line, text_file_position *tfp) {
int done_yet = write_source_line(line, tfp);
if (done_yet) tfp_lose_interest(tfp);
}
#line 715 "cBlorb/Chapter 3/Website Maker.w"
int write_source_line(char *line, text_file_position *tfp) {
int line_count = tfp_get_line_count(tfp);
if (segment_being_written == NULL)
{
#line 737 "cBlorb/Chapter 3/Website Maker.w"
segment *first_segment = FIRST_OBJECT(segment);
if ((first_segment) && (line_count == first_segment->begins_at - 1) && (line[0] == 0))
return FALSE; /* don't bother to typeset a blank line just before the first segment is reached */
if ((first_segment) && (line_count == first_segment->begins_at)) {
if (SOURCENOTES_mode == FALSE) typeset_contents_listing(TRUE);
return TRUE;
}
}
#line 717 "cBlorb/Chapter 3/Website Maker.w"
else
{
#line 751 "cBlorb/Chapter 3/Website Maker.w"
if (line_count < segment_being_written->begins_at) return FALSE;
if (line_count > segment_being_written->ends_at) return TRUE;
if (line_count == position_of_documentation_bar + 1)
typeset_contents_listing(FALSE);
}
#line 718 "cBlorb/Chapter 3/Website Maker.w"
;
if (SOURCENOTES_mode)
{
#line 761 "cBlorb/Chapter 3/Website Maker.w"
int i;
for (i=0; line[i]; i++) {
if ((line[i] == '[') && (line[i+1] == '*')) {
footnote_comment_level = 1;
fprintf(SPAGE, "<p><a name=\"note%d\"></a>", next_footnote_number);
open_style(SPAGE, "notetext");
fprintf(SPAGE, "<a href=\"#note%dref\">[%d]</a>. ",
next_footnote_number, next_footnote_number);
next_footnote_number++;
i+=2;
}
if (footnote_comment_level > 0) {
if (line[i] == '[') footnote_comment_level++;
if (line[i] == ']') footnote_comment_level--;
if (footnote_comment_level == 0) {
close_style(SPAGE, "notetext");
fprintf(SPAGE, "</p>\n");
} else {
fprintf(SPAGE, "%c", line[i]);
}
}
}
if (footnote_comment_level > 0) fprintf(SPAGE, " ");
}
#line 719 "cBlorb/Chapter 3/Website Maker.w"
else
{
#line 789 "cBlorb/Chapter 3/Website Maker.w"
int embolden = FALSE, tabulate = FALSE, underline = FALSE;
{
#line 858 "cBlorb/Chapter 3/Website Maker.w"
while ((latest_table) && (latest_table->table_line_end < line_count))
latest_table = NEXT_OBJECT(latest_table, table);
if (latest_table) {
int from = latest_table->table_line_start, to = latest_table->table_line_end;
if (line_count == from) {
embolden = TRUE;
} else if ((line_count > from) && (line_count < to)) {
tabulate = TRUE;
if (line_count == from + 1) {
underline = TRUE;
fprintf(SPAGE, "<table>");
}
} else if (line_count == to) {
fprintf(SPAGE, "</table>");
}
}
}
#line 790 "cBlorb/Chapter 3/Website Maker.w"
;
{
#line 878 "cBlorb/Chapter 3/Website Maker.w"
if ((line_count == 1) ||
((segment_being_written) && (line_count == segment_being_written->begins_at)))
embolden = TRUE;
}
#line 791 "cBlorb/Chapter 3/Website Maker.w"
;
{
#line 886 "cBlorb/Chapter 3/Website Maker.w"
while ((latest_heading) && (latest_heading->heading_line < line_count))
latest_heading = NEXT_OBJECT(latest_heading, heading);
if ((latest_heading) && (latest_heading->heading_line == line_count))
embolden = TRUE;
}
#line 792 "cBlorb/Chapter 3/Website Maker.w"
;
if ((tabulate) && (quoted_matter == FALSE)) { fprintf(SPAGE, "<tr>"); open_table_cell(SPAGE); }
int start = 0;
if (footnote_comment_level > 0) {
for (; line[start]; start++) {
if (line[start] == '[') footnote_comment_level++;
if (line[start] == ']') footnote_comment_level--;
if (footnote_comment_level == 0) { start++; break; }
}
}
if ((footnote_comment_level == 0) && (line[start])) {
if (tabulate == FALSE) {
int insteps = 0;
for (; line[start] == '\t'; start++) insteps++;
if (carry_over_indentation < 0) carry_over_indentation = insteps;
open_code_paragraph(SPAGE, carry_over_indentation);
}
{
#line 828 "cBlorb/Chapter 3/Website Maker.w"
if (underline) open_style(SPAGE, "columnhead");
if (embolden) open_style(SPAGE, "heading");
if (current_style) open_style(SPAGE, current_style);
}
#line 813 "cBlorb/Chapter 3/Website Maker.w"
;
{
#line 894 "cBlorb/Chapter 3/Website Maker.w"
if ((comment_nesting == 0) && (quoted_matter == FALSE) && (i6_matter == FALSE) &&
(line[start] == '*') && (line[start+1] == ':') && (line[start+2] == ' '))
start += 3;
if (line_count == position_of_documentation_bar) strcpy(line, "Documentation");
}
#line 814 "cBlorb/Chapter 3/Website Maker.w"
;
int i; for (i=start; line[i]; i++)
{
#line 905 "cBlorb/Chapter 3/Website Maker.w"
switch (line[i]) {
case '\t':
/* a multiple tab is equivalent to a single tab in Inform source text */
while (line[i+1] == '\t') i++;
{
#line 945 "cBlorb/Chapter 3/Website Maker.w"
if (tabulate) {
{
#line 835 "cBlorb/Chapter 3/Website Maker.w"
if (current_style) close_style(SPAGE, current_style);
if (embolden) close_style(SPAGE, "heading");
if (underline) close_style(SPAGE, "columnhead");
}
#line 946 "cBlorb/Chapter 3/Website Maker.w"
;
close_table_cell(SPAGE);
open_table_cell(SPAGE);
{
#line 828 "cBlorb/Chapter 3/Website Maker.w"
if (underline) open_style(SPAGE, "columnhead");
if (embolden) open_style(SPAGE, "heading");
if (current_style) open_style(SPAGE, current_style);
}
#line 949 "cBlorb/Chapter 3/Website Maker.w"
;
} else {
fprintf(SPAGE, " ");
}
}
#line 909 "cBlorb/Chapter 3/Website Maker.w"
;
break;
case '"':
if ((comment_nesting > 0) || (i6_matter)) fprintf(SPAGE, "&quot;");
else
{
#line 963 "cBlorb/Chapter 3/Website Maker.w"
if (quoted_matter) change_style(SPAGE, NULL);
fprintf(SPAGE, "&quot;");
if (quoted_matter == FALSE) change_style(SPAGE, "quote");
quoted_matter = (quoted_matter)?FALSE:TRUE;
}
#line 913 "cBlorb/Chapter 3/Website Maker.w"
;
break;
case '[':
if (quoted_matter) { fprintf(SPAGE, "["); change_style(SPAGE, "substitution"); }
else if (i6_matter) fprintf(SPAGE, "[");
else
{
#line 973 "cBlorb/Chapter 3/Website Maker.w"
if (line[i+1] == '*') {
/* advance past the end of the asterisked comment */
footnote_comment_level++;
for (i+=2; line[i]; ++i) {
if (line[i] == '[') footnote_comment_level++;
if (line[i] == ']') footnote_comment_level--;
if (footnote_comment_level == 0) break;
}
if (line[i] == 0) i--;
{
#line 1016 "cBlorb/Chapter 3/Website Maker.w"
fprintf(SPAGE, "<a name=\"note%dref\"></a>", next_footnote_number);
open_style(SPAGE, "notecue");
fprintf(SPAGE, "<a href=\"#note%d\">[%d]</a>",
next_footnote_number, next_footnote_number);
close_style(SPAGE, "notecue");
next_footnote_number++;
}
#line 982 "cBlorb/Chapter 3/Website Maker.w"
;
} else {
comment_nesting++;
if (comment_nesting == 1) change_style(SPAGE, "comment");
fprintf(SPAGE, "[");
}
}
#line 918 "cBlorb/Chapter 3/Website Maker.w"
;
break;
case ']':
if (quoted_matter) { change_style(SPAGE, "quote"); fprintf(SPAGE, "]"); }
else if (i6_matter) fprintf(SPAGE, "]");
else
{
#line 992 "cBlorb/Chapter 3/Website Maker.w"
fprintf(SPAGE, "]");
comment_nesting--;
if (comment_nesting == 0) change_style(SPAGE, NULL);
}
#line 923 "cBlorb/Chapter 3/Website Maker.w"
;
break;
case '(':
if ((comment_nesting == 0) && (quoted_matter == FALSE) && (i6_matter == FALSE) &&
(line[i+1] == '-')) { i++;
{
#line 1000 "cBlorb/Chapter 3/Website Maker.w"
fprintf(SPAGE, "(-");
change_style(SPAGE, "i6code");
i6_matter = TRUE;
}
#line 928 "cBlorb/Chapter 3/Website Maker.w"
} else fprintf(SPAGE, "("); break;
case '-':
if ((i6_matter) && (line[i+1] == ')')) { i++;
{
#line 1007 "cBlorb/Chapter 3/Website Maker.w"
change_style(SPAGE, NULL);
fprintf(SPAGE, "-)");
i6_matter = FALSE;
}
#line 932 "cBlorb/Chapter 3/Website Maker.w"
} else fprintf(SPAGE, "-"); break;
case '<': fprintf(SPAGE, "&lt;"); break;
case '>': fprintf(SPAGE, "&gt;"); break;
case '&': fprintf(SPAGE, "&amp;"); break;
default: fprintf(SPAGE, "%c", line[i]); break;
}
}
#line 816 "cBlorb/Chapter 3/Website Maker.w"
;
{
#line 835 "cBlorb/Chapter 3/Website Maker.w"
if (current_style) close_style(SPAGE, current_style);
if (embolden) close_style(SPAGE, "heading");
if (underline) close_style(SPAGE, "columnhead");
}
#line 818 "cBlorb/Chapter 3/Website Maker.w"
;
if ((tabulate) && (quoted_matter == FALSE)) { close_table_cell(SPAGE); fprintf(SPAGE, "</tr>\n"); }
else close_code_paragraph(SPAGE);
if (quoted_matter == FALSE) carry_over_indentation = -1;
}
}
#line 720 "cBlorb/Chapter 3/Website Maker.w"
;
return FALSE;
}
#line 1027 "cBlorb/Chapter 3/Website Maker.w"
void typeset_contents_listing(int source_contents) {
int benchmark_level = (source_contents)?0:DOC_CHAPTER_LEVEL;
int current_level = benchmark_level-1, new_level;
heading *h;
LOOP_OVER(h, heading)
if (((source_contents) && (h->heading_line < position_of_documentation_bar)) ||
((source_contents == FALSE) && (h->heading_line > position_of_documentation_bar))) {
new_level = h->heading_level;
if (h->heading_level == EXAMPLE_LEVEL) new_level = DOC_CHAPTER_LEVEL;
{
#line 1052 "cBlorb/Chapter 3/Website Maker.w"
while (new_level > current_level) { fprintf(SPAGE, "<ul>"); current_level++; }
while (new_level < current_level) { fprintf(SPAGE, "</ul>"); current_level--; }
}
#line 1036 "cBlorb/Chapter 3/Website Maker.w"
;
fprintf(SPAGE, "<li><a href=\"%s\">%s</a></li>\n",
h->heading_to_segment->segment_url, h->heading_text);
}
new_level = benchmark_level-1;
{
#line 1052 "cBlorb/Chapter 3/Website Maker.w"
while (new_level > current_level) { fprintf(SPAGE, "<ul>"); current_level++; }
while (new_level < current_level) { fprintf(SPAGE, "</ul>"); current_level--; }
}
#line 1041 "cBlorb/Chapter 3/Website Maker.w"
;
}
#line 24 "cBlorb/Chapter 3/Base64.w"
char *RFC1113_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
#line 29 "cBlorb/Chapter 3/Base64.w"
void encode_as_base64(char *in_filename, char *out_filename, char *top, char *tail) {
FILE *IN = fopen(in_filename, "rb");
if (IN == NULL)
fatal_fs("can't open story file for base-64 encoding", in_filename);
FILE *OUT = fopen(out_filename, "w"); /* a text file, not binary */
if (OUT == NULL)
fatal_fs("can't open base-64 encoded story file for output", out_filename);
if (top) fprintf(OUT, "%s", top);
while (TRUE) {
int triplet[3], triplet_size = 0;
{
#line 55 "cBlorb/Chapter 3/Base64.w"
triplet[0] = fgetc(IN);
if (triplet[0] != EOF) {
triplet_size++;
triplet[1] = fgetc(IN);
if (triplet[1] != EOF) {
triplet_size++;
triplet[2] = fgetc(IN);
if (triplet[2] != EOF)
triplet_size++;
}
}
int i; for (i=triplet_size; i<3; i++) triplet[i] = 0;
}
#line 40 "cBlorb/Chapter 3/Base64.w"
;
if (triplet_size == 0) break;
int quartet[4];
{
#line 71 "cBlorb/Chapter 3/Base64.w"
int i; for (i=0; i<4; i++) quartet[i] = 0;
quartet[0] += (triplet[0] & 0xFC) >> 2;
quartet[1] += (triplet[0] & 0x03) << 4;
quartet[1] += (triplet[1] & 0xF0) >> 4;
quartet[2] += (triplet[1] & 0x0F) << 2;
quartet[2] += (triplet[2] & 0xC0) >> 6;
quartet[3] += (triplet[2] & 0x3F) << 0;
switch (triplet_size) {
case 1: quartet[2] = 64; quartet[3] = 64; break;
case 2: quartet[3] = 64; break;
}
}
#line 43 "cBlorb/Chapter 3/Base64.w"
;
int i; for (i=0; i<4; i++) fputc(RFC1113_table[quartet[i]], OUT);
if (triplet_size < 3) break;
}
if (tail) fprintf(OUT, "%s", tail);
fclose(IN); fclose(OUT);
}