]> www.fi.muni.cz Git - evince.git/blobdiff - cut-n-paste/synctex/synctex_parser_utils.c
Add synctex parser to cut-n-paste directory.
[evince.git] / cut-n-paste / synctex / synctex_parser_utils.c
diff --git a/cut-n-paste/synctex/synctex_parser_utils.c b/cut-n-paste/synctex/synctex_parser_utils.c
new file mode 100644 (file)
index 0000000..0aef577
--- /dev/null
@@ -0,0 +1,462 @@
+/* 
+Copyright (c) 2008, 2009 jerome DOT laurens AT u-bourgogne DOT fr
+
+This file is part of the SyncTeX package.
+
+Latest Revision: Wed Nov  4 11:52:35 UTC 2009
+
+Version: 1.9
+See synctex_parser_readme.txt for more details
+
+License:
+--------
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE
+
+Except as contained in this notice, the name of the copyright holder  
+shall not be used in advertising or otherwise to promote the sale,  
+use or other dealings in this Software without prior written  
+authorization from the copyright holder.
+
+*/
+
+/*  In this file, we find all the functions that may depend on the operating system. */
+
+#include <synctex_parser_utils.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <limits.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <sys/stat.h>
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
+#define SYNCTEX_WINDOWS 1
+#endif
+
+#ifdef _WIN32_WINNT_WINXP
+#define SYNCTEX_RECENT_WINDOWS 1
+#endif
+
+#ifdef SYNCTEX_WINDOWS
+#include <windows.h>
+#endif
+
+void *_synctex_malloc(size_t size) {
+       void * ptr = malloc(size);
+       if(ptr) {
+/*  There used to be a switch to use bzero because it is more secure. JL */
+               memset(ptr,0, size);
+       }
+       return (void *)ptr;
+}
+
+int _synctex_error(const char * reason,...) {
+       va_list arg;
+       int result;
+       va_start (arg, reason);
+#      ifdef SYNCTEX_RECENT_WINDOWS
+       {/*     This code is contributed by William Blum.
+        As it does not work on some older computers,
+        the _WIN32 conditional here is replaced with a SYNCTEX_RECENT_WINDOWS one.
+        According to http://msdn.microsoft.com/en-us/library/aa363362(VS.85).aspx
+        Minimum supported client       Windows 2000 Professional
+        Minimum supported server       Windows 2000 Server
+        People running Windows 2K standard edition will not have OutputDebugStringA.
+        JL.*/
+               char *buff;
+               size_t len;
+               OutputDebugStringA("SyncTeX ERROR: ");
+               len = _vscprintf(reason, arg) + 1;
+               buff = (char*)malloc( len * sizeof(char) );
+               result = vsprintf(buff, reason, arg) +strlen("SyncTeX ERROR: ");
+               OutputDebugStringA(buff);
+               OutputDebugStringA("\n");
+               free(buff);
+       }
+#   else
+       result = fprintf(stderr,"SyncTeX ERROR: ");
+       result += vfprintf(stderr, reason, arg);
+       result += fprintf(stderr,"\n");
+#   endif
+       va_end (arg);
+       return result;
+}
+
+/*  strip the last extension of the given string, this string is modified! */
+void _synctex_strip_last_path_extension(char * string) {
+       if(NULL != string){
+               char * last_component = NULL;
+               char * last_extension = NULL;
+               char * next = NULL;
+               /*  first we find the last path component */
+               if(NULL == (last_component = strstr(string,"/"))){
+                       last_component = string;
+               } else {
+                       ++last_component;
+                       while((next = strstr(last_component,"/"))){
+                               last_component = next+1;
+                       }
+               }
+#       ifdef  SYNCTEX_WINDOWS
+               /*  On Windows, the '\' is also a path separator. */
+               while((next = strstr(last_component,"\\"))){
+                       last_component = next+1;
+               }
+#       endif
+               /*  then we find the last path extension */
+               if((last_extension = strstr(last_component,"."))){
+                       ++last_extension;
+                       while((next = strstr(last_extension,"."))){
+                               last_extension = next+1;
+                       }
+                       --last_extension;/*  back to the "." */
+                       if(last_extension>last_component){/*  filter out paths like ....my/dir/.hidden"*/
+                               last_extension[0] = '\0';
+                       }
+               }
+       }
+}
+
+/*  Compare two file names, windows is sometimes case insensitive... */
+synctex_bool_t _synctex_is_equivalent_file_name(const char *lhs, const char *rhs) {
+#      if SYNCTEX_WINDOWS
+    /*  On Windows, filename should be compared case insensitive.
+        *  The characters '/' and '\' are both valid path separators.
+        *  There will be a very serious problem concerning UTF8 because
+        *  not all the characters must be toupper...
+        *  I would like to have URL's instead of filenames. */
+next_character:
+       if(SYNCTEX_IS_PATH_SEPARATOR(*lhs)) {/*  lhs points to a path separator */
+               if(!SYNCTEX_IS_PATH_SEPARATOR(*rhs)) {/*  but not rhs */
+                       return synctex_NO;
+               }
+       } else if(SYNCTEX_IS_PATH_SEPARATOR(*rhs)) {/*  rhs points to a path separator but not lhs */
+               return synctex_NO;
+       } else if(toupper(*lhs) != toupper(*rhs)){/*  uppercase do not match */
+               return synctex_NO;
+       } else if (!*lhs) {/*  lhs is at the end of the string */
+               return *rhs ? synctex_NO : synctex_YES;
+       } else if(!*rhs) {/*  rhs is at the end of the string but not lhs */
+               return synctex_NO;
+       }
+       ++lhs;
+       ++rhs;
+       goto next_character;
+#      else
+    return 0 == strcmp(lhs,rhs)?synctex_YES:synctex_NO;
+#      endif
+}
+
+synctex_bool_t _synctex_path_is_absolute(const char * name) {
+       if(!strlen(name)) {
+               return synctex_NO;
+       }
+#      if SYNCTEX_WINDOWS
+       if(strlen(name)>2) {
+               return (name[1]==':' && SYNCTEX_IS_PATH_SEPARATOR(name[2]))?synctex_YES:synctex_NO;
+       }
+       return synctex_NO;
+#      else
+    return SYNCTEX_IS_PATH_SEPARATOR(name[0])?synctex_YES:synctex_NO;
+#      endif
+}
+
+/*  We do not take care of UTF-8 */
+const char * _synctex_last_path_component(const char * name) {
+       const char * c = name+strlen(name);
+       if(c>name) {
+               if(!SYNCTEX_IS_PATH_SEPARATOR(*c)) {
+                       do {
+                               --c;
+                               if(SYNCTEX_IS_PATH_SEPARATOR(*c)) {
+                                       return c+1;
+                               }
+                       } while(c>name);
+               }
+               return c;/* the last path component is the void string*/
+       }
+       return c;
+}
+
+int _synctex_copy_with_quoting_last_path_component(const char * src, char ** dest_ref, size_t size) {
+  const char * lpc;
+  if(src && dest_ref) {
+#              define dest (*dest_ref)
+               dest = NULL;    /*      Default behavior: no change and sucess. */
+               lpc = _synctex_last_path_component(src);
+               if(strlen(lpc)) {
+                       if(strchr(lpc,' ') && lpc[0]!='"' && lpc[strlen(lpc)-1]!='"') {
+                               /*      We are in the situation where adding the quotes is allowed.     */
+                               /*      Time to add the quotes. */
+                               /*  Consistency test: we must have dest+size>dest+strlen(dest)+2
+                                *      or equivalently: strlen(dest)+2<size (see below) */
+                               if(strlen(src)<size) {
+                                       if((dest = (char *)malloc(size+2))) {
+                                               char * dpc = dest + (lpc-src);  /*      dpc is the last path component of dest. */
+                                               if(dest != strncpy(dest,src,size)) {
+                                                       _synctex_error("!  _synctex_copy_with_quoting_last_path_component: Copy problem");
+                                                       free(dest);
+                                                       dest = NULL;/*  Don't forget to reinitialize. */
+                                                       return -2;
+                                               }
+                                               memmove(dpc+1,dpc,strlen(dpc)+1);       /*      Also move the null terminating character. */
+                                               dpc[0]='"';
+                                               dpc[strlen(dpc)+1]='\0';/*      Consistency test */
+                                               dpc[strlen(dpc)]='"';
+                                               return 0;       /*      Success. */
+                                       }
+                                       return -1;      /*      Memory allocation error.        */
+                               }
+                               _synctex_error("!  _synctex_copy_with_quoting_last_path_component: Internal inconsistency");
+                               return -3;
+                       }
+                       return 0;       /*      Success. */
+               }
+               return 0;       /*      No last path component. */
+#              undef dest
+       }
+       return 1; /*  Bad parameter, this value is subject to changes. */
+}
+
+/*  The client is responsible of the management of the returned string, if any. */
+char * _synctex_merge_strings(const char * first,...);
+
+char * _synctex_merge_strings(const char * first,...) {
+       va_list arg;
+       size_t size = 0;
+       const char * temp;
+       /*   First retrieve the size necessary to store the merged string */
+       va_start (arg, first);
+       temp = first;
+       do {
+               size_t len = strlen(temp);
+               if(UINT_MAX-len<size) {
+                       _synctex_error("!  _synctex_merge_strings: Capacity exceeded.");
+                       return NULL;
+               }
+               size+=len;
+       } while( (temp = va_arg(arg, const char *)) != NULL);
+       va_end(arg);
+       if(size>0) {
+               char * result = NULL;
+               ++size;
+               /*  Create the memory storage */
+               if(NULL!=(result = (char *)malloc(size))) {
+                       char * dest = result;
+                       va_start (arg, first);
+                       temp = first;
+                       do {
+                               if((size = strlen(temp))>0) {
+                                       /*  There is something to merge */
+                                       if(dest != strncpy(dest,temp,size)) {
+                                               _synctex_error("!  _synctex_merge_strings: Copy problem");
+                                               free(result);
+                                               result = NULL;
+                                               return NULL;
+                                       }
+                                       dest += size;
+                               }
+                       } while( (temp = va_arg(arg, const char *)) != NULL);
+                       va_end(arg);
+                       dest[0]='\0';/*  Terminate the merged string */
+                       return result;
+               }
+               _synctex_error("!  _synctex_merge_strings: Memory problem");
+               return NULL;
+       }
+       return NULL;    
+}
+
+/*  The purpose of _synctex_get_name is to find the name of the synctex file.
+ *  There is a list of possible filenames from which we return the most recent one and try to remove all the others.
+ *  With two runs of pdftex or xetex we are sure the the synctex file is really the most appropriate.
+ */
+int _synctex_get_name(const char * output, const char * build_directory, char ** synctex_name_ref, synctex_compress_mode_t * compress_mode_ref)
+{
+       if(output && synctex_name_ref && compress_mode_ref) {
+#              define synctex_name (*synctex_name_ref)
+#              define compress_mode (*compress_mode_ref)
+               /*  If output is already absolute, we just have to manage the quotes and the compress mode */
+               const char * basename = NULL; /*  base name of output*/
+               size_t size = 0;
+               /*  Initialize the return values. */
+               synctex_name = NULL;
+               compress_mode = synctex_compress_mode_none;
+               basename = _synctex_last_path_component(output); /*  do not free, output is the owner. */
+               /*  Do we have a real base name ? */
+               if((size = strlen(basename))>0) {
+                       /*  Yes, we do. */
+                       const char * temp = NULL;
+                       char * corename = NULL; /*  base name of output without path extension. */
+                       char * dirname = NULL; /*  dir name of output */
+                       char * quoted_corename = NULL;
+                       char * none = NULL;
+                       char * gz = NULL;
+                       char * quoted = NULL;
+                       char * quoted_gz = NULL;
+                       char * build = NULL;
+                       char * build_gz = NULL;
+                       char * build_quoted = NULL;
+                       char * build_quoted_gz = NULL;
+                       struct stat buf;
+                       time_t time = 0;
+                       /*  Create corename: let temp point to the dot before the path extension of basename;
+                        *  We start form the \0 terminating character and scan the string upward until we find a dot.
+                        *  The first dot is not accepted. */
+                       temp = strrchr(basename,'.');
+                       size = temp - basename;
+                       if(size>0) {
+                               /*  dot properly found, now create corename  */
+                               if(NULL == (corename = (char *)malloc(size+1))) {
+                                       _synctex_error("!  _synctex_get_name: Memory problem 1");
+                                       return -1;
+                               }
+                               if(corename != strncpy(corename,basename,size)) {
+                                       _synctex_error("!  _synctex_get_name: Copy problem 1");
+                                       free(corename);
+                                       dirname = NULL;
+                                       return -2;
+                               }
+                               corename[size] = '\0';
+                       } else {
+                               /*  There is no path extension,
+                                *  Just make a copy of basename */
+                               corename = _synctex_merge_strings(basename);
+                       }
+                       /*  corename is properly set up, owned by "self". */
+                       /*  creating dirname. */
+                       size = strlen(output)-strlen(basename);
+                       if(size>0) {
+                               /*  output contains more than one path component */
+                               if(NULL == (dirname = (char *)malloc(size+1))) {
+                                       _synctex_error("!  _synctex_get_name: Memory problem");
+                                       free(corename);
+                                       dirname = NULL;
+                                       return -1;
+                               }
+                               if(dirname != strncpy(dirname,output,size)) {
+                                       _synctex_error("!  _synctex_get_name: Copy problem");
+                                       free(dirname);
+                                       dirname = NULL;
+                                       free(corename);
+                                       dirname = NULL;
+                                       return -2;
+                               }
+                               dirname[size] = '\0';
+                       }
+                       /*  dirname is properly set up. It ends with a path separator, if non void. */
+                       /*  creating quoted_corename. */
+                       if(strchr(corename,' ')) {
+                               quoted_corename = _synctex_merge_strings("\"",corename,"\"");
+                       }
+                       /*  quoted_corename is properly set up. */
+                       if(dirname &&strlen(dirname)>0) {
+                               none = _synctex_merge_strings(dirname,corename,synctex_suffix,NULL);
+                               if(quoted_corename && strlen(quoted_corename)>0) {
+                                       quoted = _synctex_merge_strings(dirname,quoted_corename,synctex_suffix,NULL);
+                               }
+                       } else {
+                               none = _synctex_merge_strings(corename,synctex_suffix,NULL);
+                               if(quoted_corename && strlen(quoted_corename)>0) {
+                                       quoted = _synctex_merge_strings(quoted_corename,synctex_suffix,NULL);
+                               }
+                       }
+                       if(!_synctex_path_is_absolute(output) && build_directory && (size = strlen(build_directory))) {
+                               temp = build_directory + size - 1;
+                               if(_synctex_path_is_absolute(temp)) {
+                                       build = _synctex_merge_strings(build_directory,none,NULL);
+                                       if(quoted_corename && strlen(quoted_corename)>0) {
+                                               build_quoted = _synctex_merge_strings(build_directory,quoted,NULL);
+                                       }
+                               } else {
+                                       build = _synctex_merge_strings(build_directory,"/",none,NULL);
+                                       if(quoted_corename && strlen(quoted_corename)>0) {
+                                               build_quoted = _synctex_merge_strings(build_directory,"/",quoted,NULL);
+                                       }
+                               }
+                       }
+                       if(none) {
+                               gz = _synctex_merge_strings(none,synctex_suffix_gz,NULL);
+                       }
+                       if(quoted) {
+                               quoted_gz =     _synctex_merge_strings(quoted,synctex_suffix_gz,NULL);
+                       }
+                       if(build) {
+                               build_gz = _synctex_merge_strings(build,synctex_suffix_gz,NULL);
+                       }
+                       if(build_quoted) {
+                               build_quoted_gz = _synctex_merge_strings(build_quoted,synctex_suffix_gz,NULL);
+                       }
+                       /*  All the others names are properly set up... */
+                       /*  retain the most recently modified file */
+#                      define TEST(FILENAME,COMPRESS_MODE) \
+                       if(FILENAME) {\
+                               if (stat(FILENAME, &buf)) { \
+                                       free(FILENAME);\
+                                       FILENAME = NULL;\
+                               } else { \
+                                       if(buf.st_mtime>time) { \
+                                               time=buf.st_mtime; \
+                                               synctex_name = FILENAME; \
+                                               compress_mode = COMPRESS_MODE; \
+                                       } \
+                               } \
+                       }
+                       TEST(none,synctex_compress_mode_none);
+                       TEST(gz,synctex_compress_mode_gz);
+                       TEST(quoted,synctex_compress_mode_none);
+                       TEST(quoted_gz,synctex_compress_mode_gz);
+                       TEST(build,synctex_compress_mode_none);
+                       TEST(build_gz,synctex_compress_mode_gz);
+                       TEST(build_quoted,synctex_compress_mode_none);
+                       TEST(build_quoted_gz,synctex_compress_mode_gz);
+#                      undef TEST
+                       /*  Free all the intermediate filenames, except the one that will be used as returned value. */
+#                      define CLEAN_AND_REMOVE(FILENAME) \
+                       if(FILENAME && (FILENAME!=synctex_name)) {\
+                               remove(FILENAME);\
+                               printf("synctex tool info: %s removed\n",FILENAME);\
+                               free(FILENAME);\
+                               FILENAME = NULL;\
+                       }
+                       CLEAN_AND_REMOVE(none);
+                       CLEAN_AND_REMOVE(gz);
+                       CLEAN_AND_REMOVE(quoted);
+                       CLEAN_AND_REMOVE(quoted_gz);
+                       CLEAN_AND_REMOVE(build);
+                       CLEAN_AND_REMOVE(build_gz);
+                       CLEAN_AND_REMOVE(build_quoted);
+                       CLEAN_AND_REMOVE(build_quoted_gz);
+#                      undef CLEAN_AND_REMOVE
+                       return 0;
+               }
+               return -1;/*  bad argument */
+#              undef synctex_name
+#              undef compress_mode 
+       }
+       return -2;
+}
+