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 + -
显示快捷键?