diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2014-12-15 16:42:03 +0100 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2014-12-15 16:45:51 +0100 |
commit | 5e9a2e9b0f33ab50aa3a84728db75383aede19d9 (patch) | |
tree | 1f66af867652c4c12ea1c34c0e564caaf5915578 /jvmfwk/plugins | |
parent | 0136acb836f3451786c4bd9c34dafe66e30d4dda (diff) |
Check each potential JRE location only once
i.e., after recent "fdo#83753: consider JAVA_HOME and PATH when selecting JRE"
fix, if jfw_findAndSelectJRE found no suitable JRE in
jfw_plugin_getJavaInfoFromJavaHome or jfw_plugin_getJavaInfosFromPath, do not
re-check those locations in jfw_plugin_getAllJavaInfos.
Change-Id: If4e085b4fceff5b2494c7b7b84ac51691dbc78cc
Diffstat (limited to 'jvmfwk/plugins')
-rw-r--r-- | jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx | 25 | ||||
-rw-r--r-- | jvmfwk/plugins/sunmajor/pluginlib/util.cxx | 132 | ||||
-rw-r--r-- | jvmfwk/plugins/sunmajor/pluginlib/util.hxx | 27 | ||||
-rw-r--r-- | jvmfwk/plugins/sunmajor/pluginlib/vendorbase.hxx | 184 |
4 files changed, 103 insertions, 265 deletions
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx b/jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx index 1771bcc018a5..d3ac1518a858 100644 --- a/jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx +++ b/jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx @@ -299,13 +299,15 @@ javaPluginError checkJavaVersionRequirements( } javaPluginError jfw_plugin_getAllJavaInfos( + bool checkJavaHomeAndPath, OUString const& sVendor, OUString const& sMinVersion, OUString const& sMaxVersion, rtl_uString * *arExcludeList, sal_Int32 nLenList, JavaInfo*** parJavaInfo, - sal_Int32 *nLenInfoList) + sal_Int32 *nLenInfoList, + std::vector<rtl::Reference<jfw_plugin::VendorBase>> & infos) { OSL_ASSERT(parJavaInfo); OSL_ASSERT(nLenInfoList); @@ -326,7 +328,7 @@ javaPluginError jfw_plugin_getAllJavaInfos( //Find all JREs vector<rtl::Reference<VendorBase> > vecInfos = - getAllJREInfos(); + addAllJREInfos(checkJavaHomeAndPath, infos); vector<rtl::Reference<VendorBase> > vecVerifiedInfos; typedef vector<rtl::Reference<VendorBase> >::iterator it; @@ -406,15 +408,17 @@ javaPluginError jfw_plugin_getJavaInfoByPath( javaPluginError jfw_plugin_getJavaInfoFromJavaHome( std::vector<pair<OUString, jfw::VersionInfo>> const& vecVendorInfos, - JavaInfo ** ppInfo) + JavaInfo ** ppInfo, std::vector<rtl::Reference<VendorBase>> & infos) { if (!ppInfo) return JFW_PLUGIN_E_INVALID_ARG; - rtl::Reference<VendorBase> infoJavaHome = getJavaInfoFromJavaHome(); + std::vector<rtl::Reference<VendorBase>> infoJavaHome; + addJavaInfoFromJavaHome(infos, infoJavaHome); - if (!infoJavaHome.is()) + if (infoJavaHome.empty()) return JFW_PLUGIN_E_NO_JRE; + assert(infoJavaHome.size() == 1); //Check if the detected JRE matches the version requirements typedef std::vector<pair<OUString, jfw::VersionInfo>>::const_iterator ci_pl; @@ -423,10 +427,10 @@ javaPluginError jfw_plugin_getJavaInfoFromJavaHome( const OUString& vendor = vendorInfo->first; jfw::VersionInfo versionInfo = vendorInfo->second; - if (vendor.equals(infoJavaHome->getVendor())) + if (vendor.equals(infoJavaHome[0]->getVendor())) { javaPluginError errorcode = checkJavaVersionRequirements( - infoJavaHome, + infoJavaHome[0], versionInfo.sMinVersion, versionInfo.sMaxVersion, versionInfo.getExcludeVersions(), @@ -434,7 +438,7 @@ javaPluginError jfw_plugin_getJavaInfoFromJavaHome( if (errorcode == JFW_PLUGIN_E_NONE) { - *ppInfo = createJavaInfo(infoJavaHome); + *ppInfo = createJavaInfo(infoJavaHome[0]); return JFW_PLUGIN_E_NONE; } } @@ -445,11 +449,12 @@ javaPluginError jfw_plugin_getJavaInfoFromJavaHome( javaPluginError jfw_plugin_getJavaInfosFromPath( std::vector<std::pair<OUString, jfw::VersionInfo>> const& vecVendorInfos, - std::vector<JavaInfo*> & javaInfosFromPath) + std::vector<JavaInfo*> & javaInfosFromPath, + std::vector<rtl::Reference<jfw_plugin::VendorBase>> & infos) { // find JREs from PATH vector<rtl::Reference<VendorBase>> vecInfosFromPath; - createJavaInfoFromPath(vecInfosFromPath); + addJavaInfosFromPath(infos, vecInfosFromPath); vector<rtl::Reference<VendorBase> > vecVerifiedInfos; diff --git a/jvmfwk/plugins/sunmajor/pluginlib/util.cxx b/jvmfwk/plugins/sunmajor/pluginlib/util.cxx index 621b3581af5f..7b29fafc32c1 100644 --- a/jvmfwk/plugins/sunmajor/pluginlib/util.cxx +++ b/jvmfwk/plugins/sunmajor/pluginlib/util.cxx @@ -139,23 +139,35 @@ bool decodeOutput(const OString& s, OUString* out); namespace { -bool getAndAddJREInfoByPath(const OUString& path, - std::vector<rtl::Reference<VendorBase> > & vecInfos) +bool addJREInfo( + rtl::Reference<VendorBase> const & info, + std::vector<rtl::Reference<VendorBase>> & infos) { - bool ret = false; + auto i( + std::find_if( + infos.begin(), infos.end(), InfoFindSame(info->getHome()))); + if (i == infos.end()) { + infos.push_back(info); + return true; + } else { + return false; + } +} +bool getAndAddJREInfoByPath( + const OUString& path, + std::vector<rtl::Reference<VendorBase> > & allInfos, + std::vector<rtl::Reference<VendorBase> > & addedInfos) +{ rtl::Reference<VendorBase> aInfo = getJREInfoByPath(path); - if (aInfo.is()) - { - ret = true; - vector<rtl::Reference<VendorBase> >::const_iterator it_impl= std::find_if( - vecInfos.begin(),vecInfos.end(), InfoFindSame(aInfo->getHome())); - if(it_impl == vecInfos.end()) - { - vecInfos.push_back(aInfo); + if (aInfo.is()) { + if (addJREInfo(aInfo, allInfos)) { + addedInfos.push_back(aInfo); } + return true; + } else { + return false; } - return ret; } OUString getLibraryLocation() @@ -572,7 +584,9 @@ bool decodeOutput(const OString& s, OUString* out) #if defined WNT -void createJavaInfoFromWinReg(std::vector<rtl::Reference<VendorBase> > & vecInfos) +void addJavaInfoFromWinReg( + std::vector<rtl::Reference<VendorBase> > & allInfos, + std::vector<rtl::Reference<VendorBase> > & addedInfos) { // Get Java s from registry std::vector<OUString> vecJavaHome; @@ -583,7 +597,7 @@ void createJavaInfoFromWinReg(std::vector<rtl::Reference<VendorBase> > & vecInfo for(ItHome it_home= vecJavaHome.begin(); it_home != vecJavaHome.end(); it_home++) { - getAndAddJREInfoByPath(*it_home, vecInfos); + getAndAddJREInfoByPath(*it_home, allInfos, addedInfos); } } @@ -594,7 +608,7 @@ void createJavaInfoFromWinReg(std::vector<rtl::Reference<VendorBase> > & vecInfo for(ItHome it_home= vecJavaHome.begin(); it_home != vecJavaHome.end(); it_home++) { - getAndAddJREInfoByPath(*it_home, vecInfos); + getAndAddJREInfoByPath(*it_home, allInfos, addedInfos); } } } @@ -736,8 +750,9 @@ void bubbleSortVersion(vector<rtl::Reference<VendorBase> >& vec) } -void getJREInfoFromBinPath( - const OUString& path, vector<rtl::Reference<VendorBase> > & vecInfos) +void addJREInfoFromBinPath( + const OUString& path, vector<rtl::Reference<VendorBase>> & allInfos, + std::vector<rtl::Reference<VendorBase>> & addedInfos) { // file:///c:/jre/bin //map: jre/bin/java.exe @@ -782,37 +797,41 @@ void getJREInfoFromBinPath( sHome = sBinPath.copy(index - 1); } } - if (!sHome.isEmpty()) + if (!sHome.isEmpty() + && getAndAddJREInfoByPath(path, allInfos, addedInfos)) { - if (getAndAddJREInfoByPath(sHome, vecInfos)) - return; + return; } } } } -vector<Reference<VendorBase> > getAllJREInfos() +vector<Reference<VendorBase> > addAllJREInfos( + bool checkJavaHomeAndPath, + std::vector<rtl::Reference<VendorBase>> & allInfos) { - vector<Reference<VendorBase> > vecInfos; + vector<Reference<VendorBase> > addedInfos; #if defined WNT // Get Javas from the registry - createJavaInfoFromWinReg(vecInfos); + addJavaInfoFromWinReg(allInfos, addedInfos); #endif // WNT #ifndef JVM_ONE_PATH_CHECK - createJavaInfoFromJavaHome(vecInfos); - //this function should be called after createJavaInfoDirScan. - //Otherwise in SDKs Java may be started twice - createJavaInfoFromPath(vecInfos); + if (checkJavaHomeAndPath) { + addJavaInfoFromJavaHome(allInfos, addedInfos); + //this function should be called after addJavaInfosDirScan. + //Otherwise in SDKs Java may be started twice + addJavaInfosFromPath(allInfos, addedInfos); + } #endif #ifdef UNX - createJavaInfoDirScan(vecInfos); + addJavaInfosDirScan(allInfos, addedInfos); #endif - bubbleSortVersion(vecInfos); - return vecInfos; + bubbleSortVersion(addedInfos); + return addedInfos; } @@ -1080,7 +1099,9 @@ inline OUString getDirFromFile(const OUString& usFilePath) return usFilePath.copy(0, index); } -void createJavaInfoFromPath(vector<rtl::Reference<VendorBase> >& vecInfos) +void addJavaInfosFromPath( + std::vector<rtl::Reference<VendorBase>> & allInfos, + std::vector<rtl::Reference<VendorBase>> & addedInfos) { // Get Java from PATH environment variable static const char sCurDir[] = "."; @@ -1119,7 +1140,7 @@ void createJavaInfoFromPath(vector<rtl::Reference<VendorBase> >& vecInfos) } if(!usBin.isEmpty()) { - getJREInfoFromBinPath(usBin, vecInfos); + addJREInfoFromBinPath(usBin, allInfos, addedInfos); } } } @@ -1129,7 +1150,9 @@ void createJavaInfoFromPath(vector<rtl::Reference<VendorBase> >& vecInfos) } -rtl::Reference<VendorBase> getJavaInfoFromJavaHome() +void addJavaInfoFromJavaHome( + std::vector<rtl::Reference<VendorBase>> & allInfos, + std::vector<rtl::Reference<VendorBase>> & addedInfos) { // Get Java from JAVA_HOME environment @@ -1144,24 +1167,7 @@ rtl::Reference<VendorBase> getJavaInfoFromJavaHome() OUString sHomeUrl; if(File::getFileURLFromSystemPath(sHome, sHomeUrl) == File::E_None) { - return getJREInfoByPath(sHomeUrl); - } - } - - return NULL; -} - -void createJavaInfoFromJavaHome(vector<rtl::Reference<VendorBase> >& vecInfos) -{ - rtl::Reference<VendorBase> aInfo = getJavaInfoFromJavaHome(); - - if (aInfo.is()) - { - vector<rtl::Reference<VendorBase> >::const_iterator it_impl= std::find_if( - vecInfos.begin(),vecInfos.end(), InfoFindSame(aInfo->getHome())); - if(it_impl == vecInfos.end()) - { - vecInfos.push_back(aInfo); + getAndAddJREInfoByPath(sHomeUrl, allInfos, addedInfos); } } } @@ -1185,25 +1191,31 @@ bool makeDriveLetterSame(OUString * fileURL) #ifdef UNX #ifdef SOLARIS -void createJavaInfoDirScan(vector<rtl::Reference<VendorBase> >& vecInfos) +void addJavaInfosDirScan( + std::vector<rtl::Reference<VendorBase>> & allInfos, + std::vector<rtl::Reference<VendorBase>> & addedInfos) { JFW_TRACE2("Checking /usr/jdk/latest"); - getAndAddJREInfoByPath("file:////usr/jdk/latest", vecInfos); + getAndAddJREInfoByPath("file:////usr/jdk/latest", allInfos, addedInfos); } #elif defined MACOSX && defined X86_64 -void createJavaInfoDirScan(vector<rtl::Reference<VendorBase> >& vecInfos) +void addJavaInfosDirScan( + std::vector<rtl::Reference<VendorBase>> & allInfos, + std::vector<rtl::Reference<VendorBase>> & addedInfos) { // Oracle Java 7 - getAndAddJREInfoByPath("file:///Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home", vecInfos); + getAndAddJREInfoByPath("file:///Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home", allInfos, addedInfos); } #else -void createJavaInfoDirScan(vector<rtl::Reference<VendorBase> >& vecInfos) +void addJavaInfosDirScan( + std::vector<rtl::Reference<VendorBase>> & allInfos, + std::vector<rtl::Reference<VendorBase>> & addedInfos) { OUString excMessage = "[Java framework] sunjavaplugin: " - "Error in function createJavaInfoDirScan in util.cxx."; + "Error in function addJavaInfosDirScan in util.cxx."; int cJavaNames= sizeof(g_arJavaNames) / sizeof(char*); boost::scoped_array<OUString> sarJavaNames(new OUString[cJavaNames]); OUString *arNames = sarJavaNames.get(); @@ -1273,7 +1285,8 @@ void createJavaInfoDirScan(vector<rtl::Reference<VendorBase> >& vecInfos) } JFW_TRACE2("Checking if directory: " << aStatus.getFileURL() << " is a Java"); - getAndAddJREInfoByPath(aStatus.getFileURL(),vecInfos); + getAndAddJREInfoByPath( + aStatus.getFileURL(), allInfos, addedInfos); } JFW_ENSURE(errNext == File::E_None || errNext == File::E_NOENT, @@ -1305,7 +1318,8 @@ void createJavaInfoDirScan(vector<rtl::Reference<VendorBase> >& vecInfos) && (islash > RTL_CONSTASCII_LENGTH("file://"))) usDir3 = usDir3.copy(0, islash); - getAndAddJREInfoByPath(usDir3,vecInfos); + getAndAddJREInfoByPath( + usDir3, allInfos, addedInfos); } } } diff --git a/jvmfwk/plugins/sunmajor/pluginlib/util.hxx b/jvmfwk/plugins/sunmajor/pluginlib/util.hxx index 18232e8eae07..ffe07c21abfa 100644 --- a/jvmfwk/plugins/sunmajor/pluginlib/util.hxx +++ b/jvmfwk/plugins/sunmajor/pluginlib/util.hxx @@ -35,21 +35,25 @@ std::vector<OUString> getVectorFromCharArray(char const * const * ar, int size); argument to getJREInfoByPath. For example usBinDir is file:///c:/j2sdk/jre/bin then file:///c:/j2sdk/jre would be derived. */ -void getJREInfoFromBinPath( - const OUString& path, std::vector<rtl::Reference<VendorBase> > & vecInfos); +void addJREInfoFromBinPath( + const OUString& path, + std::vector<rtl::Reference<VendorBase>> & allInfos, + std::vector<rtl::Reference<VendorBase>> & addedInfos); inline OUString getDirFromFile(const OUString& usFilePath); -void createJavaInfoFromPath(std::vector<rtl::Reference<VendorBase> >& vecInfos); +void addJavaInfosFromPath( + std::vector<rtl::Reference<VendorBase>> & allInfos, + std::vector<rtl::Reference<VendorBase>> & addedInfos); /* Returns a VendorBase object if JAVA_HOME environment variable points to a JRE. */ -rtl::Reference<VendorBase> getJavaInfoFromJavaHome(); +void addJavaInfoFromJavaHome( + std::vector<rtl::Reference<VendorBase>> & allInfos, + std::vector<rtl::Reference<VendorBase>> & addedInfos); -void createJavaInfoFromJavaHome(std::vector<rtl::Reference<VendorBase> > &vecInfos); -void createJavaInfoDirScan(std::vector<rtl::Reference<VendorBase> >& vecInfos); -#ifdef WNT -void createJavaInfoFromWinReg(std::vector<rtl::Reference<VendorBase> >& vecInfos); -#endif +void addJavaInfosDirScan( + std::vector<rtl::Reference<VendorBase>> & allInfos, + std::vector<rtl::Reference<VendorBase>> & addedInfos); bool makeDriveLetterSame(OUString * fileURL); @@ -95,7 +99,8 @@ struct SameOrSubDirJREMap */ rtl::Reference<VendorBase> getJREInfoByPath(const OUString& path); -std::vector<rtl::Reference<VendorBase> > getAllJREInfos(); +std::vector<rtl::Reference<VendorBase> > addAllJREInfos( + bool checkJavaHomeAndPath, std::vector<rtl::Reference<VendorBase>> & infos); bool getJavaProps( const OUString & exePath, @@ -105,8 +110,6 @@ bool getJavaProps( std::vector<std::pair<OUString, OUString> >& props, bool * bProcessRun); -void createJavaInfoFromWinReg(std::vector<rtl::Reference<VendorBase> > & vecInfos); - void bubbleSortVersion(std::vector<rtl::Reference<VendorBase> >& vec); rtl::Bootstrap* getBootstrap(); diff --git a/jvmfwk/plugins/sunmajor/pluginlib/vendorbase.hxx b/jvmfwk/plugins/sunmajor/pluginlib/vendorbase.hxx deleted file mode 100644 index 2ecd01ff710e..000000000000 --- a/jvmfwk/plugins/sunmajor/pluginlib/vendorbase.hxx +++ /dev/null @@ -1,184 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#ifndef INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_VENDORBASE_HXX -#define INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_VENDORBASE_HXX - -#include "rtl/ustring.hxx" -#include "rtl/ref.hxx" -#include "osl/endian.h" -#include "salhelper/simplereferenceobject.hxx" -#include <vector> - -namespace jfw_plugin -{ - - -//Used by subclasses of VendorBase to build paths to Java runtime -#if defined(__sparcv9) -#define JFW_PLUGIN_ARCH "sparcv9" -#elif defined SPARC -#define JFW_PLUGIN_ARCH "sparc" -#elif defined X86_64 -#define JFW_PLUGIN_ARCH "amd64" -#elif defined INTEL -#define JFW_PLUGIN_ARCH "i386" -#elif defined POWERPC64 -#define JFW_PLUGIN_ARCH "ppc64" -#elif defined POWERPC -#define JFW_PLUGIN_ARCH "ppc" -#elif defined MIPS -#ifdef OSL_BIGENDIAN -# define JFW_PLUGIN_ARCH "mips" -#else -/* FIXME: do JDKs have some JDK-specific define? This is for -OpenJDK at least, but probably not true for Lemotes JDK */ -# define JFW_PLUGIN_ARCH "mipsel" -#endif -#elif defined S390X -#define JFW_PLUGIN_ARCH "s390x" -#elif defined S390 -#define JFW_PLUGIN_ARCH "s390" -#elif defined ARM -#define JFW_PLUGIN_ARCH "arm" -#elif defined IA64 -#define JFW_PLUGIN_ARCH "ia64" -#elif defined M68K -#define JFW_PLUGIN_ARCH "m68k" -#elif defined HPPA -#define JFW_PLUGIN_ARCH "parisc" -#elif defined AXP -#define JFW_PLUGIN_ARCH "alpha" -#elif defined AARCH64 -#define JFW_PLUGIN_ARCH "aarch64" -#else // SPARC, INTEL, POWERPC, MIPS, ARM, IA64, M68K, HPPA, ALPHA -#error unknown platform -#endif // SPARC, INTEL, POWERPC, MIPS, ARM, IA64, M68K, HPPA, ALPHA - - -class MalformedVersionException -{ -public: - MalformedVersionException(); - - MalformedVersionException(const MalformedVersionException &); - - virtual ~MalformedVersionException(); - - MalformedVersionException & operator =(const MalformedVersionException &); -}; - -class VendorBase: public salhelper::SimpleReferenceObject -{ -public: - VendorBase(); - /* static char const* const * getJavaExePaths(int* size); - - returns relative paths to the java executable as - file URLs. - - For example "bin/java.exe". You need - to implement this function in a derived class, if - the paths differ. this implmentation provides for - Windows "bin/java.exe" and for Unix "bin/java". - The paths are relative file URLs. That is, they always - contain '/' even on windows. The paths are relative - to the installation directory of a JRE. - - - The signature of this function must correspond to - getJavaExePaths_func. - */ - - /* static rtl::Reference<VendorBase> createInstance(); - - creates an instance of this class. MUST be overridden - in a derived class. - #################################################### - OVERRIDE in derived class - ################################################### - @param - Key - value pairs of the system properties of the JRE. - */ - - const OUString & getVendor() const; - const OUString & getVersion() const; - const OUString & getHome() const; - const OUString & getRuntimeLibrary() const; - const OUString & getLibraryPath() const; - bool supportsAccessibility() const; - /* determines if prior to running java something has to be done, - like setting the LD_LIBRARY_PATH. This implementation checks - if an LD_LIBRARY_PATH (getLD_LIBRARY_PATH) needs to be set and - if so, needsRestart returns true. - */ - bool needsRestart() const; - - /* compares versions of this vendor. MUST be overridden - in a derived class. - #################################################### - OVERRIDE in derived class - ################################################### - @return - 0 this.version == sSecond - 1 this.version > sSecond - -1 this.version < sSEcond - - @throw - MalformedVersionException if the version string was not recognized. - */ - virtual int compareVersions(const OUString& sSecond) const = 0; - -protected: - /* called automatically on the instance created by createInstance. - - @return - true - the object could completely initialize. - false - the object could not completely initialize. In this case - it will be discarded by the caller. - */ - virtual bool initialize( - std::vector<std::pair<OUString, OUString> > props); - - /* returns relative file URLs to the runtime library. - For example "/bin/client/jvm.dll" - */ - virtual char const* const* getRuntimePaths(int* size) = 0; - - virtual char const* const* getLibraryPaths(int* size) = 0; - - OUString m_sVendor; - OUString m_sVersion; - OUString m_sHome; - OUString m_sRuntimeLibrary; - OUString m_sLD_LIBRARY_PATH; - bool m_bAccessibility; - - - typedef rtl::Reference<VendorBase> (* createInstance_func) (); - friend rtl::Reference<VendorBase> createInstance( - createInstance_func pFunc, - std::vector<std::pair<OUString, OUString> > properties); -}; - -} - -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |