synctex_parser.c.svn-base

来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· SVN-BASE 代码 · 共 1,720 行 · 第 1/5 页

SVN-BASE
1,720
字号
 *  ±0.123456789e123 */#   define SYNCTEX_BUFFER_MIN_SIZE 16#   define SYNCTEX_BUFFER_SIZE 32768#	ifdef SYNCTEX_NOTHING#       pragma mark -#       pragma mark Prototypes#   endifvoid _synctex_log_void_box(synctex_node_t node);void _synctex_log_box(synctex_node_t node);void _synctex_log_horiz_box(synctex_node_t node);void _synctex_log_input(synctex_node_t node);synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t *  size_ptr);synctex_status_t _synctex_next_line(synctex_scanner_t scanner);synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char *  the_string);synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int*  value_ref);synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char **  value_ref);synctex_status_t _synctex_scan_input(synctex_scanner_t scanner);synctex_status_t _synctex_scan_preamble(synctex_scanner_t scanner);synctex_status_t _synctex_scan_float_and_dimension(synctex_scanner_t scanner, float *  value_ref);synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_t scanner);int _synctex_scan_postamble(synctex_scanner_t scanner);synctex_status_t _synctex_setup_visible_box(synctex_node_t box);synctex_status_t _synctex_horiz_box_setup_visible(synctex_node_t node,int h, int v);synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t parent);synctex_status_t _synctex_scan_content(synctex_scanner_t scanner);int synctex_scanner_pre_x_offset(synctex_scanner_t scanner);int synctex_scanner_pre_y_offset(synctex_scanner_t scanner);const char *  synctex_scanner_get_output_fmt(synctex_scanner_t scanner);int _synctex_node_is_box(synctex_node_t node);int _synctex_bail(void);/*  Try to ensure that the buffer contains at least size bytes. *  Passing a huge size argument means the whole buffer length. *  Passing a null size argument means return the available buffer length, without reading the file. *  In that case, the return status is always SYNCTEX_STATUS_OK unless the given scanner is NULL, *  in which case, SYNCTEX_STATUS_BAD_ARGUMENT is returned. *  The value returned in size_ptr is the number of bytes now available in the buffer. *  This is a nonnegative integer, it may take the value 0. *  It is the responsibility of the caller to test whether this size is conforming to its needs. *  Negative values may return in case of error, actually *  when there was an error reading the synctex file. */synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t *  size_ptr) {  	size_t available = 0;	if(NULL == scanner || NULL == size_ptr) {		return SYNCTEX_STATUS_BAD_ARGUMENT;	}#   define size (*  size_ptr)	if(size>SYNCTEX_BUFFER_SIZE){		size = SYNCTEX_BUFFER_SIZE;	}	available = SYNCTEX_END - SYNCTEX_CUR; /*  available is the number of unparsed chars in the buffer */	if(size<=available) {		/*  There are already sufficiently many characters in the buffer */		size = available;		return SYNCTEX_STATUS_OK;	}	if(SYNCTEX_FILE) {		/*  Copy the remaining part of the buffer to the beginning,		 *  then read the next part of the file */		int already_read = 0;		if(available) {			memmove(SYNCTEX_START, SYNCTEX_CUR, available);		}		SYNCTEX_CUR = SYNCTEX_START + available; /*  the next character after the move, will change. */		/*  Fill the buffer up to its end */		already_read = gzread(SYNCTEX_FILE,(void *)SYNCTEX_CUR,SYNCTEX_BUFFER_SIZE - available);		if(already_read>0) {			/*  We assume that 0<already_read<=SYNCTEX_BUFFER_SIZE - available, such that			 *  SYNCTEX_CUR + already_read = SYNCTEX_START + available  + already_read <= SYNCTEX_START + SYNCTEX_BUFFER_SIZE */			SYNCTEX_END = SYNCTEX_CUR + already_read;			/*  If the end of the file was reached, all the required SYNCTEX_BUFFER_SIZE - available			 *  may not be filled with values from the file.			 *  In that case, the buffer should stop properly after already_read characters. */			*  SYNCTEX_END = '\0';			SYNCTEX_CUR = SYNCTEX_START;			size = SYNCTEX_END - SYNCTEX_CUR; /* == old available + already_read*/			return SYNCTEX_STATUS_OK; /*  May be available is less than size, the caller will have to test. */		} else if(0>already_read) {			/*  There is an error in zlib */			int errnum = 0;			const char *  error_string = gzerror(SYNCTEX_FILE, &errnum);			if(Z_ERRNO == errnum) {				/*  There is an error in zlib caused by the file system */				_synctex_error("!  gzread error from the file system (%i)",errno);			} else {				_synctex_error("!  gzread error (%i:%i,%s)",already_read,errnum,error_string);			}			return SYNCTEX_STATUS_ERROR;		} else {			/*  Nothing was read, we are at the end of the file. */			gzclose(SYNCTEX_FILE);			SYNCTEX_FILE = NULL; 			SYNCTEX_END = SYNCTEX_CUR; 			SYNCTEX_CUR = SYNCTEX_START;			*  SYNCTEX_END = '\0';/*  Terminate the string properly.*/			size = SYNCTEX_END - SYNCTEX_CUR; 			return SYNCTEX_STATUS_EOF; /*  there might be a bit of text left */		}		/*  At this point, the function has already returned from above */	}	/*  We cannot enlarge the buffer because the end of the file was reached. */	size = available; 	return SYNCTEX_STATUS_EOF;#   undef size}/*  Used when parsing the synctex file. *  Advance to the next character starting a line. *  Actually, only '\n' is recognized as end of line marker. *  On normal completion, the returned value is the number of unparsed characters available in the buffer. *  In general, it is a positive value, 0 meaning that the end of file was reached. *  -1 is returned in case of error, actually because there was an error while feeding the buffer. *  When the function returns with no error, SYNCTEX_CUR points to the first character of the next line, if any. *  J. Laurens: Sat May 10 07:52:31 UTC 2008 */synctex_status_t _synctex_next_line(synctex_scanner_t scanner) {	synctex_status_t status = SYNCTEX_STATUS_OK;	size_t available = 0;	if(NULL == scanner) {		return SYNCTEX_STATUS_BAD_ARGUMENT;	}infinite_loop:	while(SYNCTEX_CUR<SYNCTEX_END) {		if(*SYNCTEX_CUR == '\n') {			++SYNCTEX_CUR;			available = 1;			return _synctex_buffer_get_available_size(scanner, &available);		}		++SYNCTEX_CUR;	}	/*  Here, we have SYNCTEX_CUR == SYNCTEX_END, such that the next call to _synctex_buffer_get_available_size	 *  will read another bunch of synctex file. Little by little, we advance to the end of the file. */	available = 1;	status = _synctex_buffer_get_available_size(scanner, &available);	if(status<=0) {		return status;	}	goto infinite_loop;}/*  Scan the given string. *  Both scanner and the_string must not be NULL, and the_string must not be 0 length. *  SYNCTEX_STATUS_OK is returned if the string is found, *  SYNCTEX_STATUS_EOF is returned when the EOF is reached, *  SYNCTEX_STATUS_NOT_OK is returned is the string is not found, *  an error status is returned otherwise. *  This is a critical method because buffering renders things more difficult. *  The given string might be as long as the maximum size_t value. *  As side effect, the buffer state may have changed if the given argument string can't fit into the buffer. */synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char *  the_string) {	size_t tested_len = 0; /*  the number of characters at the beginning of the_string that match */	size_t remaining_len = 0; /*  the number of remaining characters of the_string that should match */	size_t available = 0;	synctex_status_t status = 0;	if(NULL == scanner || NULL == the_string) {		return SYNCTEX_STATUS_BAD_ARGUMENT;	}	remaining_len = strlen(the_string); /*  All the_string should match */	if(0 == remaining_len) {		return SYNCTEX_STATUS_BAD_ARGUMENT;	}	/*  How many characters available in the buffer? */	available = remaining_len;	status = _synctex_buffer_get_available_size(scanner,&available);	if(status<SYNCTEX_STATUS_EOF) {		return status;	}	/*  Maybe we have less characters than expected because the buffer is too small. */	if(available>=remaining_len) {		/*  The buffer is sufficiently big to hold the expected number of characters. */		if(strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) {			return SYNCTEX_STATUS_NOT_OK;		}return_OK:		/*  Advance SYNCTEX_CUR to the next character after the_string. */		SYNCTEX_CUR += remaining_len;		return SYNCTEX_STATUS_OK;	} else if(strncmp((char *)SYNCTEX_CUR,the_string,available)) {			/*  No need to goo further, this is not the expected string in the buffer. */			return SYNCTEX_STATUS_NOT_OK;	} else if(SYNCTEX_FILE) {		/*  The buffer was too small to contain remaining_len characters.		 *  We have to cut the string into pieces. */		z_off_t offset = 0L;		/*  the first part of the string is found, advance the_string to the next untested character. */		the_string += available;		/*  update the remaining length and the parsed length. */		remaining_len -= available;		tested_len += available;		SYNCTEX_CUR += available; /*  We validate the tested characters. */		if(0 == remaining_len) {			/*  Nothing left to test, we have found the given string, we return the length. */			return tested_len;		}		/*  We also have to record the current state of the file cursor because		 *  if the_string does not match, all this should be a totally blank operation,		 *  for which the file and buffer states should not be modified at all.		 *  In fact, the states of the buffer before and after this function are in general different		 *  but they are totally equivalent as long as the values of the buffer before SYNCTEX_CUR		 *  can be safely discarded.  */		offset = gztell(SYNCTEX_FILE);		/*  offset now corresponds to the first character of the file that was not buffered. */		available = SYNCTEX_CUR - SYNCTEX_START; /*  available can be used as temporary placeholder. */		/*  available now corresponds to the number of chars that where already buffered and		 *  that match the head of the_string. If in fine the_string does not match, all these chars must be recovered		 *  because the buffer contents is completely replaced by _synctex_buffer_get_available_size.		 *  They were buffered from offset-len location in the file. */		offset -= available;more_characters:		/*  There is still some work to be done, so read another bunch of file.		 *  This is the second call to _synctex_buffer_get_available_size,		 *  which means that the actual contents of the buffer will be discarded.		 *  We will definitely have to recover the previous state in case we do not find the expected string. */		available = remaining_len;		status = _synctex_buffer_get_available_size(scanner,&available);		if(status<SYNCTEX_STATUS_EOF) {			return status; /*  This is an error, no need to go further. */		}		if(available==0) {			/*  Missing characters: recover the initial state of the file and return. */return_NOT_OK:			if(offset != gzseek(SYNCTEX_FILE,offset,SEEK_SET)) {				/*  This is a critical error, we could not recover the previous state. */				_synctex_error("!  can't seek file");				return SYNCTEX_STATUS_ERROR;			}			/*  Next time we are asked to fill the buffer,			 *  we will read a complete bunch of text from the file. */			SYNCTEX_CUR = SYNCTEX_END;			return SYNCTEX_STATUS_NOT_OK;		}		if(available<remaining_len) {			/*  We'll have to loop one more time. */			if(strncmp((char *)SYNCTEX_CUR,the_string,available)) {				/*  This is not the expected string, recover the previous state and return. */				goto return_NOT_OK;			}			/*  Advance the_string to the first untested character. */			the_string += available;			/*  update the remaining length and the parsed length. */			remaining_len -= available;			tested_len += available;			SYNCTEX_CUR += available; /*  We validate the tested characters. */			if(0 == remaining_len) {				/*  Nothing left to test, we have found the given string. */				return SYNCTEX_STATUS_OK;			}			goto more_characters;		}		/*  This is the last step. */		if(strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) {			/*  This is not the expected string, recover the previous state and return. */			goto return_NOT_OK;		}		goto return_OK;	} else {		/*  The buffer can't contain the given string argument, and the EOF was reached */		return SYNCTEX_STATUS_EOF;	}}/*  Used when parsing the synctex file. *  Decode an integer. *  First, field separators, namely ':' and ',' characters are skipped *  The returned value is negative if there is an unrecoverable error. *  It is SYNCTEX_STATUS_NOT_OK if an integer could not be parsed, for example *  if the characters at the current cursor position are not digits or *  if the end of the file has been reached. *  It is SYNCTEX_STATUS_OK if an int has been successfully parsed. *  The given scanner argument must not be NULL, on the contrary, value_ref may be NULL. */synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int*  value_ref) {	unsigned char *  ptr = NULL;	unsigned char *  end = NULL;	int result = 0;	size_t available = 0;	synctex_status_t status = 0;	if(NULL == scanner) {		 return SYNCTEX_STATUS_BAD_ARGUMENT;	}	available = SYNCTEX_BUFFER_MIN_SIZE;	status = _synctex_buffer_get_available_size(scanner, &available);	if(status<SYNCTEX_STATUS_EOF) {		return status;/*  Forward error. */	}	if(available==0) {		return SYNCTEX_STATUS_EOF;/*  it is the end of file. */	}	ptr = SYNCTEX_CUR;	if(*ptr==':' || *ptr==',') {		++ptr;		--available;		if(available==0) {			return SYNCTEX_STATUS_NOT_OK;/*  It is not possible to scan an int */		}	}	result = (int)strtol((char *)ptr, (char **)&end, 10);	if(end>ptr) {		SYNCTEX_CUR = end;		if(value_ref) {			*  value_ref = result;		}		return SYNCTEX_STATUS_OK;/*  Successfully scanned an int */	}		return SYNCTEX_STATUS_NOT_OK;/*  Could not scan an int */}/*  The purpose of this function is to read a string. *  A string is an array of characters from the current parser location *  and before the next '\n' character. *  If a string was properly decoded, it is returned in value_ref and *  the cursor points to the new line marker. *  The returned string was alloced on the heap, the caller is the owner and *  is responsible to free it in due time. *  If no string is parsed, *  value_ref is undefined. *  The maximum length of a string that a scanner can decode is platform dependent, namely UINT_MAX. *  If you just want to blindly parse the file up to the end of the current line, *  use _synctex_next_line instead. *  On return, the scanner cursor is unchanged if a string could not be scanned or *  points to the terminating '\n' character otherwise. As a consequence, *  _synctex_next_line is necessary after. *  If either scanner or value_ref is NULL, it is considered as an error and *  SYNCTEX_STATUS_BAD_ARGUMENT is returned. */synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char **  value_ref) {	unsigned char *  end = NULL;	size_t current_size = 0;	size_t new_size = 0;	size_t len = 0;/*  The number of bytes to copy */	size_t available = 0;	synctex_status_t status = 0;	if(NULL == scanner || NULL == value_ref) {		return SYNCTEX_STATUS_BAD_ARGUMENT;	}	/*  The buffer must at least contain one character: the '\n' end of line marker */	if(SYNCTEX_CUR>=SYNCTEX_END) {		available = 1;		status = _synctex_buffer_get_available_size(scanner,&available);		if(status < 0) {			return status;		}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?