/* Tangled output generated by inweb-C: do not edit */ #include #include #include #include #include #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 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 273 "cBlorb/Chapter 1/Text Files.w" char * get_filename_extension(char *filename) ; #line 280 "cBlorb/Chapter 1/Text Files.w" char * get_filename_leafname(char *filename) ; #line 286 "cBlorb/Chapter 1/Text Files.w" int file_exists(char *filename) ; #line 292 "cBlorb/Chapter 1/Text Files.w" long int file_size(char *filename) ; #line 306 "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 333 "cBlorb/Chapter 2/Blorb Writer.w" void picture_chunk_text(char *name, char *fn) ; #line 351 "cBlorb/Chapter 2/Blorb Writer.w" void sound_chunk(int n, char *fn, char *alt) ; #line 373 "cBlorb/Chapter 2/Blorb Writer.w" void sound_chunk_text(char *name, char *fn) ; #line 389 "cBlorb/Chapter 2/Blorb Writer.w" void add_rdes_record(int usage, int n, char *alt) ; #line 401 "cBlorb/Chapter 2/Blorb Writer.w" void rdes_chunk(void) ; #line 427 "cBlorb/Chapter 2/Blorb Writer.w" void executable_chunk(char *fn) ; #line 441 "cBlorb/Chapter 2/Blorb Writer.w" void metadata_chunk(char *fn) ; #line 448 "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 || 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 || 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:

    [CBLORBERRORS]
", 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 Release > Open Materials Folder or by clicking " "the blue folders above.

" "Releases can range in size from a single blorb file to a medium-sized website. " "Here's what we currently have:

", 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= 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; ithe_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", "

  • "); append_to_placeholder("CBLORBERRORS", err); append_to_placeholder("CBLORBERRORS", "
  • "); 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 273 "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] != SEP_CHAR)) i--; if ((i<0) || (filename[i] == SEP_CHAR)) return filename + cblorb_strlen(filename); return filename + i; } 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; idata_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 *p = get_filename_extension(fn); char *type = "PNG "; if (n < 1) fatal("Picture resource number is less than 1"); if (resource_seen(&pict_resource, n)) fatal("Duplicate Picture resource number"); if (*p == '.') { p++; if ((*p == 'j') || (*p == 'J')) type = "JPEG"; } add_chunk_to_blorb(type, n, fn, "Pict", NULL, 0); if ((alt) && (alt[0])) add_rdes_record(1, n, alt); no_pictures_included++; } #line 333 "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 351 "cBlorb/Chapter 2/Blorb Writer.w" void sound_chunk(int n, char *fn, char *alt) { char *p = get_filename_extension(fn); char *type = "AIFF"; if (n < 3) fatal("Sound resource number is less than 3"); if (resource_seen(&sound_resource, n)) fatal("Duplicate Sound resource number"); if (*p == '.') { p++; if ((*p == 'o') || (*p == 'O')) type = "OGGV"; else if ((*p == 'm') || (*p == 'M')) { if ((p[1] == 'i') || (p[1] == 'I')) type = "MIDI"; else type = "MOD "; } } add_chunk_to_blorb(type, n, fn, "Snd ", NULL, 0); if ((alt) && (alt[0])) add_rdes_record(2, n, alt); no_sounds_included++; } #line 373 "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 387 "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 427 "cBlorb/Chapter 2/Blorb Writer.w" void executable_chunk(char *fn) { char *p = get_filename_extension(fn); char *type = "ZCOD"; if (*p == '.') { if (p[cblorb_strlen(p)-1] == 'x') type = "GLUL"; } add_chunk_to_blorb(type, 0, fn, "Exec", NULL, 0); } #line 441 "cBlorb/Chapter 2/Blorb Writer.w" void metadata_chunk(char *fn) { add_chunk_to_blorb("IFmd", 0, fn, NULL, NULL, 0); } #line 448 "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 479 "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 456 "cBlorb/Chapter 2/Blorb Writer.w" ; { #line 494 "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 457 "cBlorb/Chapter 2/Blorb Writer.w" ; if (trace_mode) { #line 559 "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 458 "cBlorb/Chapter 2/Blorb Writer.w" ; chunk_metadata *chunk; LOOP_OVER(chunk, chunk_metadata) { #line 515 "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 550 "cBlorb/Chapter 2/Blorb Writer.w" int i; for (i=0; idata_in_memory[i]); one_byte(IFF, j); } } #line 526 "cBlorb/Chapter 2/Blorb Writer.w" else { #line 535 "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; ifilename); one_byte(IFF, j); } fclose(CHUNKSUB); } } #line 528 "cBlorb/Chapter 2/Blorb Writer.w" ; if ((bytes_to_copy % 2) == 1) one_byte(IFF, 0); /* as we allowed for above */ } #line 461 "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 (strcmp(get_filename_extension(name), ".html") == 0) { #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, "
  • "); download_link(COPYTO, "Play In-Browser", NULL, "play.html", "link"); fprintf(COPYTO, "
  • "); break; case SOURCE_REQ: fprintf(COPYTO, "
  • "); download_link(COPYTO, "Source Text", NULL, "source.html", "link"); fprintf(COPYTO, "
  • "); break; case SOLUTION_REQ: fprintf(COPYTO, "
  • "); download_link(COPYTO, "Solution", NULL, "solution.txt", "link"); fprintf(COPYTO, "
  • "); break; case IFICTION_REQ: fprintf(COPYTO, "
  • "); download_link(COPYTO, "Library Card", NULL, "iFiction.xml", "link"); fprintf(COPYTO, "
  • "); 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, "
      "); { #line 500 "cBlorb/Chapter 3/Releaser.w" if ((no_pictures_included > 1) || (no_sounds_included > 0)) append_to_placeholder(ph, "
    • The blorb file [STORYFILE] ([BLORBFILESIZE]K in size, " "including [BLORBFILEPICTURES] figures(s) and [BLORBFILESOUNDS] " "sound(s))
    • "); else append_to_placeholder(ph, "
    • The blorb file [STORYFILE] ([BLORBFILESIZE]K in size)
    • "); } #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, "
    • 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, "
    • "); 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, "
    • A play-in-browser page (generated from the [INTERPRETER] interpreter)
    • "); } } #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, "
    • The library card (stored as an iFiction record)
    • "); } #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, "
    • A solution file
    • "); } #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, "
    • 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, ")
    • "); } } if (count_requests_of_type(RELEASE_SOURCE_REQ) > 0) append_to_placeholder(ph, "
    • The source text (as part of the website)
    • "); } #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, "
    • The following additional file(s):
        "); request *req; LOOP_OVER(req, request) if (req->what_is_requested == COPY_REQ) { char *leafname = req->details2; append_to_placeholder(ph, "
      • "); 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, "
      • "); } append_to_placeholder(ph, "
    • "); } } #line 488 "cBlorb/Chapter 3/Releaser.w" ; append_to_placeholder(ph, "
    "); if ((launch_website) || (launch_play)) { #line 599 "cBlorb/Chapter 3/Releaser.w" append_to_placeholder(ph, "

    "); if (launch_website) { append_to_placeholder(ph, "" " home page"); } if ((launch_website) && (launch_play)) append_to_placeholder(ph, " : "); if (launch_play) { append_to_placeholder(ph, "" " play-in-browser page"); } append_to_placeholder(ph, "

    "); } #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, "

    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, ".

    "); } #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, "

    Here are some other possibilities you might want to consider:

      "); append_to_placeholder(ph, "
    • "); append_to_placeholder(ph, req->details1); append_to_placeholder(ph, "
    • "); count++; } if (count > 0) append_to_placeholder(ph, "

    "); } #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, "%[^>]>%[^<]= 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, "<") == 0) c = '<'; if (strcmp(xml_escape, ">") == 0) c = '>'; if (strcmp(xml_escape, "&") == 0) c = '&'; if (strcmp(xml_escape, "'") == 0) c = '\''; if (strcmp(xml_escape, """) == 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, "
  • "); download_link(COPYTO, aux->description, aux->full_filename, aux->aux_leafname, aux->format); fprintf(COPYTO, "
  • "); } } 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, "%s ", 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 = " 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, ", %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, "", 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, "

    "); 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, "

    "); 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, "

    "); continue; } if ((escape_quotes_mode == 1) && (p[i] == '\'')) fprintf(COPYTO, "'"); 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, "

    "); 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, "", new); } else { if (strcmp(new, "columnhead") == 0) fprintf(write_to, ""); if (strcmp(new, "comment") == 0) fprintf(write_to, ""); if (strcmp(new, "filetype") == 0) fprintf(write_to, ""); if (strcmp(new, "heading") == 0) fprintf(write_to, ""); if (strcmp(new, "i6code") == 0) fprintf(write_to, ""); if (strcmp(new, "notecue") == 0) fprintf(write_to, ""); if (strcmp(new, "notesheading") == 0) fprintf(write_to, ""); if (strcmp(new, "notetext") == 0) fprintf(write_to, ""); if (strcmp(new, "quote") == 0) fprintf(write_to, ""); if (strcmp(new, "substitution") == 0) fprintf(write_to, ""); } } void close_style(FILE *write_to, char *old) { if (old == NULL) return; if (use_css_code_styles) { fprintf(write_to, ""); } else { if (strcmp(old, "columnhead") == 0) fprintf(write_to, ""); if (strcmp(old, "comment") == 0) fprintf(write_to, ""); if (strcmp(old, "filetype") == 0) fprintf(write_to, ""); if (strcmp(old, "heading") == 0) fprintf(write_to, ""); if (strcmp(old, "i6code") == 0) fprintf(write_to, ""); if (strcmp(old, "notecue") == 0) fprintf(write_to, ""); if (strcmp(old, "notesheading") == 0) fprintf(write_to, ""); if (strcmp(old, "notetext") == 0) fprintf(write_to, ""); if (strcmp(old, "quote") == 0) fprintf(write_to, ""); if (strcmp(old, "substitution") == 0) fprintf(write_to, ""); } } #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, "

    "); } } void close_code(FILE *write_to) { if (use_css_code_styles == FALSE) { fprintf(write_to, "

    "); } } #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, "

    ", classname); } else { int i; for (i=0; i"); } else { fprintf(write_to, "
    "); } } #line 216 "cBlorb/Chapter 3/Website Maker.w" void open_table_cell(FILE *write_to) { if (use_css_code_styles) { fprintf(write_to, ""); } else { fprintf(write_to, ""); } } void close_table_cell(FILE *write_to) { if (use_css_code_styles) { fprintf(write_to, ""); } else { fprintf(write_to, "  "); } } #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, "

  • Home page
  • ", seg->link_home); if (seg->link_contents) fprintf(COPYTO, "
  • Beginning
  • ", seg->link_contents); if (seg->link_previous) fprintf(COPYTO, "
  • Previous
  • ", seg->link_previous); if (seg->link_next) fprintf(COPYTO, "
  • Next
  • ", seg->link_next); } else { fprintf(COPYTO, "
  • Home page
  • "); fprintf(COPYTO, "
  • Complete text
  • ", 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, "

    "); 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, "

    \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, "

    ", next_footnote_number); open_style(SPAGE, "notetext"); fprintf(SPAGE, "[%d]. ", 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, "

    \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, ""); } } else if (line_count == to) { fprintf(SPAGE, "
    "); } } } #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, ""); 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, """); else { #line 963 "cBlorb/Chapter 3/Website Maker.w" if (quoted_matter) change_style(SPAGE, NULL); fprintf(SPAGE, """); 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, "", next_footnote_number); open_style(SPAGE, "notecue"); fprintf(SPAGE, "[%d]", 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, "<"); break; case '>': fprintf(SPAGE, ">"); break; case '&': fprintf(SPAGE, "&"); 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, "\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, "
      "); current_level++; } while (new_level < current_level) { fprintf(SPAGE, "
    "); current_level--; } } #line 1036 "cBlorb/Chapter 3/Website Maker.w" ; fprintf(SPAGE, "
  • %s
  • \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, "
      "); current_level++; } while (new_level < current_level) { fprintf(SPAGE, "
    "); 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); }