(* *+***************************************************************
** File    : PrjMacs.pas
** Created : 14.11.00
** Author  : M.Leute
**
** Macro for FoldMaster
**       need version 1.50 or newer.
**
**
** Einige Makros, die die Arbeit mit der Projektdatei unterstützen.
**
** Backup
**        Alle Dateien des Projekts werden in ein Backupverzeichnis
**        kopiert. Bei einem Wiederholten Backup, werden nur
**        veränderte Dateien kopiert.
** Archiv
**        Erlaubt die Archivierung aller Dateien im Projekt in einer
**        ZIP- Datei. Dazu wird ein Programm zip.exe benötigt. Das
**        Programm kann bei Bedarf angepasst werden.
** ProjectFileSize
**        ermittelt die Gösse aller im Projekt enthaltener Dateien.
**        Dies ist nützlich, um den Platzbedarf für das Backup zu
**        ermitteln.
**
** AddModule
**        legt im Projekt eine C Datei und eine entsprechende Header
**        Datei an. Die grobe Struktur der Dateien wird bereits
**        eingetragen.
**
** C_CPP_SyncProject
**        Wird für ein C/CPP Projekt aufgerufen und synchronisiert das
**        Projekt mit den Verzeichnissen. Dateien mit folgenden Typen
*         *.c, *.cpp, *.h, *.rc, *.rh werden in das Projekt aufgenommen
**        wenn sie noch nicht im Projekt enthalten waren.
**        Die Liste kann entsprechen angepasst werden.
**
** C_CPP_ProjectExpert
**        Scanned ein angegebenes Verzeichnis und alle Unterverzeichnisse
**        und fügt alle gefundenen Dateien mit dem korrekten Dateityp
**        in das Projekt ein. Für jedes Unterverzeichnis wird eine
**        eigene Falte angelegt.
**
** test_prj_completness
**        prueft ob alle mit "" includierten Dateien
**        im Projekt enthalten sind, was Voraussetzung
**        für die korrekte Funktion von Make ist.
**        Es wird eine Log- Datei angelegt, die zum Schluß geöffnet
**        wird.
**
** MoveProject
**        In einigen Fällen werden Dateien nicht korrekt
**        umgezogen, wenn das Projekt in ein anderes
**        Verzeichnis kopiert oder verschoben wird.
**        In diesen Fällen kann dieses Makro helfen.
**        Es muss das Stammverzeichnis angegeben werden und
**        das Zielverzeichnis.
**        Es werden alle Verzeichnisse im Projekt zur Auswahl gestellt,
**        daraus kann das umzubenennende Verzeichnis ausgewählt werden.
**
** FilesToLower
**        Wandelt alle Dateinamen im Projekt in einheitliche
**        Schreibweise um.
**
** ProjectSetFTime
**        Liest Datum und Zeit ein.
**        Setzt Datum und Zeit jeder Datei im Projekt auf die
**        eingegebenen Werte.
**
** ProjectSortFiles
**        Sortieren von Dateien im Projekt.
**        Durch Anwenden auf eine Falte, die in einem eigenen
**        Fenster geoeffnet wurde, kann die Aktion auf diese
**        Falte beschraenkt werden.
**        Entfernt alle Module aus dem Projekt und fügt diese
**        am Ende wieder sortiert ein.
**
********************************************************************
** Version     Date      Change
** 1.50        14.11.00  Creation
** 1.52        17.09.01  ProjectSetFTime ergaenzt
** 1.53        02.11.01  ProjectSortFiles ergaenzt
**                       Benötigt Version 1.53
** **************************************************************-**)

{ Makros die auf ein Projekt angewendet werden können }
program ProjectExpert;

const
   (*{{{  FILE_ATTRIBUTE_**)
   FILE_ATTRIBUTE_READONLY   = $0001;
   FILE_ATTRIBUTE_HIDDEN     = $0002;
   FILE_ATTRIBUTE_SYSTEM     = $0004;
   FILE_ATTRIBUTE_DIRECTORY  = $0010;
   FILE_ATTRIBUTE_ARCHIVE    = $0020;
   FILE_ATTRIBUTE_NORMAL     = $0080;
   FILE_ATTRIBUTE_TEMPORARY  = $0100;
   FILE_ATTRIBUTE_COMPRESSED = $0800;
   FILE_ATTRIBUTE_OFFLINE    = $1000;
   (*}}}*)

var
   level_indent   : integer;
   log_file       : text;


(*{{{  function FTimeStr(ftime : integer) : string;*)
{ folgende Funktion dient zur Ausgabe der Zeit einer Datei
  in einen String }
{ ff_ftime:
Bits 0 to 4   The result of seconds divided by 2 (for example 10 here means 20 seconds)
Bits 5 to 10Minutes
Bits 11 to 15Hours
}
function FTimeStr(ftime : integer) : string;
var sec, min, hour : integer;
begin
   sec  := (ftime AND $1F) *2;
   min  := (ftime SHR 5)  AND $3F;
   hour := (ftime SHR 11) AND $1F;
   ftimestr := '';
   if (hour < 10) then swrite(ftimestr, '0');
   swrite(ftimestr, hour, ':');
   if (min < 10) then swrite(ftimestr, '0');
   swrite(ftimestr, min, ':');
   if (sec < 10) then swrite(ftimestr, '0');
   swrite(ftimestr, sec);
end;
(*}}}*)
(*{{{  function FDateStr(fdate : integer) : string;*)
{ folgende Funktion dient der Ausgabe des Datums einer Datei
  in einen String }
{
ff_fdate:
Bits 0-4   Day
Bits 5-8   Month
Bits 9-15  Years since 1980 (for example 9 here means 1989)
}
function FDateStr(fdate : integer) : string;
var day, month, year : integer;
begin
   day   := (fdate AND $1F);
   month := (fdate SHR 5) AND $0F;
   year  := (fdate SHR 9) AND $7F;
   FDateStr := '';
   if (day < 10)   then swrite(FDateStr, '0');
   swrite(FDateStr, day,   '.');
   if (month < 10) then swrite(FDateStr, '0');
   swrite(FDateStr, month, '.', year + 1980);
end;
(*}}}*)
(*{{{  function is_older(fa, fb : string) boolean;*)
{ folgende Funktion prueft ob die Datei a aelter ist wie
  die Datei b. Von beiden Dateien wird der absolute
  Dateipfad angegeben.}
function is_older(fa, fb : string): boolean;
var fta, ftb, datea, dateb : integer;
begin
   is_older := false;
   if (FileExist(fa) AND FileExist(fb)) then begin
      datea := FileDate(fa); dateb := FileDate(fb);
      if (datea = dateb) then begin
         fta := FileTime(fa); ftb := FileTime(fb);
         if (fta < (ftb-10)) then is_older := true;
      end else if (datea < dateb) then is_older := true;
   end else begin
      is_older := true;
   end;
end;
(*}}}*)

(*{{{  Module mit Header einfuegen *)
{ Module mit Header einfuegen }
(*{{{  PROCEDURE MakeCppFile(FileName : String);*)
{ Unterprogramm
  Legt eine CPP- Datei an und traegt ein Template ein
}
PROCEDURE MakeCppFile(FileName : String);
VAR f :Text;
      datea : integer;
BEGIN
   Assign (f, FileName);
   Rewrite(f);
   datea := FileDate(FileName);
   Writeln(f, '/*  Projekt       ', getvarvalue('Projekt'));
   Writeln(f, '    ====================================');
   Writeln(f, '    ');
   Writeln(f, '    Copyright © 1998. Alle Rechte vorbehalten.');
   Writeln(f);
   Writeln(f, '    DATEI:        ', FileNameGetName(FileName), FileNameGetExt(FileName));
   Writeln(f, '    AUTOR:        ', getvarvalue('AUTOR'));
   Writeln(f, '    DATUM:        ', FDateStr(datea));
   Writeln(f);
   Writeln(f);
   Writeln(f, '    UEBERBLICK');
   Writeln(f, '    ------------------------------------');
   Writeln(f, '    Implementation folgender Funktionen ');
   Writeln(f);
   Writeln(f, '    Implementation folgender Klassen ');
   Writeln(f);
   Writeln(f, '*/');
   Writeln(f);
   Writeln(f);
   Writeln(f, '/*{{{  INCLUDES*/');
   Writeln(f, '#include <owl\owlpch.h>');
   Writeln(f, '#pragma hdrstop');
   Writeln(f);
   Writeln(f, '/*}}}*/');
   Writeln(f);
   Writeln(f);
   Writeln(f, '/*{{{  VARIABLEN*/');
   Writeln(f, '/*}}}*/');
   Writeln(f);
   Writeln(f);
   Writeln(f, '// ////////////////////////////////////////////////////////////');
   Writeln(f, '//FUNKTIONEN');
   Writeln(f);
   Writeln(f);
   Writeln(f, '// ////////////////////////////////////////////////////////////');
   Writeln(f, '// Ende der Datei');
   Writeln(f, '// ////////////////////////////////////////////////////////////');
   Close  (f);
END;
(*}}}*)
(*{{{  PROCEDURE MakeHFile(FileName : String);*)
{ Unterprogramm
  Legt eine H- Datei an und traegt ein Template ein
}
PROCEDURE MakeHFile(FileName : String);
VAR f :Text;
      datea : integer;
BEGIN
   Assign (f, FileName);
   Rewrite(f);
   datea := FileDate(FileName);
   Writeln(f, '#ifndef  __', strupr(FileNameGetName(FileName)),'_H');
   Writeln(f, '#define  __', strupr(FileNameGetName(FileName)),'_H');
   Writeln(f, '/*  Projekt       ', getvarvalue('Projekt'));
   Writeln(f, '    ====================================');
   Writeln(f, '    ');
   Writeln(f, '    Copyright © 1998. Alle Rechte vorbehalten.');
   Writeln(f);
   Writeln(f, '    DATEI:        ', FileNameGetName(FileName), FileNameGetExt(FileName));
   Writeln(f, '    AUTOR:        ', getvarvalue('AUTOR'));
   Writeln(f, '    DATUM:        ', FDateStr(datea));
   Writeln(f);
   Writeln(f);
   Writeln(f, '    UEBERBLICK');
   Writeln(f, '    ------------------------------------');
   Writeln(f, '    Deklaration der globalen Variablen, Funktionen und Klasse ');
   Writeln(f);
   Writeln(f, '*/');
   Writeln(f);
   Writeln(f);
   Writeln(f, '/*{{{  INCLUDES*/');
   Writeln(f, '/*}}}*/');
   Writeln(f);
   Writeln(f);
   Writeln(f, '/*{{{  EXTERN VARIABLES*/');
   Writeln(f, '/*}}}*/');
   Writeln(f);
   Writeln(f);
   Writeln(f, '/*{{{  EXTERN FUNCTIONS*/');
   Writeln(f, '/*}}}*/');
   Writeln(f);
   Writeln(f);
   Writeln(f, '/*{{{  EXTERN CLASSES*/');
   Writeln(f, '/*}}}*/');
   Writeln(f);
   Writeln(f);
   Writeln(f, '#endif // __', strupr(FileNameGetName(FileName)),'_H');
   Writeln(f, '// Ende der Datei');
   Close  (f);
END;
(*}}}*)
(*{{{  PROCEDURE AddModule;*)
{ Unterprogramm
  um in der Projektdatei eine neues Modul einzufuegen
  dabei wird auch gleich eine Headerdatei mit angelegt.
  In den einzelnen Dateien wird der notwendige
  Rumpf eingefuegt.
  Die .CPP- Datei wird an der aktuellen Cursorposition
  eingefuegt, die Headerdatei in einer mit INCLUDE
  bezeichneten Falte
}
PROCEDURE add_module;
Var ModuleName : String;
    CppName : String;
    HName : String;
    ret : Boolean;
    iret : Integer;
BEGIN
   IF IsProject THEN BEGIN
      { Name des Moduls abfragen }
      IF (FileNameInput('Modulname angeben', '*.cpp;*.h|*.cpp;*.h',ModuleName) = 1) THEN BEGIN
         CppName := '';
         HName   := '';
         swrite (CppName, FilenameGetDriveDir(ModuleName), FileNameGetName(ModuleName), '.cpp');
         swrite (HName, FilenameGetDriveDir(ModuleName), FileNameGetName(ModuleName), '.h');
         writeln('Lege Datei "', CppName, '" an');
         writeln('Lege Datei "', HName, '" an');
         { pruefen ob Dateien existieren }
         IF (FileExist(CppName) OR FileExist(HName)) THEN BEGIN
            iret := BoxWarning('Achtung', 'Eine der beiden Dateien existiert bereits');
         END ELSE IF (IsModuleInProject(CppName) OR IsModuleInProject(HName)) THEN BEGIN
            { pruefen ob Dateien bereits im Projekt enthalten sind }
            iret := BoxWarning('Achtung', 'Eine der beiden Dateien ist bereits im Projekt enthalten');
         END ELSE BEGIN
            { Dateien anlegen }
            MakeCppFile(CppName);
            MakeHFile  (HName);
            { Dateien in Projekt einfuegen }
            FileAdd    (CppName);
            TempPosSet (9);          { Diese Position merken }
            StartOfText;
            SearchFold ('INCLUDE', '');
            if (IsFoldTitle) then begin
               FoldExpand;
               EndOfFold;
            end;
            FileAdd    (HName);
            TempPosGoto(9);
         END;
      END;
   END ELSE BEGIN
      iret := BoxWarning('Achtung', 'Macro kann nur auf Projektliste angewendet werden.');
   END;
END;
(*}}}*)
(*}}}*)
(*{{{  Backup und Archvierung *)
{ Backup und Archvierung }
(*{{{  Verzeichnis anlegen*)
{ folgende Funktion wird benutzt um in einem Unterverzeichnis
  weitere Verzeichnisse anzulegen, wie sie im uebergebenen
  relativen Pfad angegeben sind. }
procedure make_dir(dest,fn : String);
var subdir, sub: string;
    i, p1,p2 : integer;
begin
   ChDir(dest);
   subdir := FileNameGetDriveDir(fn);
   { Slash am Ende loeschen }
   if (Length(subdir) > 1) then begin
      if (copy(subdir, Length(subdir),1) = '\')then
         delete(subdir,Length(subdir), 1);
   end;
   repeat
      p1     := pos('\',subdir);
      p2     := pos('/',subdir);
      if (p1 > 0) then begin
         sub := copy(subdir, 1, p1-1); delete(subdir,1,p1);
      end else if (p2 > 0) then begin
         sub := copy(subdir, 1, p1-1); delete(subdir,1,p1);
      end else begin
         sub := subdir; subdir := '';
      end;
      { pruefen ob Unterverzeichnis besteht sonst anlegen }
      if (sub <> '') then begin
         if (NOT DirExist(sub)) then begin
            Writeln(sub, ' anlegen ');
            MkDir(sub);
         end;
         ChDir(sub);
      end;
   until (subdir = '');
end;
(*}}}*)
(*{{{  procedure project_file_size*)
{ folgendes Macro berechnet die gesamte Groesse aller
  Dateien innerhalb des Projekts um z.B.: den benoetigten
  Speicherplatz auf einem BackupMedium zu ermitteln. }
procedure project_file_size;
var s           : string;
    size, fs, i : integer;
    f           : Text;
begin
   i := 0; size := 0; MacroConsoleClear;
   repeat
      { kompletten Dateinamen mit Pfad ermitteln }
      s := IterateProjectModules(false, i);
      if (s <> '') then  begin
         Assign(f,s); Reset(f); fs := FileSize(f); close(f);
         writeln(fs:8, ' ', s);
         size := size + fs;
      end;
      Inc(i);
   until s = '';
   writeln('Groesse aller Projektdateien : ');
   writeln('  ist  ',size, ' Byte');
   writeln('  oder ',(size/1024):5:2, ' KByte');
end;
(*}}}*)
(*{{{  procedure backup_project;*)
{ Dieses Macro speichert alle Dateien, die in der
  Projektdatei angegeben sind in ein Verzeichnis.
  Das Verzeichnis wird eingelesen.Es wird das Tool
  (CopyFile) aufgerufen. }
procedure backup_project;
var i, res : integer;
    abspath, rel, mod_name, destpath , parameter: string;
    prompt : string;
begin
   // globale Variable abfragen
   destpath := GetVarValue('BACKUP_PATH');
   res := 1;
   if (destpath <> '') then begin
      (*{{{  Abfrage ob Pfad akzeptiert wird *)
      { Abfrage ob Pfad akzeptiert wird }
      swrite(prompt, #11, 'backup Verzeichnis : ',#10, #1,
                     #3, destpath, #1, #10,
                     'Sollen Dateien in dieses Verzeichnis gesichert werden?');
      res := BoxQuestion('BACKUP_PATH', prompt);
      if (res = -1) then destpath := ''; { Nein wurde eingegeben }
      (*}}}*)
   end;
   // ist res = 0 dann wurde Dialog abgebrochen
   if (res <> 0) then begin
      (*{{{  Wenn globale Variable nicht gesetzt ist, Pfad einlesen *)
      { Wenn globale Variable nicht gesetzt ist, Pfad einlesen }
      if (destpath = '') then begin
         if (DirectoryInput('Zielpfad für Backup', destpath)) then begin
            SetGlobalVar('BACKUP_PATH', destpath);
         end else begin
            destpath := '';
         end;
      end;
      (*}}}*)

      (*{{{  Dateien kopieren *)
      // Dateien kopieren
      i := 0; StartOfText;
      if (destpath <> '') then begin
         // destpath sollte immer mit '\' enden
         if (copy(destpath,Length(destpath),1) <> '\') then begin
            destpath := concat(destpath,'\');
         end;

         (*{{{  Projekt durchgehen*)
         // Projekt durchgehen
         repeat
            rel     := IterateProjectModules(true,  i); // relativen Pfad zum Projekt
            abspath := IterateProjectModules(false, i); // absoluten Pfad holen
            if (abspath <> '') then begin
               if ((rel <> '') AND (pos('..',rel) = 0)) then  begin
                  // make_dir legt Verzeichnisbaum nur an wenn
                  // nicht bereits vorhanden
                  make_dir(destpath, rel);
                  parameter := '';

                  // nur Datei kopieren die neuer sind
                  if (is_older(concat(destpath,rel), abspath)) then begin
                     swrite(parameter, abspath, ' ', destpath, rel);
                     ToolRunParameter('CopyFile', parameter);
                     writeln('Datei ', rel, ' gespeichert');
                  end else begin
                     writeln('Datei ', rel, ' ist aktuell');
                  end;
               end else begin
                  // Verzeichnis kann nicht angelegt werden
                  // daher kann auch Datei nicht kopiert werden
                  writeln('Datei ', rel, ' nicht gespeichert');
               end;
            end;
            Inc(i);
         until abspath = '';
         (*}}}*)
      end;
      (*}}}*)
   end;
end;
(*}}}*)
(*{{{  procedure archive_project;*)
{ folgendes Macro dient dazu das komplette Projekt zu
  archivieren. Es wird das Tool (ArcFile) aufgerufen.
  Dieses Tool muss vorhanden sein.
  Es wird ein ZIP- File in einem Verzeichnis angelegt
  oder gepflegt, das vorher eingegeben werden kann.
}
procedure archive_project;
var i,res : integer;
    s, mod_name, destpath , parameter: string;
    prompt : string;
begin
   // globale Variable abfragen
   destpath := GetVarValue('ARC_FILE');
   res := 1;
   if (destpath <> '') then begin
      (*{{{  Abfrage ob Pfad akzeptiert wird *)
      // Abfrage ob Pfad akzeptiert wird
      swrite(prompt, #11, 'Verzeichnis : ',#10, #1,
                     #3, destpath, #1, #10,
                     'Soll Archiv in diesem Verzeichnis angelegt werden?');
      res := BoxQuestion('Archivierung', prompt);
      if (res = -1) then destpath := ''; // Nein wurde eingegeben
      (*}}}*)
   end;
   // ist res = 0 dann wurde Dialog abgebrochen
   if (res <> 0) then begin
      (*{{{  Wenn globale Variable nicht gesetzt ist, Pfad einlesen *)
      // Wenn globale Variable nicht gesetzt ist, Pfad einlesen
      if (destpath = '') then begin
         if (DirectoryInput('Verzeichnis zur Archivierung', destpath)) then begin
            SetGlobalVar('ARC_FILE', destpath);
         end else begin
            destpath := '';
         end;
      end;
      (*}}}*)
      i := 0; StartOfText;
      (*{{{  Dateien archivieren *)
      // Dateien archivieren
      if (destpath <> '') then begin
         repeat
            s := IterateProjectModules(true, i);
            if (s <> '') then  begin
               parameter := '';
               swrite(parameter, '"'+destpath+'\'+FileNameGetName(GetProjectName)+'.zip" "', s, '"');
               ToolRunParameter('ArcFile', parameter);
            end;
            Inc(i);
         until s = '';
      end;
      (*}}}*)
   end;
end;
(*}}}*)
(*}}}*)


(*{{{  benoetigte Tools anlegen*)
// benoetigte Tools anlegen
(*{{{  define_copy_tool*)
{ define_copy_tool
  Definiert ein Tool um eine Datei zu kopieren
}
procedure define_copy_tool;
begin
   ToolDefine       ('CopyFile', getenvvalue('COMSPEC'), '', '/c copy');
   ToolDefineType   ('CopyFile', '', '', '', 0);
   ToolDefineMode   ('CopyFile', '', 2);
   ToolDefineConnect('CopyFile', '', 0);
   ToolDefineOptions('CopyFile', 0, 0);
end;
(*}}}*)
(*{{{  define_zip_tool*)
{ define_zip_tool
  definiert ein Tool zur Archivierung in einer ZIP- Datei
}
procedure define_zip_tool;
var Zip_InstPath : string;
begin
   (* ------------------------------------------------- *)
   (* Definition of ArcFile *)
   Beep;
   Zip_InstPath := 'zip.exe';
   if (FileNameInput  ('Ausführbare Datei für ZIP', 'Ausführbare Dateien|*.exe;*.com', Zip_InstPath) = 1) then begin
      // an dieser Stelle sollten die Paramenter fuer das ZIP- Tool ueberprueft werden
      // -u : update only changed or new files
      // Die Aktion wird aus dem Verzeichnis des Projekts gestartet.
      // Alle Dateien erhalten so einen Pfadeintrag relativ zum Projekt.
      ToolDefine       ('ArcFile', Zip_InstPath,
                        '$DRIVEDIR($PRONAME)',
                        '-u ');
      ToolDefineType   ('ArcFile', '', '', '', 0);
      ToolDefineMode   ('ArcFile', '', 2);
      ToolDefineConnect('ArcFile', '', 0);
      ToolDefineOptions('ArcFile', 0, 0);
   end;
end;
(*}}}*)
(*}}}*)

// Project Expert scannt Verzeichnisse und Unterverzeichnisse
(*{{{  procedure HasFiles(basedir, pattern : string);*)
// HasFiles checks if any file is found with the given search pattern
function HasFiles(basedir, pattern : string):boolean;
var s : string;
begin
   HasFiles := false;
   s := FindFirst(basedir+'\'+pattern);
   while (s <> '') do begin
      // den kompletten Pfad bilden
      s := basedir + '\' + s;
      if (NOT DirExist(s)) then begin
         HasFiles := true; s := '';  // break loop
      end else begin
         s := FindNext;
      end;
   end;
end;
(*}}}*)
(*{{{  procedure AddFiles(basedir, pattern : string);*)
procedure AddFiles(basedir, pattern : string);
var s : string;
begin
   s := FindFirst(basedir+'\'+pattern);
   while (s <> '') do begin
      // den kompletten Pfad bilden
      s := basedir + '\' + s;
      if (NOT DirExist(s)) then begin
         FileAdd(s);
      end;
      s := FindNext;
   end;
end;
(*}}}*)
(*{{{  procedure ProcessDirectory(basedir : string);*)
procedure ProcessDirectory(basedir : string);
var s   : string;
begin
   //writeln('Scaning directory ', basedir);
   s := strfill(s, level_indent);
   s := s+ FilenameGetName(basedir);
   FoldInsert(s); FoldEnter;
   InsertLine(basedir);

   (*{{{  verschiedene Dateitypen einhaengen*)
   // verschiedene Dateitypen einhaengen
   if (HasFiles(basedir, '*.h')) then begin
      InsertLine('INCLUDE FILES');
      AddFiles  (basedir, '*.h');   NewLine;
   end;
   if (HasFiles(basedir, '*.c') OR HasFiles(basedir, '*.cpp')) then begin
      InsertLine('SOURCE FILES');
      AddFiles  (basedir, '*.c');   NewLine;
      AddFiles  (basedir, '*.cpp'); NewLine;
   end;
   if (HasFiles(basedir, '*.cmd') OR HasFiles(basedir,'*.bat')) then begin
      InsertLine('COMMAND FILES');
      AddFiles  (basedir, '*.cmd'); NewLine;
      AddFiles  (basedir, '*.bat'); NewLine;
   end;
   if (HasFiles(basedir, '*.')) then begin
      InsertLine('MAKE FILES');
      AddFiles  (basedir, '*.');    NewLine;
   end;
   (*}}}*)
   (*{{{  Weitere Unterverzeichnisse durchsuchen*)
   // Weitere Unterverzeichnisse durchsuchen
   s := FindFirst(basedir+'\*.*');
   while (s <> '') do begin
      // den kompletten Pfad bilden
      s := basedir + '\' + s;
      if (DirExist(s)) then begin
         // es handelt sich um ein Unterverzeichnis
         ProcessDirectory(s);
      end;
      s := FindNext;
   end;
   (*}}}*)
   FoldClose;
end;
(*}}}*)
(*{{{  procedure C_CPP_ProjectExpert;*)
procedure C_CPP_ProjectExpert;
var s : string;
    basedir : string;
begin
   level_indent := 0;
   if (DirectoryInput('Basisverzeichnis des Projekts', basedir) = 1) then begin
      ProjectShow;
      ProcessDirectory(basedir);
   end;
end;
(*}}}*)
(*{{{  procedure C_CPP_SyncProject;*)
// Projekt mit Verzeichnissen synchronisieren
// Als Basisverzeichnis wird das Projektverzeichnis verwendet
// es werden alle Dateien eingefuegt, die noch nicht im Projekt
// enthalten sind.
procedure C_CPP_SyncProject;
var s : string;
    basedir : string;
    // Verzeichnisse synchronisieren
    (*{{{  procedure sync_files(basedir, pattern : string);*)
    procedure sync_files(basedir, pattern : string);
    begin
       s := FindFirst(basedir+'\'+pattern);
       while (s <> '') do begin
          // den kompletten Pfad bilden
          s := basedir + '\' + s;
          if (NOT DirExist(s)) then begin
             // Nur Dateien ueberpruefen
             if (NOT IsModuleInProject (s)) then begin
                FileAdd(s);
             end else begin
                Writeln('File ', s, ' found');
             end;
          end;
          s := FindNext;
       end;
    end;
    (*}}}*)
    (*{{{  procedure sync_dir(basedir : string);*)
    procedure sync_dir(basedir : string);
    begin
       (*{{{  Dateien ueberpruefen*)
       sync_files(basedir, '*.c');
       sync_files(basedir, '*.cpp');
       sync_files(basedir, '*.h');
       sync_files(basedir, '*.rc');
       sync_files(basedir, '*.rh');
       (*}}}*)
       (*{{{  Weitere Unterverzeichnisse durchsuchen*)
       // Weitere Unterverzeichnisse durchsuchen
       s := FindFirst(basedir+'\*.*');
       while (s <> '') do begin
          // den kompletten Pfad bilden
          s := basedir + '\' + s;
          if (DirExist(s)) then begin
             // es handelt sich um ein Unterverzeichnis
             sync_dir(s);
          end;
          s := FindNext;
       end;
       (*}}}*)
    end;
    (*}}}*)
begin
   level_indent := 0;
   basedir := FileNameGetDriveDirX(GetProjectName);
   sync_dir(basedir);
end;
(*}}}*)
(*{{{  TestIncludes*)
{ TestIncludes

}
procedure TestIncludes(fn : string);
var s : string;
    i : integer;
begin
   FileOpen(fn);
   (*{{{  Test if file is available*)
   if (NOT IsModuleOpen(fn)) then begin
      Writeln('   File ', fn, ' not found!');
      exit;
   end;
   (*}}}*)
   i := 0;
   repeat
      s := IterateIncludes(false,i);
      if (s <> '') then begin
         if (IsModuleInProject(s)) then begin
            writeln(log_file, '             ', s);
         end else begin
            writeln(log_file, ' NOT FOUND : ', s);
         end;
      end;
      Inc(i);
   until s = '';
   FileClose;
end;
(*}}}*)
(*{{{  test_prj_completness*)
{ test_prj_completness
  prueft ob alle mit "" includierten Dateien
  im Projekt enthalten sind, was Voraussetzung
  fuer die korrekte Funktion von Make ist.
}

procedure test_prj_completness;
var s : string;
    lg: string;
    i : integer;
begin
   (*{{{  LOG- Datei anlegen*)
   lg := FileNameGetDriveDir(GetProjectName);
   FileNameSetName(lg, 'includes');
   FileNameSetExt (lg, '.log');
   Assign (log_file, lg); // Assign the filename
   Rewrite(log_file);    // Open the file
   writeln('Creating ', lg);
   (*}}}*)
   (*{{{  Projektdateien durchgehen*)
   i := 0;
   repeat
      // Iterate through project modules
      s := IterateProjectModules(false, i);
      if (s <> '') then begin
         writeln(log_file, s);
         TestIncludes(s);
      end;
      inc (i);
   until (s = '');
   (*}}}*)
   (*{{{  LOG- Datei schliessen*)
   Flush(log_file);
   Close(log_file);
   (*}}}*)
   FileOpen(lg);
end;
(*}}}*)

// Projekt verschieben
(*{{{  MoveDirectory*)
{ MoveDirectory
  moves references in project from source directory to a
  user selectable destination directory. The user is asked for
  the destination directory.
}
procedure MoveDirectory(source: string);
var s, tmp    : string;
    dest_path : string;
    i         : integer;
begin
   // Start with project path
   dest_path := FileNameGetDriveDir(GetProjectName);
   if (DirectoryInput('Specify Destination Path '+source, dest_path) <> 1) then exit;
   i := 0;
   repeat
      // just move files within the source directoy
      s := IterateProjectModules(false, i);
      if (s <> '') AND (posi(source, s) = 1) then begin
         tmp := s;
         FileNameSetDrive(tmp, dest_path);
         FileNameSetDir  (tmp, dest_path);
         FileRename      (s, tmp);
         writeln('rename ', s, ' to ', tmp);
      end;
      inc (i);
   until (s = '');

end;
(*}}}*)
(*{{{  procedure MoveProject;*)
{ MoveProject
  In einigen Fällen werden Dateien nicht korrekt
  umgezogen, wenn das Projekt in ein anderes
  Verzeichnis kopiert wird. In diesen Fällen kann
  folgendes Makro helfen.
  Es muss das Stammverzeichnis angegeben werden und
  das Zielverzeichnis.
  Es werden alle Verzeichnisse im Projekt zur Auswahl gestellt,
  daraus kann das umzubenennende Verzeichnis ausgewählt werden.
}
procedure MoveProject;
var s, tmp    : string;
    i, start  : integer;
begin
   (*{{{  Alle vorhandenen Verzeichnisse des Projekts auflisten*)
   // Alle vorhandenen Verzeichnisse des Projekts auflisten
   TempstoreClear(0);
   i := 0;
   writeln('Im Projekt enthaltene Verzeichnisse');
   repeat
      s := IterateProjectModules(false, i);
      if (s <> '') then begin
         // Verzeichnis isolieren
         s := FileNameGetDriveDir(s);  start := 0;
         // pruefen ob Verzeichnis bereits enthalten ist
         if (TempstoreGetLinestr(0, s, start, 0, 0) = '') then begin
            // Verzeichnis ist noch nicht enthalten
            writeln('   ', s);
            TempstoreAddLine(0, s);
         end;
      end;
      inc(i);
   until (s = '');
   (*}}}*)
   (*{{{  Alle Verzeichnisse der Reihe nach zur Auswahl stellen*)
   i := 0;
   repeat
      s := TempstoreGetLineAt(0,i);
      if (s <> '') then begin
         if (BoxQuestion('umziehen von', s) = 1) then begin
            MoveDirectory(s);
         end;
      end;
      inc(i);
   until (s = '');
   (*}}}*)
end;
(*}}}*)

// Filenamen Gross- Kleinschreibung aendern
// nach Kleinschreibung
(*{{{  FilesToLower*)
{ FilesToLower
}
procedure FilesToLower;
var s : string;
    i : integer;
begin
   i := 0;
   repeat
      // kompletten Dateinamen mit Pfad ermitteln
      s := IterateProjectModules(false, i);
      if (s <> '') then  begin
         StrLower(s);
         //StrUpper(s);
         FileRename(s,s);
      end;
      Inc(i);
   until s = '';
end;
(*}}}*)

// Dateidatum und Zeit anpassen
(*{{{  procedure ProjectSetFTime*)
{ ProjectSetFTime
  Liest Datum und Zeit ein.
  Setzt Datum und Zeit jeder Datei im Projekt auf die
  ein gegebenen Werte.
}
procedure ProjectSetFTime;
var  s          : string;
     i          : integer;
     ft, new_ft : integer;
     f          : File;
     a,b,c      : integer;
     time, date : integer;
begin
   i := 0; MacroConsoleClear;

   (*{{{  neue Zeit einlesen*)
   // neue Zeit einlesen
   if (InputBox('Bitte Zeit eingeben', s) = 1) then begin
      a := atoi(s); i := pos(':',s); delete(s, 1, i); // Stunden
      b := atoi(s); i := pos(':',s); delete(s, 1, i); // Minuten
      c := atoi(s); c := c DIV 2; // Sec immer in 2er Schritten
      if (a > 23) then a := 23 else if (a < 0) then a := 0;
      if (b > 59) then b := 59 else if (b < 0) then b := 0;
      if (c > 59) then c := 59 else if (c < 0) then c := 0;
      time := (a SHL 11) OR (b SHL 5) OR c;
      writeln(' New Time is : ', FTimeStr(time));
   end;
   (*}}}*)
   (*{{{  neues Datum einlesen*)
   // neues Datum einlesen
   if (InputBox('Bitte Datum eingeben',s) = 1) then begin
      a := atoi(s); i := pos('.',s); delete(s, 1, i); // Tag
      b := atoi(s); i := pos('.',s); delete(s, 1, i); // Monat
      c := atoi(s);                                   // Jahr
      if (a > 31) then a := 31 else if (a < 1) then a := 1;
      if (b > 12) then b := 12 else if (b < 1) then b := 1;
      if (c > 1980) then c := c - 1980
      else if (c <= 99) AND (c >= 80) then c := c-80
      else if (c >= 0) AND (c < 80) then c := c+20;
      date := (c SHL 9) OR (b SHL 5) OR a;
      writeln(' New Date is : ', FDateStr(date));
   end;
   (*}}}*)

   // Datum und Zeit zusammensetzen
   new_ft := (date SHL 16) OR time;

   i := 0;
   repeat
      // kompletten Dateinamen mit Pfad ermitteln
      s := IterateProjectModules(false, i);
      if (s <> '') then begin
         Writeln(s); Assign(f, s);
         GetFTime(f, ft);
         writeln('  vor:  ',FDateStr(ft SHR 16),' ', FTimeStr(ft));
         SetFTime(f, new_ft); GetFTime(f, ft);
         writeln('  nach: ',FDateStr(ft SHR 16),' ', FTimeStr(ft));
      end;
      Inc(i);
   until s = '';

end;
(*}}}*)
(*{{{  procedure ProjectSetFAttrToNormal*)
{ ProjectSetFAttrToNormal
  Setzt die Dateiattribute aller im Projekt enthaltener
  Dateien auf Normal.
  ReadOnly und Archive Flags werden dadurch zurückgesetzt.
}
procedure ProjectSetFAttrToNormal;
var  s : string;
     i : integer;
     f : file;
begin
   i := 0; MacroConsoleClear;
   repeat
      // kompletten Dateinamen mit Pfad ermitteln
      s := IterateProjectModules(false, i);
      if (s <> '') then begin
         Writeln (s);
         if (fileexist(s)) then begin
            Assign  (f, s);
            SetFAttr(f, FILE_ATTRIBUTE_NORMAL);
         end else begin
            Writeln(' File NOT found');
         end;
      end;
      Inc(i);
   until s = '';
end;
(*}}}*)

// Dateien sortieren
(*{{{  ProjectSortFiles*)
{ ProjectSortFiles
  Dateien sortieren
}
procedure ProjectSortFiles;
var s : string;
    i : integer;
    x : integer;
begin
   // Subfalten koennen fuer sich sortiert werden,
   // wenn sie zuvor in einem eigenen Fenster geoeffnet werden
   TempStoreClear(0);
   StartOfText; FoldExpandAll;

   (*{{{  Alle Module aus der Projektdatei loeschen*)
   // Alle Module aus der Projektdatei loeschen
   repeat
      if (IsModuleTitle) then begin
         s := GetModuleName;
         TempStoreInsSorted(0, s, 0);
         // Zeile loeschen : damit wird Cursor
         // automatisch in die naechste Zeile gestellt
         FoldDelete;
      end else begin
         // Alle normalen Zeilen ueberspringen
         LineDown;
      end;
   until (IsLastLine);
   (*}}}*)

   (*{{{  Alle gefundenen Dateien der Reihe nach wieder einfuegen*)
   // Alle gefundenen Dateien der Reihe nach wieder einfuegen
   i := 0;
   repeat
      s := TempStoreGetLineAt(0,i);
      if (s <> '') then FileAdd(s);
      Inc(i);
   until (s = '');
   (*}}}*)
end;
(*}}}*)


begin
   if (NOT ToolAvail('CopyFile'))   then define_copy_tool;
   if (NOT ToolAvail('ArcFile'))    then define_zip_tool;
   // Funktionen in Menu eintragen
   MacroMenuAdd('backup_project',     'Backup aller Dateien im Projekt');
   MacroMenuAdd('archive_project',    'ZIP- Archiv anlegen');
   MacroMenuAdd('project_file_size',  'Grösse aller Dateien im Projekt');
   MacroMenuAdd('');
   MacroMenuAdd('add_module',         'C/CPP und Header File einfügen');
   MacroMenuAdd('');
   MacroMenuAdd('C_CPP_ProjectExpert','Bestehende C/CPP Dateien in Projekt aufnehmen');
   MacroMenuAdd('C_CPP_SyncProject',  'Projekt mit Verzeichnis synchronisieren');
   MacroMenuAdd('test_prj_completness',  'Prüfen ob alle Includedateien im Projekt enthalten sind');
   MacroMenuAdd('');
   MacroMenuAdd('MoveProject',        'Projektdateien umziehen');
   MacroMenuAdd('FilesToLower',       'Schreibweise aller Dateien ändern');
   MacroMenuAdd('');
   MacroMenuAdd('ProjectSetFTime',    'Zeit und Datum aller Dateien im Projekt setzen');
   MacroMenuAdd('ProjectSetFAttrToNormal', 'Attribut aller Dateien im Projekt auf Normal setzen');
   MacroMenuAdd('');
   MacroMenuAdd('ProjectSortFiles',   'Dateien in einer Falte sortieren');
end.

