function rtw_checkdir(dirToCheck)
%RTW_CHECKDIR check if Real-Time Workshop can build in to current directory
%
%  This routine will error out if the dos() command doesn't work or
%  if the current directory is an invalid location for a Real-Time Workshop
%  build.
%
%  1) On Windows PCs, 
%     This file checks to see that the MATLAB 'dos' command is functional.
%     MATLAB does not support banging out and running an executable, when in a 
%     UNC directory (e.g. directory starting with "\\"). 
%     This file also checks to see if you are in a UNC directory.
%  
%  2) To avoid corruption of MATLAB directories under the MATLAB path, this
%     function checks to see if you are working in a directory 
%     under MATLABROOT.
%
%  3) Validate that current directory is not a Real-Time Workshop project
%     (build) directory.
%
  
%   Copyright 1994-2019 The MathWorks, Inc.
%     
  
  if nargin < 1
      dirToCheck = pwd;
  end
  
  % To avoid corruption of MATLAB directories, check to see the current    
  % working directory is not under matlabroot
  locErrorIfInProtectedMatlabrootDir(dirToCheck);

  % Check to see if current directory is a project directory
  locErrorIfInProjDir(dirToCheck);
  locErrorIfInSlprjDir(dirToCheck);
  locErrorIfInCustomStructureDir(dirToCheck);
%endfunction rtw_checkdir

% Function: locErrorIfInMatlabroot ========================================
% Abstract:
%     To avoid corruption of MATLAB directories, check to see the current    
%     working directory is not in a protected directory under matlabroot
%
function locErrorIfInProtectedMatlabrootDir(dirToCheck)
  
  endOfPathExpr = '(?=\\|\/|$)';
  mlroot = [regexptranslate('escape', matlabroot) endOfPathExpr];
  derived = [regexptranslate('escape', fullfile(matlabroot, 'derived')) endOfPathExpr];   
  
  % Use case insensitive comparison on PC
  if ispc
      cmpfcn = @(s, e) ~isempty(regexp(s, e, 'match', 'once', 'ignorecase'));
  else
      cmpfcn = @(s, e) ~isempty(regexp(s, e, 'match', 'once'));
  end
  
  % Throw an error if pwd is under a protected matlabroot sub directory
  if cmpfcn(dirToCheck, mlroot)
      % Permit building in matlabroot/derived
      if cmpfcn(dirToCheck, derived)       
          return;
      end
      
      DAStudio.error('RTW:buildProcess:buildDirInMatlabDir', dirToCheck);
  end

end % locErrorIfInMatlabroot

% Function: locErrorIfInProjDir ===========================================
% Abstract:
%   Issue an error if cwd is a Real-Time Workshop project directory, i.e.,
%   rtw_proj.tmw exists.
%
function locErrorIfInProjDir(cur_dir,cur_depth)

  rtwProjFile  = fullfile(cur_dir,'rtw_proj.tmw');
  if (exist(rtwProjFile, 'file') == 2)
      DAStudio.error('RTW:buildProcess:buildDirInRTWProjDir',rtwProjFile,pwd);
  end
 
  % the first caller doesn't pass in a depth, but the recursive call needs it
  % to cap out the max depth allowed.  We could force the original caller
  % to always pass in a 0, but it just adds noise.
  if (nargin == 1)
    cur_depth = 0;
  end
  
  fslist = find(cur_dir == filesep);
  
  % The Current RTW proj dir only goes 1 level deep, however, we can look up
  % the stack 3 more levels, to allow for future expansion.
  if ((cur_depth < 3) && (length(fslist) > 1))
      locErrorIfInProjDir(cur_dir(1:fslist(end)-1),cur_depth+1);
  end
  
end % locErrorIfInProjDir

% Function: locErrorIfInSlprjDir ==========================================
% Abstract:
%   Detect whether we are in project build directory, which follows pattern
% such as slprj/build/<model>/sl/sim/src/core
function locErrorIfInSlprjDir(dirToCheck)

projDir = 'slprj';

slprjIdx = strfind(dirToCheck, projDir);
if ~isempty(slprjIdx)
    slProjFile = fullfile(dirToCheck(1:slprjIdx+length(projDir)-1), 'sl_proj.tmw');
    if (exist(slProjFile,'file') == 2)
        DAStudio.error('RTW:buildProcess:buildDirInBuildDir',pwd);
    end
end

end % locErrorIfInSlprjDir

% Function: locErrorIfInCustomStructureDir ================================
% Abstract:
%   Detect whether we are in project build directory
function locErrorIfInCustomStructureDir(dirToCheck)

markerFiles = Simulink.filegen.CodeGenFolderStructure.getMarkerFiles();
checkDir = true;

% Unlike slprj, the custom structure directory cannot be detected by
% matching the current path as we have nothing to match it to. Currently
% the best way to detect if we're in a build dir is to search for the
% possible marker files in the current directory and the 4 directories
% above. This is consistent with similar checks elsewhere in the build
% process.
directoryLevelsToCheck = 5;
levelsChecked = 0;
while(checkDir)

    filesToCheck = cellfun(@(f) fullfile(dirToCheck, f), markerFiles, 'UniformOutput', false);

    for i=1:length(filesToCheck)
       fileToCheck = filesToCheck{i};
       if fileExists(fileToCheck)
           DAStudio.error('RTW:buildProcess:buildDirInBuildDir', dirToCheck);
       end
    end
    
    levelsChecked = levelsChecked + 1;

    % go to parent folder
    parentDir = fileparts(dirToCheck);        
    checkDir = ~isequal(parentDir, dirToCheck) && (levelsChecked < directoryLevelsToCheck);
    dirToCheck = parentDir;
end

end % locErrorIfInCustomStructureDir


function exists = fileExists(fileName)

    % dir and ls should not be used for performance reasons, however, exists
    % has some odd behaviour around the root directory on unix: if the following
    % file in the root directory is being checked /somefile.txt exists will also
    % check the MATLAB path for ./somefile.txt. This is fixed by using a double
    % forward slash in the unix path name.
    if isunix
        fileName = ['/' fileName];
    end
    
    exists = (exist(fileName, 'file') == 2);

end % fileExists

end % rtw_checkdir

% LocalWords:  PC's syscmd Proj proj slrpj somefile ignorecase
