Exemplo n.º 1
0
/* Given a GString containing MMD source, and optional base directory,
	substitute transclusion references in the source 

	Pass the path to the current folder if available -- should be a full path. 

	Keep track of what we're parsing to prevent recursion using stack. */
void transclude_source(GString *source, char *basedir, char *stack, int output_format, GString *manifest) {
	char *base = NULL;
	char *path = NULL;
	char *start;
	char *stop;
	char *temp;
	int curchar;
	size_t pos;
	char real[1000];
	FILE *input;
	long offset;

	if (basedir == NULL) {
		base = strdup("");
	} else {
		base = strdup(basedir);
	}

	GString *folder = NULL;
	GString *filename = NULL;
	GString *filebuffer = NULL;
	GString *stackstring = NULL;

	path = strdup(base);

	/* Look for override folder inside document */
	if (has_metadata(source->str, 0x000000)) {
		char *meta = extract_metadata_value(source->str, 0x000000, "transcludebase");
		if (meta != NULL)
			path = path_from_dir_base(base, meta);
	}

	if (path == NULL) {
		/* We have nowhere to look, so nothing to do */
		free(path);
		free(base);
		return;
	}

	folder = g_string_new(path);

	/* Ensure that folder ends in "/" */
	/* TODO: adjust for windows */
	if (!(folder->str[strlen(folder->str)-1] == '/') ) {
		g_string_append_c(folder, '/');
	}

	/* fprintf(stderr, "Transclude using '%s'\n", folder->str); */

	/* Iterate through {{foo.txt}} and substitute contents of file without metadata */

	start = strstr(source->str,"{{");

	while (start != NULL) {
		stop = strstr(start,"}}");
		if (stop == NULL)
			break;

		/* Check that we found something reasonable -- we cap at 1000 characters */
        if (stop - start < 1000) {
			strncpy(real,start+2,stop-start-2);
			real[stop-start-2] = '\0';

			if (is_separator(real[0])) {
				filename = g_string_new(real);
			} else {
				filename = g_string_new(folder->str);
				g_string_append_printf(filename, "%s",real);
			}

			if (strcmp(filename->str,"./TOC") == 0) {
				pos = stop - source->str;
				start = strstr(source->str + pos,"{{");
				g_string_free(filename, true);
				continue;
			}

			/* Adjust for wildcard extensions */
			/* But not if output_format == 0 */
			if (output_format && strncmp(&filename->str[strlen(filename->str) - 2],".*",2) == 0) {
				g_string_erase(filename, strlen(filename->str) - 2, 2);
				if (output_format == TEXT_FORMAT) {
					g_string_append(filename,".txt");
				} else if (output_format == HTML_FORMAT) {
					g_string_append(filename,".html");
				} else if (output_format == LATEX_FORMAT) {
					g_string_append(filename,".tex");
				} else if (output_format == BEAMER_FORMAT) {
					g_string_append(filename,".tex");
				} else if (output_format == MEMOIR_FORMAT) {
					g_string_append(filename,".tex");
				} else if (output_format == ODF_FORMAT) {
					g_string_append(filename,".fodt");
				} else if (output_format == OPML_FORMAT) {
					g_string_append(filename,".opml");
				} else if (output_format == LYX_FORMAT) {
					g_string_append(filename,".lyx");
				} else if (output_format == RTF_FORMAT) {
					g_string_append(filename,".rtf");
				} else {
					/* default extension -- in this case we only have 1 */
					g_string_append(filename,".txt");
				}
			}

			pos = stop - source->str;

			/* Add to the manifest (if not already included) */
			if (manifest != NULL) {
				temp = strstr(manifest->str,filename->str);

				offset = temp - manifest->str;
				if ((temp != NULL) &&
					((temp == manifest->str) || ((manifest->str)[offset - 1] == '\n')) &&
					(temp[strlen(filename->str)] == '\n') ){
					/* Already on manifest, so don't add again */
				} else {
					g_string_append_printf(manifest,"%s\n",filename->str);
				}
			}


			/* Don't reparse ourselves */
			if (stack != NULL) {
				temp = strstr(stack,filename->str);

				if ((temp != NULL) && (temp[strlen(filename->str)] == '\n')){
					start = strstr(source->str + pos,"{{");
					g_string_free(filename, true);
					continue;
				}
			}

			/* Read file */
#if defined(__WIN32)
			int wchars_num = MultiByteToWideChar(CP_UTF8, 0, filename->str, -1, NULL, 0);
			wchar_t wstr[wchars_num];
			MultiByteToWideChar(CP_UTF8, 0, filename->str, -1, wstr, wchars_num);

			if ((input = _wfopen(wstr, L"r")) != NULL ) {
#else
			if ((input = fopen(filename->str, "r")) != NULL ) {
#endif
				filebuffer = g_string_new("");

				while ((curchar = fgetc(input)) != EOF)
					g_string_append_c(filebuffer, curchar);
				
				fclose(input);

	 			pos = start - source->str;

				g_string_erase(source, pos, 2 + stop - start);

				/* Update stack list */
				stackstring = g_string_new(stack);
				g_string_append_printf(stackstring,"%s\n",filename->str);


				/* Recursively transclude files */

				/* We want to reset the base directory if we enter a subdirectory */
				char * new_dir;
				char * file_only;
				split_path_file(&new_dir, &file_only, filename->str);

				/* transclude_source(filebuffer, folder->str, stackstring->str, output_format, manifest); */
				transclude_source(filebuffer, new_dir, stackstring->str, output_format, manifest);

				free(new_dir);
				free(file_only);
				
				temp = source_without_metadata(filebuffer->str, 0x000000);

				g_string_insert(source, pos, temp);

				pos += strlen(temp);
				g_string_free(filebuffer, true);
				g_string_free(stackstring, true);
			} else {
				/* fprintf(stderr, "error opening file: %s\n", filename->str); */
			}

            g_string_free(filename, true);
        } else {
        	/* Our "match" was > 1000 characters long */
            pos = stop - source->str;
        }
		start = strstr(source->str + pos,"{{");
	}

	g_string_free(folder, true);
	free(path);
	free(base);
}

/* Allow for a footer to specify files to be appended to the end of the text, and then transcluded.
	Useful for appending a list of footnotes, citations, abbreviations, etc. to each separate file,
	but not including multiple copies when processing the master file. */
void append_mmd_footer(GString *source) {
	/* Look for mmd_footer metadata */
	if (has_metadata(source->str, 0x000000)) {
		char *meta = extract_metadata_value(source->str, 0x000000, "mmdfooter");
		if (meta != NULL)
			g_string_append_printf(source, "\n\n{{%s}}\n", meta);
	}
}

void prepend_mmd_header(GString *source) {
	/* Same thing, but to be inserted after metadata and before content */
	if (has_metadata(source->str, 0x000000)) {
		char *meta = extract_metadata_value(source->str, 0x000000, "mmdheader");
		if (meta != NULL) {
			char *content = strstr(source->str, "\n\n");
			if (content != NULL) {
				size_t pos = content - source->str;
				g_string_insert_printf(source, pos, "\n\n{{%s}}", meta);
			} else {
				g_string_append_printf(source, "\n\n{{%s}}\n", meta);
			}
		}
	}
}
Exemplo n.º 2
0
/* Given a GString containing MMD source, and optional base directory,
	substitute transclusion references in the source 

	Pass the path to the current folder if available -- should be a full path. 

	Keep track of what we're parsing to prevent recursion using stack. */
void transclude_source(GString *source, char *basedir, char *stack, int output_format) {
	char *base = NULL;
	char *path = NULL;
	char *start;
	char *stop;
	char *temp;
	int curchar;
	size_t pos;
	char real[1000];
	FILE *input;

	if (basedir == NULL) {
		base = strdup("");
	} else {
		base = strdup(basedir);
	}

	GString *folder = NULL;
	GString *filename = NULL;
	GString *filebuffer = NULL;
	GString *stackstring = NULL;

	path = strdup(base);

	/* Look for override folder inside document */
	if (has_metadata(source->str, 0x000000)) {
		char *meta = extract_metadata_value(source->str, 0x000000, "transcludebase");
		if (meta != NULL)
			path = path_from_dir_base(base, meta);
	}

	if (path == NULL) {
		/* We have nowhere to look, so nothing to do */
		free(path);
		free(base);
		return;
	}

	folder = g_string_new(path);

	/* Ensure that folder ends in "/" */
	/* TODO: adjust for windows */
	if (!(folder->str[strlen(folder->str)-1] == '/') ) {
		g_string_append_c(folder, '/');
	}

	//fprintf(stderr, "Transclude using '%s'\n", folder->str);

	/* Iterate through {{foo.txt}} and substitute contents of file without metadata */

	start = strstr(source->str,"{{");

	while (start != NULL) {
		stop = strstr(start,"}}");
		if (stop == NULL)
			break;

		// TODO: Need to check that we found something reasonable 

		strncpy(real,start+2,stop-start-2);
		real[stop-start-2] = '\0';

		filename = g_string_new(folder->str);
		g_string_append_printf(filename, "%s",real);

		/* Adjust for wildcard extensions */
		/* But not if output_format == 0 */
		if (output_format && strncmp(&filename->str[strlen(filename->str) - 2],".*",2) == 0) {
			g_string_erase(filename, strlen(filename->str) - 2, 2);
			if (output_format == TEXT_FORMAT) {
				g_string_append(filename,".txt");
			} else if (output_format == HTML_FORMAT) {
				g_string_append(filename,".html");
			} else if (output_format == LATEX_FORMAT) {
				g_string_append(filename,".tex");
			} else if (output_format == BEAMER_FORMAT) {
				g_string_append(filename,".tex");
			} else if (output_format == MEMOIR_FORMAT) {
				g_string_append(filename,".tex");
			} else if (output_format == ODF_FORMAT) {
				g_string_append(filename,".fodt");
			} else if (output_format == OPML_FORMAT) {
				g_string_append(filename,".opml");
			} else if (output_format == LYX_FORMAT) {
				g_string_append(filename,".lyx");
			} else if (output_format == RTF_FORMAT) {
				g_string_append(filename,".rtf");
			} else {
				/* default extension -- in this case we only have 1 */
				g_string_append(filename,".txt");
			}
		}

		pos = stop - source->str;

		/* Don't reparse ourselves */
		if (stack != NULL) {
			temp = strstr(stack,filename->str);

			if ((temp != NULL) && (temp[strlen(filename->str)] == '\n')){
				start = strstr(source->str + pos,"{{");
				g_string_free(filename, true);
				continue;
			}
		}

		/* Read file */
		if ((input = fopen(filename->str, "r")) != NULL ) {
			filebuffer = g_string_new("");

			while ((curchar = fgetc(input)) != EOF)
				g_string_append_c(filebuffer, curchar);
			
			fclose(input);

 			pos = start - source->str;

			g_string_erase(source, pos, 2 + stop - start);

			/* Update stack list */
			stackstring = g_string_new(stack);
			g_string_append_printf(stackstring,"%s\n",filename->str);


			/* Recursively transclude files */
			transclude_source(filebuffer, folder->str, stackstring->str, output_format);

			temp = source_without_metadata(filebuffer->str, 0x000000);

			g_string_insert(source, pos, temp);

			pos += strlen(temp);
			g_string_free(filebuffer, true);
			g_string_free(stackstring, true);
		} else {
			/* fprintf(stderr, "error opening file: %s\n", filename->str); */
		}

		start = strstr(source->str + pos,"{{");
		g_string_free(filename, true);
	}

	g_string_free(folder, true);
	free(path);
	free(base);
}