Cleaning messy IBM i Integrated File System (IFS) file names


Dec 05

This morning I had an email from a blog subscriber ( Hi Rick! ) asking for a code tips on how to cleanup IFS file names to remove erroneous characters and/or malformed directory name slashes. Rather than reply with a plethora of programming options — here is an old, but functional, RPG code snippet that should help. 🙂

A looong time ago (in an office far far away) I faced a similar problem so decided to write a little RPGLE service program to give me some re-useable procedures to cleanup IFS file addresses.

In my case the users were asked to enter a file name in a green screen. What could go wrong? 😉

We all know that asking our users for a valid IFS File name is prone to spelling errors, syntax errors, finger slips and plain old end-user madness.

For example: Lets imagine an old IFS file that should be entered as /home/nick/myfile.cssv which is a lovely clean little file name.

In the real world, this could easily be entered as virtually any combination of keyboard whacks — /home\Nick//%¢&my file .CSV

While this file name might look reasonable to an end-user we (and when I say *we* I am referring to us propeller headed programming chaps and chappettes) know that the combination for front slashes, rear slashes and spaces in the file name might give us endless errors

So, I knocked up the #cleanifsfolder routine which basically switches everything to lower cases, removes duff characters, removes double spaces and replace spaces for underscores – obviously you can hack these rules to  your heart’s delight.

Anyway, I’m waffling as usual, so lets just copy/paste the code:

// |
// | #CleanIFSfolder - Clean up the string to remove Duff Stuff!                                                                       |
// |
// | Remove duff characters from parm and then use a cheeky little do loop to
// | squish it up so if this programs is passed a value of 'this is A file%¢&NaMe PlOp'
// |
// | The results will be calculated like this: 
// |     starting 1. '/this is A file%¢&/NaMe PlOp'
// |   strip duff 2. '/this is A file /NaMe PlOp'
// |        lower 3. '/this is a file /name plop' 
// | SquishSingle 4. '/this is a file/name plop'
// |

dcl-proc #CleanIFSfolder export;
dcl-pi #CleanIFSfolder char(1024);
  ParmIfsFolder char(1024) const;

dcl-s NeedsSquishing ind inz(*off);
dcl-c @Dirty const('\,¢!~`?%&*<>()+"|:;'); // naughty characters edit this to your needs
dcl-c @Clean const('/ ');
dcl-s cleanIfsFolder char(1024);

// Load up work field with the input value
clear cleanIfsFolder;
cleanIfsFolder = %subst(ParmIfsFolder:1:%Len(ParmIfsFolder));

If cleanIfsFolder <> *blanks;

  // Clean out any duff characters and switch to *blanks
  cleanIfsFolder = %Xlate(@Dirty:@Clean:cleanIfsFolder );
  cleanIfsFolder = %Xlate(@quoteMark:@blank:cleanIfsFolder);

  // Make sure we only have forward slashes
  cleanIfsFolder = #LeanForward ( cleanIfsFolder );

  // make it all lower case to be neat
  cleanIfsFolder = #lowercase ( cleanIfsFolder );

  // Squish out any multiple blanks
  cleanIfsFolder = #SquishSingle ( cleanIfsFolder );

  // Append '/' to the end
  cleanIfsFolder = %trim(cleanIfsFolder) + '/';

  // underscore it to make it look saucy
  cleanIfsFolder = #underscoreIt ( cleanIfsFolder );

  // change any accidental double forward-slashes to singles
  Dow %Scan('//': %trimR(cleanIfsFolder )) > *Zeros;
    NeedsSquishing = *on;
    cleanIfsFolder = %Replace('/':cleanIfsFolder:%Scan('//':%trimR(cleanIfsFolder )): 2);

  // Squish out any blanks again after double thing
  if NeedsSquishing;
    cleanIfsFolder = #SquishSingle ( cleanIfsFolder );

Return cleanIfsFolder ;


// +----------------------------------------------------------------+
// | #LeanForward - Fix the Forward lash to backslash debacle       |
// +----------------------------------------------------------------+
dcl-proc #LeanForward export;
dcl-pi #LeanForward char(1024);
  p_Data char(1024) const;
dcl-s $SlashData char(1024);

$SlashData = %subst(p_Data:1:%Len(p_Data));

// Replace any LESS THAN or GREATER THAN Chevrons with UNDERSCORE
$SlashData = %Xlate( '\':'/':$SlashData);

Return $SlashData;


// +-----------------------------------------------------------+
// | #SQUISHSINGLE - Squish together leaving ONE single space  |
// +-----------------------------------------------------------+
dcl-proc #SquishSingle export;
dcl-pi #SquishSingle char(1024);
  p_Data char(1024) const;
dcl-s $Squishey like(p_Data);

// Load up work field with the input value
$Squishey = %subst(p_Data:1:%Len(p_Data));

// replace all double blanks with a single one
Dow %Scan('  ':%trimR($Squishey)) > *Zeros;
  $Squishey = %Replace(' ':$Squishey:%Scan(' ':%trimR($Squishey)):2);

$BigVariable = %trim($Squishey);

Return $BigVariable;


// +-------------------------------------------------+
// | #UnderScoreIt - switch spaces to underscores    |
// | 1. 'this is a file name plop '                  |
// | 2. 'this_is_a_file_name_plop '                  |
// +-------------------------------------------------+
dcl-proc #UnderScoreIt export;
dcl-pi #UnderScoreIt like($bigvariable);
  p_Data like($bigvariable) const;
dcl-s clnVariable like(p_Data);

clnVariable = %subst(p_Data:1:%Len(p_Data));

clnVariable = %Xlate(@blank:@underScore:%trim(clnVariable));

// Replace Double UNDERSCORES with Singles
Dow %Scan('__': %trimR(clnVariable )) > *Zeros;
  clnVariable = %Replace(@underScore:clnVariable:%Scan('__':%trimR(clnVariable)): 2);

// check for any left behind
Dow %Scan('_ ':clnVariable ) > *Zeros;
  clnVariable = %Replace(' ':clnVariable:%Scan('_ ':clnVariable ): 2);

Return clnVariable;


// +---------------------------------------------------------+
// | #lowercase - purpose:convert text to lower case.        |
// | input:text data                                         |
// | Returns:lower case text data                            |
// +---------------------------------------------------------+
dcl-proc #LowerCase export;
dcl-pi #LowerCase like($bigvariable);
  ParmInput like($bigvariable) const;

dcl-s lowercaseWaffle like($bigvariable);

  SET :lowercaseWaffle = lower(:ParmInput);

Return lowercaseWaffle;


// +---------------------------------------------------------+
// | #uppercase - purpose:convert text to upper case.        |
// | input:text data                                         |
// | Returns:upper case text data                            |
// +---------------------------------------------------------+
dcl-proc #UpperCase export;
dcl-pi #UpperCase like($bigvariable);
  ParmInput like($bigvariable) const;

dcl-s upperCaseWaffle like($bigvariable);

  SET :upperCaseWaffle = UPPER(:ParmInput);

Return upperCaseWaffle;



Be gentle with me….

These code snippets are from over a decade ago, I’m sure there are some super simple SQL way of doing this nowadays.

But hopefully they will be useful…


About the Author

IBM i Software Developer, Digital Dad, AS400 Anarchist, RPG Modernizer, Alpha Nerd and Passionate Eater of Cheese and Biscuits. Nick Litten Dot Com is a mixture of blog posts that can be sometimes serious, frequently playful and probably down-right pointless all in the space of a day. Enjoy your stay, feel free to comment and in the words of the most interesting man in the world: Stay thirsty my friend.