Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / scripting / source / stringresource / stringresource.hxx
blob5e65f06f09b3e2fe17d22dff417fc7efc89ffc5e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifndef INCLUDED_SCRIPTING_SOURCE_STRINGRESOURCE_STRINGRESOURCE_HXX
21 #define INCLUDED_SCRIPTING_SOURCE_STRINGRESOURCE_STRINGRESOURCE_HXX
23 #include <com/sun/star/resource/XStringResourceWithStorage.hpp>
24 #include <com/sun/star/resource/XStringResourceWithLocation.hpp>
25 #include <com/sun/star/lang/XServiceInfo.hpp>
26 #include <com/sun/star/lang/XInitialization.hpp>
27 #include <com/sun/star/uno/XComponentContext.hpp>
28 #include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
29 #include <com/sun/star/io/XInputStream.hpp>
30 #include <com/sun/star/io/XOutputStream.hpp>
31 #include <cppuhelper/implbase.hxx>
32 #include <comphelper/interfacecontainer2.hxx>
33 #include <osl/mutex.hxx>
35 #include <unordered_map>
36 #include <vector>
39 namespace stringresource
43 // mutex
46 ::osl::Mutex& getMutex();
49 // class stringresourceImpl
52 // Hashtable to map string ids to string
53 typedef std::unordered_map
55 OUString,
56 OUString
58 IdToStringMap;
60 typedef std::unordered_map
62 OUString,
63 sal_Int32
65 IdToIndexMap;
68 struct LocaleItem
70 css::lang::Locale m_locale;
71 IdToStringMap m_aIdToStringMap;
72 IdToIndexMap m_aIdToIndexMap;
73 sal_Int32 m_nNextIndex;
74 bool m_bLoaded;
75 bool m_bModified;
77 LocaleItem( css::lang::Locale locale, bool bLoaded=true )
78 : m_locale( locale )
79 , m_nNextIndex( 0 )
80 , m_bLoaded( bLoaded )
81 , m_bModified( false )
85 typedef std::vector< std::unique_ptr<LocaleItem> > LocaleItemVector;
87 typedef ::cppu::WeakImplHelper<
88 css::lang::XServiceInfo,
89 css::resource::XStringResourceManager > StringResourceImpl_BASE;
91 class StringResourceImpl : public StringResourceImpl_BASE
93 protected:
94 css::uno::Reference< css::uno::XComponentContext > m_xContext;
96 LocaleItem* m_pCurrentLocaleItem;
97 LocaleItem* m_pDefaultLocaleItem;
98 bool m_bDefaultModified;
100 ::comphelper::OInterfaceContainerHelper2 m_aListenerContainer;
102 std::vector< std::unique_ptr<LocaleItem> > m_aLocaleItemVector;
103 std::vector< std::unique_ptr<LocaleItem> > m_aDeletedLocaleItemVector;
104 LocaleItemVector m_aChangedDefaultLocaleVector;
106 bool m_bModified;
107 bool m_bReadOnly;
109 sal_Int32 m_nNextUniqueNumericId;
111 // Scans ResourceID to start with number and adapt m_nNextUniqueNumericId
112 void implScanIdForNumber( const OUString& ResourceID );
113 const static sal_Int32 UNIQUE_NUMBER_NEEDS_INITIALISATION = -1;
115 // Checks read only status and throws exception if it's true
116 /// @throws css::lang::NoSupportException
117 void implCheckReadOnly( const sal_Char* pExceptionMsg );
119 // Returns the LocalItem for a given locale, if it exists, otherwise NULL
120 // This method compares the locales exactly, no closest match search is performed
121 /// @throws css::lang::IllegalArgumentException
122 LocaleItem* getItemForLocale( const css::lang::Locale& locale, bool bException );
124 // Returns the LocalItem for a given locale, if it exists, otherwise NULL
125 // This method performs a closest match search, at least the language must match
126 LocaleItem* getClosestMatchItemForLocale( const css::lang::Locale& locale );
127 /// @throws css::lang::IllegalArgumentException
128 /// @throws css::uno::RuntimeException
129 void implSetCurrentLocale( const css::lang::Locale& locale,
130 bool FindClosestMatch, bool bUseDefaultIfNoMatch );
132 void implModified();
133 void implNotifyListeners();
135 //=== Impl methods for ...ForLocale methods ===
136 /// @throws css::resource::MissingResourceException
137 OUString implResolveString( const OUString& ResourceID, LocaleItem* pLocaleItem );
138 bool implHasEntryForId( const OUString& ResourceID, LocaleItem* pLocaleItem );
139 css::uno::Sequence< OUString > implGetResourceIDs( LocaleItem* pLocaleItem );
140 void implSetString( const OUString& ResourceID,
141 const OUString& Str, LocaleItem* pLocaleItem );
142 /// @throws css::resource::MissingResourceException
143 void implRemoveId( const OUString& ResourceID, LocaleItem* pLocaleItem );
145 // Method to load a locale if necessary, returns true if loading was
146 // successful. Default implementation in base class just returns true.
147 virtual bool loadLocale( LocaleItem* pLocaleItem );
149 virtual void implLoadAllLocales();
151 public:
152 explicit StringResourceImpl(
153 const css::uno::Reference< css::uno::XComponentContext >& rxContext );
154 virtual ~StringResourceImpl() override;
156 // XServiceInfo
157 virtual OUString SAL_CALL getImplementationName( ) override;
158 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
159 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
161 // XModifyBroadcaster
162 virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
163 virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
165 // XStringResourceResolver
166 virtual OUString SAL_CALL resolveString( const OUString& ResourceID ) override;
167 virtual OUString SAL_CALL resolveStringForLocale( const OUString& ResourceID,
168 const css::lang::Locale& locale ) override;
169 virtual sal_Bool SAL_CALL hasEntryForId( const OUString& ResourceID ) override;
170 virtual sal_Bool SAL_CALL hasEntryForIdAndLocale( const OUString& ResourceID,
171 const css::lang::Locale& locale ) override;
172 virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDs( ) override;
173 virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDsForLocale
174 ( const css::lang::Locale& locale ) override;
175 virtual css::lang::Locale SAL_CALL getCurrentLocale( ) override;
176 virtual css::lang::Locale SAL_CALL getDefaultLocale( ) override;
177 virtual css::uno::Sequence< css::lang::Locale > SAL_CALL getLocales( ) override;
179 // XStringResourceManager
180 virtual sal_Bool SAL_CALL isReadOnly() override;
181 virtual void SAL_CALL setCurrentLocale( const css::lang::Locale& locale, sal_Bool FindClosestMatch ) override;
182 virtual void SAL_CALL setDefaultLocale( const css::lang::Locale& locale ) override;
183 virtual void SAL_CALL setString( const OUString& ResourceID, const OUString& Str ) override;
184 virtual void SAL_CALL setStringForLocale( const OUString& ResourceID, const OUString& Str,
185 const css::lang::Locale& locale ) override;
186 virtual void SAL_CALL removeId( const OUString& ResourceID ) override;
187 virtual void SAL_CALL removeIdForLocale( const OUString& ResourceID,
188 const css::lang::Locale& locale ) override;
189 virtual void SAL_CALL newLocale( const css::lang::Locale& locale ) override;
190 virtual void SAL_CALL removeLocale( const css::lang::Locale& locale ) override;
191 virtual ::sal_Int32 SAL_CALL getUniqueNumericId( ) override;
194 typedef ::cppu::ImplInheritanceHelper<
195 StringResourceImpl,
196 css::resource::XStringResourcePersistence > StringResourcePersistenceImpl_BASE;
198 class BinaryOutput;
200 class StringResourcePersistenceImpl : public StringResourcePersistenceImpl_BASE
202 protected:
203 OUString m_aNameBase;
204 OUString m_aComment;
206 /// @throws css::uno::Exception
207 /// @throws css::uno::RuntimeException
208 void implInitializeCommonParameters( const css::uno::Sequence< css::uno::Any >& aArguments );
210 // Scan locale properties files
211 virtual void implScanLocales();
213 // Method to load a locale if necessary, returns true if loading was successful
214 virtual bool loadLocale( LocaleItem* pLocaleItem ) override;
216 // does the actual loading
217 virtual bool implLoadLocale( LocaleItem* pLocaleItem );
219 virtual void implLoadAllLocales() override;
221 void implScanLocaleNames( const css::uno::Sequence< OUString >& aContentSeq );
222 static OUString implGetFileNameForLocaleItem( LocaleItem const * pLocaleItem, const OUString& aNameBase );
223 static OUString implGetPathForLocaleItem( LocaleItem const * pLocaleItem, const OUString& aNameBase,
224 const OUString& aLocation, bool bDefaultFile=false );
226 bool implReadPropertiesFile( LocaleItem* pLocaleItem,
227 const css::uno::Reference< css::io::XInputStream >& xInput );
229 bool implWritePropertiesFile( LocaleItem const * pLocaleItem,
230 const css::uno::Reference< css::io::XOutputStream >& xOutputStream,
231 const OUString& aComment );
233 void implWriteLocaleBinary( LocaleItem* pLocaleItem, BinaryOutput& rOut );
235 /// @throws css::uno::Exception
236 /// @throws css::uno::RuntimeException
237 void implStoreAtStorage
239 const OUString& aNameBase,
240 const OUString& aComment,
241 const css::uno::Reference< css::embed::XStorage >& Storage,
242 bool bUsedForStore,
243 bool bStoreAll
246 /// @throws css::uno::Exception
247 /// @throws css::uno::RuntimeException
248 void implKillRemovedLocaleFiles
250 const OUString& Location,
251 const OUString& aNameBase,
252 const css::uno::Reference< css::ucb::XSimpleFileAccess3 >& xFileAccess
255 /// @throws css::uno::Exception
256 /// @throws css::uno::RuntimeException
257 void implKillChangedDefaultFiles
259 const OUString& Location,
260 const OUString& aNameBase,
261 const css::uno::Reference< css::ucb::XSimpleFileAccess3 >& xFileAccess
264 /// @throws css::uno::Exception
265 /// @throws css::uno::RuntimeException
266 void implStoreAtLocation
268 const OUString& Location,
269 const OUString& aNameBase,
270 const OUString& aComment,
271 const css::uno::Reference< css::ucb::XSimpleFileAccess3 >& xFileAccess,
272 bool bUsedForStore,
273 bool bStoreAll,
274 bool bKillAll = false
277 public:
278 explicit StringResourcePersistenceImpl(
279 const css::uno::Reference< css::uno::XComponentContext >& rxContext );
280 virtual ~StringResourcePersistenceImpl() override;
282 // XServiceInfo
283 virtual OUString SAL_CALL getImplementationName( ) override;
284 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
285 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
287 // XModifyBroadcaster
288 virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
289 virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
291 // XStringResourceResolver
292 virtual OUString SAL_CALL resolveString( const OUString& ResourceID ) override;
293 virtual OUString SAL_CALL resolveStringForLocale( const OUString& ResourceID,
294 const css::lang::Locale& locale ) override;
295 virtual sal_Bool SAL_CALL hasEntryForId( const OUString& ResourceID ) override;
296 virtual sal_Bool SAL_CALL hasEntryForIdAndLocale( const OUString& ResourceID,
297 const css::lang::Locale& locale ) override;
298 virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDs( ) override;
299 virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDsForLocale
300 ( const css::lang::Locale& locale ) override;
301 virtual css::lang::Locale SAL_CALL getCurrentLocale( ) override;
302 virtual css::lang::Locale SAL_CALL getDefaultLocale( ) override;
303 virtual css::uno::Sequence< css::lang::Locale > SAL_CALL getLocales( ) override;
305 // XStringResourceManager
306 virtual sal_Bool SAL_CALL isReadOnly() override;
307 virtual void SAL_CALL setCurrentLocale( const css::lang::Locale& locale, sal_Bool FindClosestMatch ) override;
308 virtual void SAL_CALL setDefaultLocale( const css::lang::Locale& locale ) override;
309 virtual void SAL_CALL setString( const OUString& ResourceID, const OUString& Str ) override;
310 virtual void SAL_CALL setStringForLocale( const OUString& ResourceID, const OUString& Str,
311 const css::lang::Locale& locale ) override;
312 virtual void SAL_CALL removeId( const OUString& ResourceID ) override;
313 virtual void SAL_CALL removeIdForLocale( const OUString& ResourceID,
314 const css::lang::Locale& locale ) override;
315 virtual void SAL_CALL newLocale( const css::lang::Locale& locale ) override;
316 virtual void SAL_CALL removeLocale( const css::lang::Locale& locale ) override;
317 virtual ::sal_Int32 SAL_CALL getUniqueNumericId( ) override;
319 // XStringResourcePersistence
320 virtual void SAL_CALL store( ) override;
321 virtual sal_Bool SAL_CALL isModified( ) override;
322 virtual void SAL_CALL setComment( const OUString& Comment ) override;
323 virtual void SAL_CALL storeToStorage
324 ( const css::uno::Reference< css::embed::XStorage >& Storage,
325 const OUString& NameBase, const OUString& Comment ) override;
326 virtual void SAL_CALL storeToURL( const OUString& URL, const OUString& NameBase,
327 const OUString& Comment, const css::uno::Reference
328 < css::task::XInteractionHandler >& Handler ) override;
329 virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL exportBinary( ) override;
330 virtual void SAL_CALL importBinary( const css::uno::Sequence< ::sal_Int8 >& Data ) override;
334 typedef ::cppu::ImplInheritanceHelper<
335 StringResourcePersistenceImpl,
336 css::lang::XInitialization,
337 css::resource::XStringResourceWithStorage > StringResourceWithStorageImpl_BASE;
339 class StringResourceWithStorageImpl : public StringResourceWithStorageImpl_BASE
341 css::uno::Reference< css::embed::XStorage > m_xStorage;
342 bool m_bStorageChanged;
344 virtual void implScanLocales() override;
345 virtual bool implLoadLocale( LocaleItem* pLocaleItem ) override;
347 public:
348 explicit StringResourceWithStorageImpl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
349 virtual ~StringResourceWithStorageImpl() override;
351 // XServiceInfo
352 virtual OUString SAL_CALL getImplementationName( ) override;
353 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
354 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
356 // XInitialization
357 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
359 // XModifyBroadcaster
360 virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
361 virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
363 // XStringResourceResolver
364 virtual OUString SAL_CALL resolveString( const OUString& ResourceID ) override;
365 virtual OUString SAL_CALL resolveStringForLocale( const OUString& ResourceID,
366 const css::lang::Locale& locale ) override;
367 virtual sal_Bool SAL_CALL hasEntryForId( const OUString& ResourceID ) override;
368 virtual sal_Bool SAL_CALL hasEntryForIdAndLocale( const OUString& ResourceID,
369 const css::lang::Locale& locale ) override;
370 virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDs( ) override;
371 virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDsForLocale
372 ( const css::lang::Locale& locale ) override;
373 virtual css::lang::Locale SAL_CALL getCurrentLocale( ) override;
374 virtual css::lang::Locale SAL_CALL getDefaultLocale( ) override;
375 virtual css::uno::Sequence< css::lang::Locale > SAL_CALL getLocales( ) override;
377 // XStringResourceManager
378 virtual sal_Bool SAL_CALL isReadOnly() override;
379 virtual void SAL_CALL setCurrentLocale( const css::lang::Locale& locale, sal_Bool FindClosestMatch ) override;
380 virtual void SAL_CALL setDefaultLocale( const css::lang::Locale& locale ) override;
381 virtual void SAL_CALL setString( const OUString& ResourceID, const OUString& Str ) override;
382 virtual void SAL_CALL setStringForLocale( const OUString& ResourceID, const OUString& Str,
383 const css::lang::Locale& locale ) override;
384 virtual void SAL_CALL removeId( const OUString& ResourceID ) override;
385 virtual void SAL_CALL removeIdForLocale( const OUString& ResourceID,
386 const css::lang::Locale& locale ) override;
387 virtual void SAL_CALL newLocale( const css::lang::Locale& locale ) override;
388 virtual void SAL_CALL removeLocale( const css::lang::Locale& locale ) override;
389 virtual ::sal_Int32 SAL_CALL getUniqueNumericId( ) override;
391 // XStringResourcePersistence
392 virtual void SAL_CALL store( ) override;
393 virtual sal_Bool SAL_CALL isModified( ) override;
394 virtual void SAL_CALL setComment( const OUString& Comment ) override;
395 virtual void SAL_CALL storeToStorage
396 ( const css::uno::Reference< css::embed::XStorage >& Storage,
397 const OUString& NameBase, const OUString& Comment ) override;
398 virtual void SAL_CALL storeToURL( const OUString& URL, const OUString& NameBase,
399 const OUString& Comment, const css::uno::Reference
400 < css::task::XInteractionHandler >& Handler ) override;
401 virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL exportBinary( ) override;
402 virtual void SAL_CALL importBinary( const css::uno::Sequence< ::sal_Int8 >& Data ) override;
404 // XStringResourceWithStorage
405 virtual void SAL_CALL storeAsStorage
406 ( const css::uno::Reference< css::embed::XStorage >& Storage ) override;
407 virtual void SAL_CALL setStorage
408 ( const css::uno::Reference< css::embed::XStorage >& Storage ) override;
412 typedef ::cppu::ImplInheritanceHelper<
413 StringResourcePersistenceImpl,
414 css::lang::XInitialization,
415 css::resource::XStringResourceWithLocation > StringResourceWithLocationImpl_BASE;
417 class StringResourceWithLocationImpl : public StringResourceWithLocationImpl_BASE
419 OUString m_aLocation;
420 bool m_bLocationChanged;
421 css::uno::Reference< css::ucb::XSimpleFileAccess3 > m_xSFI;
422 css::uno::Reference< css::task::XInteractionHandler > m_xInteractionHandler;
424 const css::uno::Reference< css::ucb::XSimpleFileAccess3 > & getFileAccess();
426 virtual void implScanLocales() override;
427 virtual bool implLoadLocale( LocaleItem* pLocaleItem ) override;
429 public:
430 explicit StringResourceWithLocationImpl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
431 virtual ~StringResourceWithLocationImpl() override;
433 // XServiceInfo
434 virtual OUString SAL_CALL getImplementationName( ) override;
435 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
436 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
438 // XInitialization
439 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
441 // XModifyBroadcaster
442 virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
443 virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
445 // XStringResourceResolver
446 virtual OUString SAL_CALL resolveString( const OUString& ResourceID ) override;
447 virtual OUString SAL_CALL resolveStringForLocale( const OUString& ResourceID,
448 const css::lang::Locale& locale ) override;
449 virtual sal_Bool SAL_CALL hasEntryForId( const OUString& ResourceID ) override;
450 virtual sal_Bool SAL_CALL hasEntryForIdAndLocale( const OUString& ResourceID,
451 const css::lang::Locale& locale ) override;
452 virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDs( ) override;
453 virtual css::uno::Sequence< OUString > SAL_CALL getResourceIDsForLocale
454 ( const css::lang::Locale& locale ) override;
455 virtual css::lang::Locale SAL_CALL getCurrentLocale( ) override;
456 virtual css::lang::Locale SAL_CALL getDefaultLocale( ) override;
457 virtual css::uno::Sequence< css::lang::Locale > SAL_CALL getLocales( ) override;
459 // XStringResourceManager
460 virtual sal_Bool SAL_CALL isReadOnly() override;
461 virtual void SAL_CALL setCurrentLocale( const css::lang::Locale& locale, sal_Bool FindClosestMatch ) override;
462 virtual void SAL_CALL setDefaultLocale( const css::lang::Locale& locale ) override;
463 virtual void SAL_CALL setString( const OUString& ResourceID, const OUString& Str ) override;
464 virtual void SAL_CALL setStringForLocale( const OUString& ResourceID, const OUString& Str,
465 const css::lang::Locale& locale ) override;
466 virtual void SAL_CALL removeId( const OUString& ResourceID ) override;
467 virtual void SAL_CALL removeIdForLocale( const OUString& ResourceID,
468 const css::lang::Locale& locale ) override;
469 virtual void SAL_CALL newLocale( const css::lang::Locale& locale ) override;
470 virtual void SAL_CALL removeLocale( const css::lang::Locale& locale ) override;
471 virtual ::sal_Int32 SAL_CALL getUniqueNumericId( ) override;
473 // XStringResourcePersistence
474 virtual void SAL_CALL store( ) override;
475 virtual sal_Bool SAL_CALL isModified( ) override;
476 virtual void SAL_CALL setComment( const OUString& Comment ) override;
477 virtual void SAL_CALL storeToStorage
478 ( const css::uno::Reference< css::embed::XStorage >& Storage,
479 const OUString& NameBase, const OUString& Comment ) override;
480 virtual void SAL_CALL storeToURL( const OUString& URL, const OUString& NameBase,
481 const OUString& Comment, const css::uno::Reference
482 < css::task::XInteractionHandler >& Handler ) override;
483 virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL exportBinary( ) override;
484 virtual void SAL_CALL importBinary( const css::uno::Sequence< ::sal_Int8 >& Data ) override;
486 // XStringResourceWithLocation
487 virtual void SAL_CALL storeAsURL( const OUString& URL ) override;
488 virtual void SAL_CALL setURL( const OUString& URL ) override;
492 } // namespace stringtable
495 #endif // INCLUDED_SCRIPTING_SOURCE_STRINGRESOURCE_STRINGRESOURCE_HXX
497 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */