Borland C++ 5.0 Scripts




List all opened .cpp or .h files

This script assigns shortcut which show list of all currently opened .h or .cpp files. When selecting an item from this list, it will bring the corresponding window to the top.


import IDE;
import editor;

declare kbd = IDE.KeyboardManager.GetKeyboard("Editor");

// Choose a key combination
kbd.Assign("<Alt-F11>","get_h();");
kbd.Assign("<Alt-F12>","get_cpp();");

ChooseFile(ext)
{
  declare buffersArray = new array [];
  declare i = 0;
  declare firstBuffer = editor.TopBuffer;
  if( firstBuffer == NULL || !initialized(firstBuffer) ){
    print "First Buffer invalid";
    return;
    }
  declare current = firstBuffer;
  do {
    if( current.TopView != NULL){
      declare currExt = new String(current.Extension);
      currExt.Upper();
      if( currExt.Text == ext.Text ){
        buffersArray[i] = current.FullName;
        i++;
        }
      }
    current = current.NextBuffer(false);
  } while( firstBuffer.FullName != current.FullName );

  if( i == 0 ){
    print "No modules";
    return;
  }

  declare popup = new PopupMenu(200, 100, buffersArray);
  declare res = popup.Track();
  if( res == "" ) return;

  current = firstBuffer;
  for( declare j=0 ; ; current = current.NextBuffer(false),j++ ){
    if( current.FullName == res ){
      current.TopView.Window.IsHidden = false;
      current.TopView.Window.Activate();
      break;
      }
    }
}

get_cpp()
{
  declare ext = new String(".CPP");
  ChooseFile(ext);
}

get_h()
{
  declare ext = new String(".H");
  ChooseFile(ext);
}



Download ShowHCpp.zip




Save editor files on build and make
This script performs saving of all editor files when build or make is started. It's purpose is to prevent loss of unsaved files if the IDE crashes during compilation.


print ("SaveOnCompile.spp");

import IDE;
import debugger;

on IDE:>BuildStarted()
{
  print ("Saving all...");
  IDE.FileSaveAll();
  pass();
}

on IDE:>MakeStarted()
{
  print ("Saving all...");
  IDE.FileSaveAll();
  pass();
}

on debugger:>DebugeeAboutToRun() 
{
  print ("Saving all...");
  IDE.FileSaveAll();
  pass();
}

Download SaveOnCompile.zip




Auto arrange editor windows
This script arranges editor windows by placing newly opened source or header file to previously opened header or source with the same name and the corresponding type (e.g. .h with .cpp, .rh with .rc and .hxx with .cxx).
It is modification done by Chavdar Dimitrov of Kent Reisdorph's example, which can be found at http://www.reisdorph.com/bcpp/scripts.htm#newedsiz

To use it, myedsize.cpp must be build to a 32-bit multithread DLL, and placed in the BC5\BIN folder.
myedsize.spp

print("myedsize.spp");

import editor;

// import the DLL function
import "myedsize.dll" {
  void PositionWindow(char*, int, int, bool);
}

// I like 600 pixels by 350 for my edit windows
declare width = 800;
declare height = 500;
declare ViewID;

on editor:>ViewCreated(newView)
{
  ViewID = newView.Identifier;
  pass(newView);
}

// if a view was activated and it was not
// an existing window then call the DLL
// function to move it
on editor:>ViewActivated(view)
{
  if (ViewID == view.Identifier) {
    pass(view);
    declare newViewTitle = editor.TopView.Window.Title;
    PositionWindow(newViewTitle, width, height, false);
    ViewID = NULL;
  }
  pass(view);
}

///////////////////////////////////////////////////////////////

myedsize.cpp

#define WIN32_LEAN_AND_MEAN
#define STRICT
#include <windows.h>
#include <cstring.h>
#include <dir.h>
#include <stdio.h>

int xPos;
int yPos;
HWND hWndNew;
HWND hWndExisting;
HWND hWndMDI;

enum FileGroup {
  Header,
  Source,
  Other
};

#define PAIRS_NUM 3

static const char* HeaderSourcePairsExt [][PAIRS_NUM] = {
  {".h", ".cpp"},
  {".hxx", ".cxx"},
  {".rh",".rc"},
};

FileGroup GetFileGroup(const char* pszExt)
{
  for (int i = 0; i < PAIRS_NUM; i++)
    if (!strcmpi(pszExt, HeaderSourcePairsExt[i][Header]))
      return Header;
    else
      if (!strcmpi(pszExt, HeaderSourcePairsExt[i][Source]))
        return Source;

  return Other;
}

const char* GetCorrespondingExt(FileGroup fileGroup, const char* pszExt)
{
  for (int i = 0; i<PAIRS_NUM; i++)
    if (!strcmpi(pszExt,HeaderSourcePairsExt[i][fileGroup]))
      return HeaderSourcePairsExt[i][(fileGroup+1)%2];

  return 0;
}

int GetOffset()
{
  return GetSystemMetrics(SM_CYCAPTION) +(GetSystemMetrics(SM_CYFRAME) * 2);
}


string GetPath(const char* pszWndCaption)
{
  string sCaption(pszWndCaption);
  int nPos = sCaption.find_last_of(string(":"));
  if (nPos != NPOS && nPos != 1)//C:\.....
    sCaption.remove(nPos);

  nPos = sCaption.find_first_of(string(" "));
  if (nPos != NPOS)
    sCaption.remove(nPos);

  return sCaption;
}

string GetNameExt(const char* pszWndTitle, char* pszName, char* pszExt)
{
  string sPath = GetPath(pszWndTitle);
  fnsplit(sPath.c_str(),0,0,pszName,pszExt);
  return string(pszName) + pszExt;
}

string GetNameExt(const char* pszWndTitle)
{
  char pszName[MAXFILE];
  char pszExt[MAXEXT];
  return GetNameExt(pszWndTitle,pszName,pszExt);
}

BOOL CALLBACK FindExistingWindow(HWND hwnd, LPARAM pszNameExt)
{
  const int size = 20;
  char className[size];

  GetClassName(hwnd, className, size);

  if (hwnd == hWndNew || strcmp(className, "BCW5Editor"))
    return TRUE;

  if (IsIconic(hwnd))
    return TRUE;

  const int nCurrWndTitleLen = MAXPATH + 3;//title:2
  char pszCurrWndTitle[nCurrWndTitleLen];
  GetWindowText(hwnd,pszCurrWndTitle,nCurrWndTitleLen);
  string sCurrNameExt = GetNameExt(pszCurrWndTitle);

  if (sCurrNameExt == (char*)pszNameExt) {
    hWndExisting = hwnd;
    return FALSE;
  }
  
  return TRUE;
}

// callback function called to enumerate
// the child windows
BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lParam)
{
  const int size = 20;
  char className[size];

  GetClassName(hwnd, className, size);

  if (hwnd == hWndNew || strcmp(className, "BCW5Editor")) return TRUE;

  if (IsIconic(hwnd))
    return TRUE;

  RECT rect;
  POINT point;

  int offset = GetOffset();

  GetWindowRect(hwnd, &rect);
  point.x = rect.left;
  point.y = rect.top;

  ScreenToClient((HWND)lParam, &point);

  if (point.y >= yPos)
    yPos = point.y + offset;

  return TRUE;
}

extern "C"
void PASCAL _export
PositionWindow(char* title, int width, int height, bool bSourceInLeft = true)
{
  // reset x and y pos before each run
  xPos = yPos = 0;
  hWndExisting = 0;
  string::set_case_sensitive(0);

  // find the IDE window
  HWND hWndIDE = FindWindow("CPPFRAME", NULL);

  // find the MDI client which is the client
  // window of the IDE
  hWndMDI = FindWindowEx(hWndIDE, NULL, "MDIClient", NULL);

  // get a handle to the newly-created editor
  hWndNew = FindWindowEx(hWndMDI, NULL, "BCW5Editor", title);


  char pszName[MAXFILE];
  char pszExt[MAXEXT];
  GetNameExt(title,pszName,pszExt);

  FileGroup fileGroup = GetFileGroup(pszExt);

  if (fileGroup != Other) {
    RECT rect;
    if(fileGroup == (bSourceInLeft ? Source : Header)) {
      GetClientRect(hWndMDI, &rect);
      xPos = rect.right - width;
    }
    strcpy(pszExt,GetCorrespondingExt(fileGroup,pszExt));
    char pszNameExt[MAXFILE + MAXEXT + 1];
    sprintf(pszNameExt,"%s%s",pszName,pszExt);
    EnumChildWindows(hWndMDI, FindExistingWindow, (LPARAM)pszNameExt);
    if (hWndExisting) {
      POINT point;
      GetWindowRect(hWndExisting, &rect);
      point.x = rect.left;
      point.y = rect.top;
      ScreenToClient(hWndMDI, &point);
      yPos = point.y;
    }
    else
      EnumChildWindows(hWndMDI, EnumProc, (LPARAM)hWndMDI);
  }
  else
    EnumChildWindows(hWndMDI, EnumProc, (LPARAM)hWndMDI);

  if (hWndNew)
    SetWindowPos(hWndNew, 0, xPos, yPos, width, height, SWP_NOZORDER);
}


Download MyEdSize.zip




Toggle between source and header files
When editing a source file, this script will bring up the corresponding header file, and vice versa. Supports these extensions: cpp c h hpp rc rh. Can be extended by editing a single array ('map'). First searches in the same directory, then does a little heuristics by replacing parts of the path like '\source\' and '\include\', in order to find files located in different paths (like Owl files), as suggested by Jogy. If you too store your headers separately from your source, you can customize another array ('dirMap') to suit your needs. Currently assigned to <Ctrl-h> (this can be modified)..



import IDE;
import editor;

declare keyCut = "<Ctrl-h>";   // set a keycut you like
declare kbd = IDE.KeyboardManager.GetKeyboard("Editor");

kbd.Assign(keyCut, "CppH_Tog_Launch();");
print("Show Header assigned to " + keyCut);


CppH_Tog_Launch()
{
  // just create an object to do the job
  new CppH_Tog_Worker();
}


class CppH_Tog_Worker
{
  declare topBuf = editor.TopBuffer;

  // validate current buffer
  if (!topBuf) {
    IDE.StatusBar = "CppH_Tog: Invalid top buffer";
    return;
  }

  // You can customize this mapping to better suit your needs.
  // It's simply an array of entries, which are themselves
  // an array of 2 elements:
  // 1. the source extension (of the currently edited file)
  // 2. a list (another array) of corresponding extensions, which
  //    are checked in order of appearance
  //
  // Note that I've mapped "cpp" first to "h" and then to "hpp".
  // That's because I only use .h headers for .cpp files.
  // If you're using .hpp headers they will be opened nicely,
  // unless you also have a .h with the same name in the directory
  // (for interfacing with C programs).
  // In that case, just put "hpp" before "h".
  //
  declare map = {
                  { "cpp", {"h",   "hpp"} },
                  { "h",   {"cpp", "c"  } },
                  { "c",   {"h"         } },
                  { "hpp", {"cpp"       } },
                  { "rc",  {"rh"        } },
                  { "rh",  {"rc"        } }
                };

  // The next array provides mappings for the directory part
  // of the filename.
  // It's very useful for toggling between Owl source and
  // headers, which are in different paths, e.g.
  //
  //  Owl5
  //    C:\BC5\SOURCE\OWL\window.cpp
  //    C:\BC5\INCLUDE\OWL\window.h
  //
  //  OwlNext
  //    C:\Owl\source\owlcore\window.cpp
  //    C:\Owl\include\owl\window.h
  //
  // This array contains string pairs. After scanning the directory
  // for an open/existing file, we'll start replacing parts of it
  // using the 'dirMap' table. The order of the two strings in each pair
  // is not significant, since we'll check for both of them and
  // replace whichever we find with the other.
  // Each modification will be applied to the original path.
  // Note that these 'tokens' are delimited by '\' characters
  // to avoid partial replacement of directory names.
  //
  // The predefined pairs are mainly targeted to:
  // 1. searching in the same directory;
  //    a single NULL causes the path to remain unchanged
  // 2. Owl5 files.
  // 3. OwlNext files.
  // 4. Other cases.
  // You can add more pairs, and rearrange their order.
  //
  declare dirMap = {
                     NULL,
                      {"\\include\\",       "\\source\\"},
                      {"\\include\\owl\\", "\\source\\owlcore\\"},
                      {"\\inc\\",           "\\src\\"}
                   };


  // get the parts of the buffer's filename
  declare drive = topBuf.Drive;
  declare path  = topBuf.Directory;
  declare fname = topBuf.FileName;
  declare ext   = topBuf.Extension;

  // get a list of mapped extensions
  declare mapExt = GetMappedExtensions(ext);

  // check for unsupported extensions
  if (!mapExt) {
    IDE.StatusBar = "CppH_Tog: Unsupported extension (" + ext + ")";
    return;
  }

  //======================================
  // STEP 1. Check for an existing buffer
  //======================================
  declare exBuf = GetExistingBuffer();
  if (exBuf) {
    HandleExistingBuffer(exBuf);
    return; // if the above failed, we shouldn't continue
  }

  //=========================================
  // STEP 2. Check if a matching file exists
  //=========================================
  // iterate through the mapped extensions to check
  // if a matching file exists
  declare exFile = GetExistingFile();
  if (exFile) {
    HandleExistingFile(exFile);
    return; // if the above failed, we shouldn't continue
  }

  //======================================================
  // STEP 3. Create a new buffer with the first extension
  //         in the same directory as a last resort.
  //======================================================
  // the file doesn't really exist, but we open it anyway
  HandleExistingFile(drive + path + fname + "." + mapExt[0]);


  // THE END
  // ----------------------------------
  // MEMBER FUNCTIONS FOLLOW:
  // ----------------------------------


  // ----------------------------------
  // Check whether two strings match, ignoring case.
  // ----------------------------------
  StrIMatch(s1, s2)
  {
    s1 = (new String(s1)).Upper().Text;
    s2 = (new String(s2)).Upper().Text;
    return s1 == s2;
  }


  // ----------------------------------
  // Check whether the specified extension
  // exists in the mapping array.
  // ----------------------------------
  GetMappedExtensions(ext)
  {
    declare ret = NULL;
    declare index; // cannot declare this inside 'iterate's parentheses

    iterate (declare entry; map; index)
    if (StrIMatch("." + entry[0], ext))
      return map[index][1];

    // we didn't find it
    return NULL;
  }


  // ----------------------------------
  // Return the first existing buffer in the IDE that matches
  // the mapped extensions, or NULL if non is found.
  // ----------------------------------
  GetExistingBuffer()
  {
    declare sentry = 0;

    // apply directory mappings
    //
    iterate (declare tokPair; dirMap)
    {
      declare xPath = TransformPath(path, tokPair);
      if (xPath == NULL) continue;    // in case the path didn't change

      // walk the buffer list.
      //
      // explaining the 'for' loop params:
      // init: we start checking the next buffer from the top
      // cond: a valid buf and not the top buffer (because buffer list is circular)
      //   CAUTION: don't use "testBuf && (testBuf != topBuf)", it always evals to FALSE  (don't know why...)
      // step: the next, non-private buffer
      //
      for (declare testBuf = topBuf.NextBuffer(false);
           (testBuf != NULL) && (testBuf != topBuf);
           testBuf = testBuf.NextBuffer(false))
      {
        // iterate through the mapped extensions to check
        // if the buffer matches one of them
        iterate (declare testExt; mapExt)
        {
          if (StrIMatch(drive + xPath + fname + "." + testExt,
                        testBuf.FullName))
            return testBuf;
        }

        // this sentry will terminate the loop
        // in case something goes haywire  :)
        // (perhaps it's not needed...)
        if (++sentry >= 1000) break;
      }
    }

    // we couldn't find a valid buffer
    return NULL;
  }


  // ----------------------------------
  // If a matching buffer is found, try to open one of its views
  // ----------------------------------
  HandleExistingBuffer(exBuf)
  {
    // does it have any views?
    if (exBuf.TopView) {
      // (is EditView::Window always non-NULL? docs don't mention returning NULL)
      exBuf.TopView.Window.IsHidden = false;
      exBuf.TopView.Window.Activate();
    }
    else {
      // there are no views attached;
      // create a new window; a default view will be created too
      declare newWnd = editor.EditWindowCreate(exBuf);
      if (newWnd == NULL) {
        IDE.StatusBar = "CppH_Tog: Could create new edit window";
        return;
      }
    }

    IDE.StatusBar = "CppH_Tog: OK";
  }


  // ----------------------------------
  // Return the first existing file that matches
  // the mapped extensions, or NULL if non is found.
  // ----------------------------------
  GetExistingFile()
  {
    // apply directory mappings
    //
    iterate (declare tokPair; dirMap)
    {
      declare xPath = TransformPath(path, tokPair);
      if (xPath == NULL) continue;    // in case the path didn't change

      // iterate through the mapped extensions to check
      // if the file exists
      iterate (declare testExt; mapExt)
      {
        if (FileExists(drive + xPath + fname + "." + testExt))
          return drive + xPath + fname + "." + testExt;
      }
    }

    // we couldn't find an existing file
    return NULL;
  }


  // ----------------------------------
  // If a matching file is found, try to create a buffer
  // and attach a new view to it.
  // (NOTE: Assuming a buffer was not found,
  // this function will create a new one)
  // ----------------------------------
  HandleExistingFile(fname)
  {
    // create an EditBuffer
    declare newBuf = editor.EditBufferCreate(fname);
    if (newBuf == NULL) {
      IDE.StatusBar = "CppH_Tog: Could create new edit buffer";
      return;
    }

    // create an EditWindow - a default view will be created too
    declare newWnd = editor.EditWindowCreate(newBuf);
    if (newWnd == NULL) {
      IDE.StatusBar = "CppH_Tog: Could create new edit window";
      return;
    }

    IDE.StatusBar = "CppH_Tog: OK";
  }


  // ----------------------------------
  // Accepts a string path and a 'dirMap' entry,
  // and returns a modified string path.
  // By convention, if 'tokPair' is NULL, 'path' is returned
  // (to allow searching in the same directory).
  // If no replacement was possible, NULL is returned.
  // ----------------------------------
  TransformPath(path, pair)
  {
    if (pair == NULL)
      return path;

    declare n;
    declare sPath = (new String(path   )).Upper();
    declare sTok1 = (new String(pair[0])).Upper();
    declare sTok2 = (new String(pair[1])).Upper();

    n = sPath.Index(sTok1.Text);
    if (n) return StrReplace(path, --n, sTok1.Length, pair[1]);

    n = sPath.Index(sTok2.Text);
    if (n) return StrReplace(path, --n, sTok2.Length, pair[0]);

    return NULL;    // could not replace anything
  }


  // Replaces 'len' characters of string 'src',
  // starting at 'pos', with string 'part'.
  //
  StrReplace(src, pos, len, part)
  {
    // note that .SubString(n,0) acts like .SubString(n)
    // (i.e. it doesn't return "")
    //
    declare s = new String(src);
    return (pos ? s.SubString(0, pos).Text : "")
            + part + s.SubString(pos + len).Text;
  }

};

Download CppH_Tog.zip






Back to home Back to main