On Monday 12 September 2005 23:19, Angus Leeming wrote:
> On Monday 12 September 2005 22:30, Luis Rivera wrote:
> >>> package.C:384: error: `GetLongPathName' undeclared (first use of
> >>> this function)

Luis,

I've made available a new version of tex2lyx for Windows that should work on 
Win95 and Win98. Get it from

http://wiki.lyx.org/uploads/LaTeX/tex2lyx/tex2lyx_win32_26sep05.zip

If you can confirm it works, then I'll adjust the docs at 
http://wiki.lyx.org/LaTeX/LatexToLyx to point to the new package.

Moreover, the attached patch should allow the code to be compiled on Cygwin as 
well as on MinGW. I'd be interested to see whether the cygwin-compiled binary 
runs on Win95/Win98 too, although it appears that there's a bug that will 
prevent you from running tex2lyx in-place; you'll have to use the installed 
binary C:/Program File/LyX-1.4/bin/tex2lyx.exe (or similar)

Regards,
Angus
Index: src/support/os_win32.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/os_win32.C,v
retrieving revision 1.29
diff -u -a -u -r1.29 os_win32.C
--- src/support/os_win32.C	29 Apr 2005 08:42:02 -0000	1.29
+++ src/support/os_win32.C	26 Sep 2005 07:43:08 -0000
@@ -19,6 +19,19 @@
 
 #include "debug.h"
 
+#include <boost/assert.hpp>
+#include <vector>
+
+/*
+ * The GetLongPathNameA function declaration in
+ * winbase.h under MinGW or Cygwin is protected
+ * by the WINVER macro which must therefore be defined
+ * before including windows.h.
+ */
+#if defined(__MINGW32__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
+# define WINVER 0x0500
+#endif
+
 #include <windows.h>
 #include <io.h>
 #include <direct.h> // _getdrive
@@ -27,6 +40,194 @@
 using std::string;
 
 
+/* Note from Angus, 26 September 2005:
+ *
+ * GetLongPathNameA is to be found in Kernel32.dll
+ * on Win98 and newer flavours of Windows. The function
+ * is declared in winbase.h on such a machine.
+ *
+ * However, whilst
+ *
+ *     char spath[] = ...;
+ *     char lpath[PATH_MAX];
+ *     GetLongPathName(spath, lpath, PATH_MAX);
+ *
+ * will compile on WinXP, the resulting executable will
+ * fail on Win95. Thus, we need to check Kernel32.dll
+ * dynamically for GetLongPathNameA and if it is not
+ * found, revert to our own version that emulates it.
+ */
+namespace {
+
+class GetLongPath {
+public:
+	GetLongPath();
+	~GetLongPath();
+
+	/** Wrapper for GetLongPathNameA.
+	 *  @returns the long path name associated with @c short_path.
+	 */
+	string const operator()(string const & short_path) const;
+private:
+	string const system_wrapper(string const & short_path) const;
+
+	typedef DWORD (__stdcall * FuncPtr)(LPCTSTR, LPTSTR, DWORD);
+	HMODULE kernel32_dll_;
+	FuncPtr system_func_;
+};
+
+
+GetLongPath::GetLongPath()
+	: kernel32_dll_(0),
+	  system_func_(0)
+{
+	kernel32_dll_ = LoadLibrary("kernel32.dll");
+	if (kernel32_dll_)
+		system_func_ = reinterpret_cast<FuncPtr>(::GetProcAddress(kernel32_dll_, "GetLongPathNameA"));
+}
+
+
+GetLongPath::~GetLongPath()
+{
+	if (kernel32_dll_)
+		FreeLibrary(kernel32_dll_);
+}
+
+
+string const win95_get_long_path(string const & short_path);
+
+
+string const GetLongPath::operator()(string const & short_path) const
+{
+	return system_func_ ?
+		system_wrapper(short_path) :
+		win95_get_long_path(short_path);
+}
+
+
+string const GetLongPath::system_wrapper(string const & short_path) const
+{
+	std::vector<char> long_path(PATH_MAX);
+	DWORD result = system_func_(short_path.c_str(),
+				    &long_path[0], long_path.size());
+
+	if (result > long_path.size()) {
+		long_path.resize(result);
+		result = system_func_(short_path.c_str(),
+				      &long_path[0], long_path.size());
+		BOOST_ASSERT(result <= long_path.size());
+	}
+
+	return (result == 0) ? short_path : &long_path[0];
+}
+
+
+string::size_type get_start_relative_path(string const & path)
+{
+	typedef string::size_type size_type;
+
+	// Match "//shr" or "//shr/", returning the index of the next character
+	// thereafter or string::npos.
+	if (path.size() > 2 &&
+	    path.substr(0,2) == "//" ||
+	    path.substr(0,2) == "\\\\") {
+		size_type const pos = path.find_first_of("/\\", 2);
+		if (pos == string::npos)
+			return pos;
+		if (pos+1 == path.size())
+			return string::npos;
+		return pos+1;
+	}
+
+	// Match "C:", "C:/", "prn:" or "prn:/", returning the index of
+	// the next character thereafter or string::npos.
+	size_type const colon = path.find_first_of(":");
+	if (colon == string::npos)
+		return 0;
+	else {
+		if (colon+1 == path.size())
+			return string::npos;
+		return path.find_first_not_of("/\\", colon+1);
+	}
+
+	// There was no root.
+	return 0;
+}
+
+
+string const win95_get_long_path(string const & short_path)
+{
+	/* The grammar of a Windows path can be written as the EBNF grammar:
+
+	   path ::= [root] [relative-path]  // an empty path is valid
+	   root ::= [root-name] [root-directory]
+	   root-directory ::= separator
+	   relative-path ::= path-element { separator path-element } [separator]
+	   path-element ::= name | parent-directory | directory-placeholder
+	   name ::= char { char }
+	   directory-placeholder ::= "."
+	   parent-directory ::= ".."
+	   separator ::= "/"  | "\"
+
+	   where a | b means "a or b",
+	         [a] means "zero or one instance of a"
+		 {a} means zero or more instances of a"
+
+	   Examples of valid "root-name"s:
+	         C:
+	         C:/
+		 //shr
+		 //shr/
+		 prn:
+		 prn:/
+
+	   This function should modify only the "name" component of
+	   "relative-path".
+	*/
+	string const sp = lyx::support::trim(short_path);
+
+	// Initialise "lp" with everything up to the beginning of the
+	// relative-path component of "sp". If "sp" doesn't have a
+	// relative-path component, return.
+	typedef string::size_type size_type;
+
+	size_type const start_rel_path = get_start_relative_path(sp);
+	if (start_rel_path == string::npos)
+		return sp;
+
+	string lp = (start_rel_path == 0) ?
+		string() : sp.substr(0, start_rel_path);
+
+	size_type begin = start_rel_path;
+	while (begin != string::npos) {
+		size_type const next_separator = sp.find_first_of("/\\", begin);
+		size_type const count = (next_separator == string::npos) ?
+			string::npos : (next_separator - begin);
+
+		string const short_elem = sp.substr(begin, count);
+
+		string const trial_path = lp + short_elem;
+		WIN32_FIND_DATA find_data;
+		if (INVALID_HANDLE_VALUE == ::FindFirstFile(trial_path.c_str(), &find_data)) {
+			return sp;
+		} else
+			lp += find_data.cFileName;
+
+		if (next_separator != string::npos)
+			lp += sp[next_separator];
+
+		if (next_separator == string::npos)
+			begin = string::npos;
+		else
+			begin = sp.find_first_not_of("/\\", next_separator);
+	}
+
+	return lp;
+}
+
+} // namespace anon
+
+
 namespace lyx {
 namespace support {
 namespace os {
@@ -159,7 +360,8 @@
 // the Win32/DOS pathnames into Cygwin pathnames.
 string internal_path(string const & p)
 {
-	return subst(p, "\\", "/");
+	static GetLongPath get_long_path;
+	return subst(get_long_path(p), "\\", "/");
 }
 
 
Index: src/support/package.C.in
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/package.C.in,v
retrieving revision 1.12
diff -u -a -u -r1.12 package.C.in
--- src/support/package.C.in	17 Jul 2005 01:59:18 -0000	1.12
+++ src/support/package.C.in	26 Sep 2005 07:44:36 -0000
@@ -26,6 +26,9 @@
 
 #include <boost/assert.hpp>
 #include <boost/filesystem/operations.hpp>
+#if defined (USE_WINDOWS_PACKAGING)
+# include <boost/scoped_ptr.hpp>
+#endif
 #include <boost/tuple/tuple.hpp>
 
 #include <list>
@@ -39,23 +42,6 @@
 
 #if defined (USE_WINDOWS_PACKAGING)
 
-/*
- * MinGW's version of winver.h contains this comment:
- *
- * If you need Win32 API features newer the Win95 and WinNT then you must
- * define WINVER before including windows.h or any other method of including
- * the windef.h header.
- *
- * GetLongPathNameA requires WINVER == 0x0500.
- *
- * It doesn't matter if the Windows version is older than this because the
- * function will compile but will fail at run time. See
- * http://msdn.microsoft.com/library/en-us/mslu/winprog/microsoft_layer_for_unicode_apis_with_limited_support.asp
- */
-# if defined(__MINGW32__)
-#  define WINVER 0x0500
-# endif
-
 # include <windows.h>
 # include <shlobj.h>  // SHGetFolderPath
 
@@ -135,6 +121,34 @@
 get_user_support_dir(string const & default_user_support_dir,
 		     string const & command_line_user_support_dir);
 
+#if defined (USE_WINDOWS_PACKAGING)
+/** Win98 and earlier don't have SHGetFolderPath in shell32.dll.
+ *  Microsoft recommend that we load shfolder.dll at run time and
+ *  access the function through that. It will work on all versions
+ *  of Windows from Win95.
+ *
+ *  This class wraps the LoadLibrary and FreeLibrary calls and
+ *  makes SHGetFolderPath through its function operator.
+ */
+class GetFolderPath {
+public:
+	GetFolderPath();
+	~GetFolderPath();
+
+	/** Wrapper for SHGetFolderPathA, returning
+	 *  the path asscociated with @c folder_id.
+	 */
+	string const operator()(int folder_id) const;
+private:
+	typedef HRESULT (__stdcall * FuncPtr)(HWND, int, HANDLE, DWORD, LPCSTR);
+
+	HMODULE folder_module_;
+	FuncPtr folder_path_func_;
+};
+
+boost::scoped_ptr<GetFolderPath> win32_folder_path;
+#endif // USE_WINDOWS_PACKAGING
+
 } // namespace anon
 
 
@@ -144,6 +158,10 @@
 		 exe_build_dir_to_top_build_dir top_build_dir_location)
 	: explicit_user_support_dir_(false)
 {
+#if defined (USE_WINDOWS_PACKAGING)
+	win32_folder_path.reset(new GetFolderPath);
+#endif
+
 	home_dir_ = get_home_dir();
 	temp_dir_ = get_temp_dir();
 	document_dir_ = get_document_dir(home_dir_);
@@ -168,6 +186,10 @@
 		get_user_support_dir(default_user_support_dir,
 				     command_line_user_support_dir);
 
+#if defined (USE_WINDOWS_PACKAGING)
+	win32_folder_path.reset();
+#endif
+
 	lyxerr[Debug::INIT]
 		<< "<package>\n"
 		<< "\tbinary_dir " << binary_dir() << '\n'
@@ -216,6 +238,17 @@
 
 namespace {
 
+// If we use a 'lazy' lyxerr in the hope of setting the locale before
+// printing any messages, then we should ensure that it is flushed first.
+void bail_out()
+{
+#ifndef CXX_GLOBAL_CSTD
+	using std::exit;
+#endif
+	exit(1);
+}
+
+
 bool check_command_line_dir(string const & dir,
 			    string const & file,
 			    string const & command_line_switch);
@@ -235,16 +268,46 @@
 
 
 #if defined (USE_WINDOWS_PACKAGING)
+
+ GetFolderPath::GetFolderPath()
+	: folder_module_(0),
+	  folder_path_func_(0)
+{
+	folder_module_ = LoadLibrary("shfolder.dll");
+	if (!folder_module_) {
+		lyxerr << "Unable to load shfolder.dll\nPlease install."
+		       << std::endl;
+		bail_out();
+	}
+
+	folder_path_func_ = (FuncPtr) ::GetProcAddress(folder_module_, "SHGetFolderPathA");
+	if (folder_path_func_ == 0) {
+		lyxerr << "Unable to find SHGetFolderPathA in shfolder.dll\n"
+		          "Don't know how to proceed. Sorry."
+		       << std::endl;
+		bail_out();
+	}
+}
+
+
+GetFolderPath::~GetFolderPath()
+{
+	if (folder_module_)
+		FreeLibrary(folder_module_);
+}
+
+
 // Given a folder ID, returns the folder name (in unix-style format).
 // Eg CSIDL_PERSONAL -> "C:/Documents and Settings/USERNAME/My Documents"
-string const win32_folder_path(int folder_id)
+string const GetFolderPath::operator()(int folder_id) const
 {
-	char folder_path[PATH_MAX + 1];
-	if (SUCCEEDED(SHGetFolderPath(0, folder_id, 0,
-				      SHGFP_TYPE_CURRENT, folder_path)))
-		return os::internal_path(folder_path);
-	return string();
+	char folder_path[PATH_MAX];
+	HRESULT const result = (folder_path_func_)(0, folder_id, 0,
+						   SHGFP_TYPE_CURRENT,
+						   folder_path);
+	return (result == 0) ? os::internal_path(folder_path) : string();
 }
+
 #endif
 
 
@@ -325,7 +388,7 @@
 {
 #if defined (USE_WINDOWS_PACKAGING)
 	(void)home_dir; // Silence warning about unused variable.
-	return win32_folder_path(CSIDL_PERSONAL);
+	return (*win32_folder_path)(CSIDL_PERSONAL);
 #else // Posix-like.
 	return home_dir;
 #endif
@@ -379,9 +442,8 @@
 {
 #if defined (USE_WINDOWS_PACKAGING)
 	// Typical example: C:/TEMP/.
-	char path[PATH_MAX + 1];
+	char path[PATH_MAX];
 	GetTempPath(PATH_MAX, path);
-	GetLongPathName(path, path, PATH_MAX + 1);
 	return os::internal_path(path);
 #else // Posix-like.
 	return "/tmp";
@@ -389,17 +451,6 @@
 }
 
 
-// If we use a 'lazy' lyxerr in the hope of setting the locale before
-// printing any messages, then we should ensure that it is flushed first.
-void bail_out()
-{
-#ifndef CXX_GLOBAL_CSTD
-	using std::exit;
-#endif
-	exit(1);
-}
-
-
 // Extracts the absolute path from the foo of "-sysdir foo" or "-userdir foo"
 string const abs_path_from_command_line(string const & command_line)
 {
@@ -631,7 +682,7 @@
 #if defined (USE_WINDOWS_PACKAGING)
 	(void)home_dir; // Silence warning about unused variable.
 
-	return AddPath(win32_folder_path(CSIDL_APPDATA), PACKAGE);
+	return AddPath((*win32_folder_path)(CSIDL_APPDATA), PACKAGE);
 
 #elif defined (USE_MACOSX_PACKAGING)
 	(void)home_dir; // Silence warning about unused variable.

Reply via email to