Commit 27819858 authored by Kasper Skårhøj's avatar Kasper Skårhøj
Browse files

Updates mainly to import/export extension. Many smaller changes / additions....

Updates mainly to import/export extension. Many smaller changes / additions. See changelog for details.


git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@520 709f56b5-9817-0410-a4d7-c38de5d9e867
parent 9c8716c4
2004-12-17 Kasper Skårhøj,,, <kasper@typo3.com>
* Mainly: Did tons of improvements on the import/export module (system extension "impexp").
Main features:
Supports flexforms (hence TEmplaVoila).
Supports RTE embedded images.
Supports updates of existing records in various forms.
Has optional XML format.
Supports a new concept called "soft references" which are plain-text links/file references/markers and allows to track and include these in export. Examples are "fileadmin/..." references in TypoScript templates and <link> typolink tags.
Can export from the page tree root.
Character set dependant
Extension dependencies can be set
Embedding of HTML files and internal resources
Export links directly from clipboard and Web>List
Supports meta data including embedded thumbnail
* In shortcut frame I added possibility to enter a table:uid pair in the "Edit page" box. For instance "tt_content:123" will launch the doc module for that element.
* Soft References; A parser-concept tied to TCA which allows to define parsers for certain fields that finds "soft references", eg. <link> tags, file-references etc. See import/export improvements above.
* Improvements to array2xml which allows detained mapping of array keys to XML-tags. As an example, study the import/export extensions T3RecordDocument configuration.
* Improved t3lib_parsehtml::prefixResourcePath() to access a suffix string to WRAP file references
* Improved t3lib_tcemain with support for forcing a UID for newly created records (used by import/export)
* t3lib_tcemain::checkValue_flex_procInData_travDS() now supports callback functions from external objects
* Changed "displayErrors" in config_default.php BACK to "-1" which corresponds to the default from before (notice this, stucki!)
* Ended the regime of the new be-usergroup selection box - back to the previous with ordering of backend groups since the first group was significant (being the default owner group)
* Added support for having temporary files in typo3temp/ prefixed with a meaningful prefix, typically coming from the menu title, original image name etc.
2004-11-28 Kasper Skårhøj,,, <kasper@typo3.com>
* Main feature: Lots of updates on Indexed Search extension. The changes are mainly in the indexer, not the search plugin. The work is NOT FINISHED yet and don't update a production site with this work! One main thing to be aware of is that all indexing is done internally as utf-8. You should flush your old index tables before running the new one.
......@@ -6,7 +33,7 @@
* Fixed order of configuration forms in Extension Manager
* Added timezone option in TYPO3_CONF_VARS array
* Added right-click feature on context menus. Can be disabled with TYPO3_CONF_VARS if you don't like it. And a rightclick on the page/folder _title_ will also activate the menu! Theoretically it is not valid XHTML. Works in Mozilla and MSIE. Thanks Wolfgang!
* Added TS option "USERUID_substToken"
* Added TS option "USERUID_substToken"
2004-11-26 Michael Stucki <michael@typo3.org>
......
......@@ -41,7 +41,7 @@ TCEmain:
- Transformation API: Implement the possibility of custom to/from transformations for the "user" type (or any field?)
- Selector box type:
- MM support for strings
- Support for MM-records which does NOT get deleted, but is kept... and then support for having data in those!!
- Support for MM-records which does NOT get deleted, but is kept... and then support for having data in those!! NOTE 3/12 04: This will cause severe problems in the import/export interface and probably many other places where the MM relations are stored only as the uid of another table and nothing more. That makes it impossible to track the record in the middle....
- Support that the content of a single field can be stored in an external file instead.
- Support that a list of fields can be stored in an external XML file instead.
- Record Reference tracking in a table in TCEmain; Used to:
......
......@@ -331,6 +331,24 @@ class t3lib_basicFileFunctions {
}
}
/**
* Find first web folder (relative to PATH_site.'fileadmin') in filemounts array
*
* @return string The key to the first mount inside PATH_site."fileadmin" found, otherwise nothing is returned.
*/
function findFirstWebFolder() {
global $TYPO3_CONF_VARS;
if (is_array($this->mounts)) {
reset ($this->mounts);
while(list($k,$val)=each($this->mounts)) {
if (t3lib_div::isFirstPartOfStr($val['path'], PATH_site.$TYPO3_CONF_VARS['BE']['fileadminDir'])) {
return $k;
}
}
}
}
/**
* Removes filemount part of a path, thus blinding the position.
* Takes a path, $thePath, and removes the part of the path which equals the filemount.
......@@ -371,6 +389,11 @@ class t3lib_basicFileFunctions {
/*********************
*
* Cleaning functions
......
......@@ -2804,16 +2804,17 @@ class t3lib_BEfunc {
/**
* Returns first possible RTE object if available.
* Usage: $RTEobj = &t3lib_BEfunc::RTEgetObj();
*
* @return mixed If available, returns RTE object, otherwise an array of messages from possible RTEs
*/
function &RTEgetObj() {
// If no RTE object has been set previously, try to create it:
if (!isset($GLOBALS['TYPO3_CONF_VARS']['T3_VAR']['RTEobj'])) {
if (!isset($GLOBALS['T3_VAR']['RTEobj'])) {
// Set the object string to blank by default:
$GLOBALS['TYPO3_CONF_VARS']['T3_VAR']['RTEobj'] = array();
$GLOBALS['T3_VAR']['RTEobj'] = array();
// Traverse registered RTEs:
if (is_array($GLOBALS['TYPO3_CONF_VARS']['BE']['RTE_reg'])) {
......@@ -2821,22 +2822,86 @@ class t3lib_BEfunc {
$rteObj = &t3lib_div::getUserObj($rteObjCfg['objRef']);
if (is_object($rteObj)) {
if ($rteObj->isAvailable()) {
$GLOBALS['TYPO3_CONF_VARS']['T3_VAR']['RTEobj'] = &$rteObj;
$GLOBALS['T3_VAR']['RTEobj'] = &$rteObj;
break;
} else {
$GLOBALS['TYPO3_CONF_VARS']['T3_VAR']['RTEobj'] = array_merge($GLOBALS['TYPO3_CONF_VARS']['T3_VAR']['RTEobj'], $rteObj->errorLog);
$GLOBALS['T3_VAR']['RTEobj'] = array_merge($GLOBALS['T3_VAR']['RTEobj'], $rteObj->errorLog);
}
}
}
}
if (!count($GLOBALS['TYPO3_CONF_VARS']['T3_VAR']['RTEobj'])) {
$GLOBALS['TYPO3_CONF_VARS']['T3_VAR']['RTEobj'][] = 'No RTEs configured at all';
if (!count($GLOBALS['T3_VAR']['RTEobj'])) {
$GLOBALS['T3_VAR']['RTEobj'][] = 'No RTEs configured at all';
}
}
// Return RTE object (if any!)
return $GLOBALS['TYPO3_CONF_VARS']['T3_VAR']['RTEobj'];
return $GLOBALS['T3_VAR']['RTEobj'];
}
/**
* Returns soft-reference parser for the softRef processing type
* Usage: $softRefObj = &t3lib_BEfunc::softRefParserObj('[parser key]');
*
* @param string softRef parser key
* @return mixed If available, returns Soft link parser object.
*/
function &softRefParserObj($spKey) {
// If no softRef parser object has been set previously, try to create it:
if (!isset($GLOBALS['T3_VAR']['softRefParser'][$spKey])) {
// Set the object string to blank by default:
$GLOBALS['T3_VAR']['softRefParser'][$spKey] = '';
// Now, try to create parser object:
$objRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser'][$spKey] ?
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser'][$spKey] :
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'][$spKey];
if ($objRef) {
$softRefParserObj = &t3lib_div::getUserObj($objRef,'');
if (is_object($softRefParserObj)) {
$GLOBALS['T3_VAR']['softRefParser'][$spKey] = &$softRefParserObj;
}
}
}
// Return RTE object (if any!)
return $GLOBALS['T3_VAR']['softRefParser'][$spKey];
}
/**
* Returns array of soft parser references
*
* @param string softRef parser list
* @param string Table name
* @param string Field name
* @return array Array where the parser key is the key and the value is the parameter string
*/
function explodeSoftRefParserList($parserList, $table, $field) {
// Looking for global parsers:
if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'])) {
$parserList = implode(',',array_keys($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'])).','.$parserList;
}
// Return immediately if list is blank:
if (!strlen($parserList)) return FALSE;
// Otherwise parse the list:
$keyList = t3lib_div::trimExplode(',', $parserList, 1);
$output = array();
foreach($keyList as $val) {
$reg = array();
if (ereg('^([[:alnum:]_-]+)\[(.*)\]$', $val, $reg)) {
$output[$reg[1]] = t3lib_div::trimExplode(';', $reg[2], 1);
} else {
$output[$val] = '';
}
}
return $output;
}
/**
......
......@@ -118,6 +118,23 @@ class t3lib_clipboard {
var $fileMode=0; // If set, clipboard is displaying files.
/*****************************************
*
* Initialize
*
****************************************/
/**
* Initialize the clipboard from the be_user session
*
......@@ -153,8 +170,8 @@ class t3lib_clipboard {
* @return void
*/
function lockToNormal() {
$this->lockToNormal=1;
$this->current='normal';
$this->lockToNormal = 1;
$this->current = 'normal';
}
/**
......@@ -257,14 +274,22 @@ class t3lib_clipboard {
return $CBarr;
}
/**
* Reports if the current pad has elements (does not check file/DB type OR if file/DBrecord exists or not. Only counting array)
/*****************************************
*
* @return boolean True if elements exist.
*/
function isElements() {
return is_array($this->clipData[$this->current]['el']) && count($this->clipData[$this->current]['el']);
}
* Clipboard HTML renderings
*
****************************************/
/**
* Prints the clipboard
......@@ -291,17 +316,27 @@ class t3lib_clipboard {
// Selector menu + clear button
$opt=array();
$opt[]='<option value="" selected="selected">'.$this->clLabel('menu','rm').'</option>';
if (!$this->fileMode && $elCount) $opt[]='<option value="'.htmlspecialchars("document.location='".$this->editUrl()."&returnUrl='+top.rawurlencode(document.location);").'">'.$this->clLabel('edit','rm').'</option>';
if ($elCount) $opt[]='<option value="'.htmlspecialchars("
// Import / Export link:
if ($elCount && t3lib_extMgm::isLoaded('impexp')) {
$opt[] = '<option value="'.htmlspecialchars("document.location='".$this->backPath.t3lib_extMgm::extRelPath('impexp').'app/index.php'.$this->exportClipElementParameters().'\';').'">'.$this->clLabel('export','rm').'</option>';
}
// Edit:
if (!$this->fileMode && $elCount) {
$opt[]='<option value="'.htmlspecialchars("document.location='".$this->editUrl()."&returnUrl='+top.rawurlencode(document.location);").'">'.$this->clLabel('edit','rm').'</option>';
}
// Delete:
if ($elCount) {
$opt[]='<option value="'.htmlspecialchars("
if(confirm(".$GLOBALS['LANG']->JScharCode(sprintf($LANG->sL('LLL:EXT:lang/locallang_core.php:mess.deleteClip'),$elCount)).")){
document.location='".$this->deleteUrl(0,$this->fileMode?1:0)."&redirect='+top.rawurlencode(document.location);
}
").'">'.$this->clLabel('delete','rm').'</option>';
}
$selector_menu = '<select name="_clipMenu" onchange="eval(this.options[this.selectedIndex].value);this.selectedIndex=0;">'.implode('',$opt).'</select>';
$out[]='
<tr class="typo3-clipboard-head">
<td>'.
<td nowrap="nowrap">'.
'<a href="'.htmlspecialchars($thumb_url).'#clip_head">'.
'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/thumb_'.($this->clipData['_setThumb']?'s':'n').'.gif','width="21" height="16"').' vspace="2" border="0" title="'.$this->clLabel('thumbmode_clip').'" alt="" />'.
'</a>'.
......@@ -310,7 +345,10 @@ class t3lib_clipboard {
'</a>'.
'</td>
<td width="95%">'.$selector_menu.'</td>
<td><a href="'.htmlspecialchars($rmall_url).'#clip_head">'.$LANG->sL('LLL:EXT:lang/locallang_core.php:buttons.clear',1).'</a></td>
<td>'.
'<a href="'.htmlspecialchars($rmall_url).'#clip_head">'.
'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/closedok_2.gif','width="21" height="16"').' vspace="2" border="0" title="'.$LANG->sL('LLL:EXT:lang/locallang_core.php:buttons.clear',1).'" alt="" />'.
'</a></td>
</tr>';
......@@ -384,7 +422,7 @@ class t3lib_clipboard {
<td class="'.$bgColClass.'">'.$icon.'</td>
<td class="'.$bgColClass.'" nowrap="nowrap" width="95%">&nbsp;'.$this->linkItemText(htmlspecialchars(t3lib_div::fixed_lgd_cs(basename($v),$GLOBALS['BE_USER']->uc['titleLen'])),$v).
($pad=='normal'?(' <strong>('.($this->clipData['normal']['mode']=='copy'?$this->clLabel('copy','cm'):$this->clLabel('cut','cm')).')</strong>'):'').'&nbsp;'.($thumb?'<br />'.$thumb:'').'</td>
<td class="'.$bgColClass.'" align="center">'.
<td class="'.$bgColClass.'" align="center" nowrap="nowrap">'.
'<a href="#" onclick="'.htmlspecialchars('top.launchView(\''.$v.'\', \'\'); return false;').'"><img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/zoom2.gif','width="12" height="12"').' hspace="2" border="0" title="'.$this->clLabel('info','cm').'" alt="" /></a>'.
'<a href="'.htmlspecialchars($this->removeUrl('_FILE',t3lib_div::shortmd5($v))).'#clip_head"><img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/close_12h.gif','width="11" height="12"').' border="0" title="'.$this->clLabel('removeItem').'" alt="" /></a>'.
'</td>
......@@ -402,7 +440,7 @@ class t3lib_clipboard {
<td class="'.$bgColClass.'">'.$this->linkItemText(t3lib_iconWorks::getIconImage($table,$rec,$this->backPath,'hspace="20" title="'.htmlspecialchars(t3lib_BEfunc::getRecordIconAltText($rec,$table)).'"'),$rec,$table).'</td>
<td class="'.$bgColClass.'" nowrap="nowrap" width="95%">&nbsp;'.$this->linkItemText(htmlspecialchars(t3lib_div::fixed_lgd_cs(t3lib_BEfunc::getRecordTitle($table,$rec),$GLOBALS['BE_USER']->uc['titleLen'])),$rec,$table).
($pad=='normal'?(' <strong>('.($this->clipData['normal']['mode']=='copy'?$this->clLabel('copy','cm'):$this->clLabel('cut','cm')).')</strong>'):'').'&nbsp;</td>
<td class="'.$bgColClass.'" align="center">'.
<td class="'.$bgColClass.'" align="center" nowrap="nowrap">'.
'<a href="#" onclick="'.htmlspecialchars('top.launchView(\''.$table.'\', \''.intval($uid).'\'); return false;').'"><img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/zoom2.gif','width="12" height="12"').' hspace="2" border="0" title="'.$this->clLabel('info','cm').'" alt="" /></a>'.
'<a href="'.htmlspecialchars($this->removeUrl($table,$uid)).'#clip_head"><img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/close_12h.gif','width="11" height="12"').' border="0" title="'.$this->clLabel('removeItem').'" alt="" /></a>'.
'</td>
......@@ -468,41 +506,6 @@ class t3lib_clipboard {
return $str;
}
/**
* Verifies if the item $table/$uid is on the current pad.
* If the pad is "normal", the mode value is returned if the element existed. Thus you'll know if the item was copy or cut moded...
*
* @param string Table name, (_FILE for files...)
* @param integer Element uid (path for files)
* @return string
*/
function isSelected($table,$uid) {
$k=$table.'|'.$uid;
return $this->clipData[$this->current]['el'][$k] ? ($this->current=='normal'?$this->currentMode():1) : '';
}
/**
* Returns item record $table,$uid if selected on current clipboard
* If table and uid is blank, the first element is returned.
* Makes sense only for DB records - not files!
*
* @param string Table name
* @param integer Element uid
* @return array Element record with extra field _RECORD_TITLE set to the title of the record...
*/
function getSelectedRecord($table='',$uid='') {
if (!$table && !$uid) {
$elArr = $this->elFromTable('');
reset($elArr);
list($table,$uid) = explode('|',key($elArr));
}
if ($this->isSelected($table,$uid)) {
$selRec = t3lib_BEfunc::getRecord($table,$uid);
$selRec['_RECORD_TITLE'] = t3lib_BEfunc::getRecordTitle($table,$selRec);
return $selRec;
}
}
/**
* Returns the select-url for database elements
*
......@@ -605,62 +608,6 @@ class t3lib_clipboard {
return t3lib_div::linkThisScript(array('CB'=>array('remove'=>$table.'|'.$uid)));
}
/**
* This traverses the elements on the current clipboard pane
* and unsets elements which does not exist anymore or are disabled.
*
* @return void
*/
function cleanCurrent() {
if (is_array($this->clipData[$this->current]['el'])) {
reset($this->clipData[$this->current]['el']);
while(list($k,$v)=each($this->clipData[$this->current]['el'])) {
list($table,$uid) = explode('|',$k);
if ($table!='_FILE') {
if (!$v || !is_array(t3lib_BEfunc::getRecord($table,$uid,'uid'))) {
unset($this->clipData[$this->current]['el'][$k]);
$this->changed=1;
}
} else {
if (!$v || !@file_exists($v)) {
unset($this->clipData[$this->current]['el'][$k]);
$this->changed=1;
}
}
}
}
}
/**
* Counts the number of elements from the table $matchTable. If $matchTable is blank, all tables (except '_FILE' of course) is counted.
*
* @param string Table to match/count for.
* @param string $pad can optionally be used to set another pad than the current.
* @return array Array with keys from the CB.
*/
function elFromTable($matchTable='',$pad='') {
$pad = $pad ? $pad : $this->current;
$list=array();
if (is_array($this->clipData[$pad]['el'])) {
reset($this->clipData[$pad]['el']);
while(list($k,$v)=each($this->clipData[$pad]['el'])) {
if ($v) {
list($table,$uid) = explode('|',$k);
if ($table!='_FILE') {
if ((!$matchTable || (string)$table==(string)$matchTable) && $GLOBALS['TCA'][$table]) {
$list[$k]= ($pad=='normal'?$v:$uid);
}
} else {
if ((string)$table==(string)$matchTable) {
$list[$k]=$v;
}
}
}
}
}
return $list;
}
/**
* Returns confirm JavaScript message
*
......@@ -707,6 +654,66 @@ class t3lib_clipboard {
return $conf;
}
/**
* Clipboard label - getting from "EXT:lang/locallang_core.php:"
*
* @param string Label Key
* @param string Alternative key to "labels"
* @return string
*/
function clLabel($key,$Akey='labels') {
return htmlspecialchars($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:'.$Akey.'.'.$key));
}
/**
* Creates GET parameters for linking to the export module.
*
* @return string GET parameters for current clipboard content to be exported.
*/
function exportClipElementParameters() {
// Init:
$pad = $this->current;
$params = array();
$params[] = 'tx_impexp[action]=export';
// Traverse items:
if (is_array($this->clipData[$pad]['el'])) {
reset($this->clipData[$pad]['el']);
while(list($k,$v)=each($this->clipData[$pad]['el'])) {
if ($v) {
list($table,$uid) = explode('|',$k);
if ($table=='_FILE') { // Rendering files/directories on the clipboard:
if (@file_exists($v) && t3lib_div::isAllowedAbsPath($v)) {
$params[] = 'tx_impexp['.(is_dir($v) ? 'dir' : 'file').'][]='.rawurlencode($v);
}
} else { // Rendering records:
$rec = t3lib_BEfunc::getRecord($table,$uid);
if (is_array($rec)) {
$params[] = 'tx_impexp[record][]='.rawurlencode($table.':'.$uid);
}
}
}
}
}
return '?'.implode('&', $params);
}
/*****************************************
*
* Helper functions
*
****************************************/
/**
* Removes element on clipboard
*
......@@ -740,14 +747,103 @@ class t3lib_clipboard {
}
/**
* Clipboard label - getting from "EXT:lang/locallang_core.php:"
* This traverses the elements on the current clipboard pane
* and unsets elements which does not exist anymore or are disabled.
*
* @param string Label Key
* @param string Alternative key to "labels"
* @return void
*/
function cleanCurrent() {
if (is_array($this->clipData[$this->current]['el'])) {
reset($this->clipData[$this->current]['el']);
while(list($k,$v)=each($this->clipData[$this->current]['el'])) {
list($table,$uid) = explode('|',$k);
if ($table!='_FILE') {
if (!$v || !is_array(t3lib_BEfunc::getRecord($table,$uid,'uid'))) {
unset($this->clipData[$this->current]['el'][$k]);
$this->changed=1;
}
} else {
if (!$v || !@file_exists($v)) {
unset($this->clipData[$this->current]['el'][$k]);
$this->changed=1;
}
}
}
}
}
/**
* Counts the number of elements from the table $matchTable. If $matchTable is blank, all tables (except '_FILE' of course) is counted.
*
* @param string Table to match/count for.
* @param string $pad can optionally be used to set another pad than the current.
* @return array Array with keys from the CB.
*/
function elFromTable($matchTable='',$pad='') {
$pad = $pad ? $pad : $this->current;
$list=array();
if (is_array($this->clipData[$pad]['el'])) {
reset($this->clipData[$pad]['el']);
while(list($k,$v)=each($this->clipData[$pad]['el'])) {
if ($v) {
list($table,$uid) = explode('|',$k);
if ($table!='_FILE') {
if ((!$matchTable || (string)$table==(string)$matchTable) && $GLOBALS['TCA'][$table]) {
$list[$k]= ($pad=='normal'?$v:$uid);
}
} else {
if ((string)$table==(string)$matchTable) {
$list[$k]=$v;
}
}
}
}
}
return $list;
}
/**
* Verifies if the item $table/$uid is on the current pad.
* If the pad is "normal", the mode value is returned if the element existed. Thus you'll know if the item was copy or cut moded...
*
* @param string Table name, (_FILE for files...)
* @param integer Element uid (path for files)
* @return string
*/
function clLabel($key,$Akey='labels') {
return htmlspecialchars($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:'.$Akey.'.'.$key));
function isSelected($table,$uid) {
$k=$table.'|'.$uid;
return $this->clipData[$this->current]['el'][$k] ? ($this->current=='normal'?$this->currentMode():1) : '';
}
/**
* Returns item record $table,$uid if selected on current clipboard
* If table and uid is blank, the first element is returned.
* Makes sense only for DB records - not files!
*
* @param string Table name
* @param integer Element uid
* @return array Element record with extra field _RECORD_TITLE set to the title of the record...
*/
function getSelectedRecord($table='',$uid='') {
if (!$table && !$uid) {
$elArr = $this->elFromTable('');
reset($elArr);
list($table,$uid) = explode('|',key($elArr));
}
if ($this->isSelected($table,$uid)) {
$selRec = t3lib_BEfunc::getRecord($table,$uid);
$selRec['_RECORD_TITLE'] = t3lib_BEfunc::getRecordTitle($table,$selRec);
return $selRec;
}
}
/**
* Reports if the current pad has elements (does not check file/DB type OR if file/DBrecord exists or not. Only counting array)
*
* @return boolean True if elements exist.
*/
function isElements() {
return is_array($this->clipData[$this->current]['el']) && count($this->clipData[$this->current]['el']);
}
......
......@@ -1707,11 +1707,11 @@ class t3lib_div {
* @param string Alternative document tag. Default is "phparray".
* @param integer If set, the number of spaces corresponding to this number is used for indenting, otherwise a single chr(9) (TAB) is used