DEFINITION MODULE M2AmigaLib;

(*
 * 23-Aug-92/bp
 *
 * Diese Library ist nur für die Benutzung von M2Amiga-Programmen
 * ausgelegt.
 *
 * Deshalb wird vom Benutzer größte Umsicht verlangt!!!!
 *
 *)

FROM SYSTEM	IMPORT	ADDRESS;
FROM ExecD	IMPORT	Library;
IMPORT R;

(* Eigene Importe: *)
FROM DosD	IMPORT	FileLockPtr;

CONST
  version	= 35;
  maxPathLen	= 128;
  maxFileName	= maxPathLen;


TYPE
  ModName	= ARRAY [0..35] OF CHAR;
  PathName	= ARRAY [0..maxPathLen-1] OF CHAR;

CONST
  pathFileName="path";
TYPE
  FileType=(defFile,modFile,symFile,
 	    objFile,ob1File,ob2File,ob3File,ob4File,ob8File,
 	    refFile,binFile);
  ObFileType=[objFile..ob8File];

(*
 * Listenstrategie:
 *
 * Neue kommen beim Öffnen immer vorne rein.
 * Bei Speichermangel oder so fangen wir hinten an zu löschen.
 *
 *)

  (* Read-Only! *)
  ObjType	= FileType;
  ObTypeSet	= SET OF ObFileType;
  ObjFilePtr	= POINTER TO ObjFile;
  ObjFile	= RECORD
    succ,
    pred:	ObjFilePtr;
    magic,		(* zum testen, ob von mir *)
    useCount:	LONGINT;
    name:	ModName; (* der Dateiname ohne Endung z.B. "RArts" *)
    pathName:	PathName;
    buffer:	ADDRESS;
    buffLen:	LONGINT;
    valid:	BOOLEAN;
    realType:	FileType; (* obj..ob8 *)
    CASE type:	FileType OF (* hier steht nur objFile, auch wenn z.B. ob4 *)
    | defFile,modFile,symFile,refFile: (* andere nicht *)
	(* ; nix *)
    | objFile:
	(*
	 * Bit = 1: Das Ding wurde schon einmal gesucht, gibt es aber nicht.
	 * hier vermerken, welche schon geladen sind.
	 * 5,6,7 sind immer auf 1!
	 *)
	cpuDoesntExist: ObTypeSet;
	(* Pro cpuType nur EINEN obx halten! *)
    END; (* CASE tpe *)
  END;
  ObjList	= RECORD
    head,
    tail,
    tailPred:	ObjFilePtr;
  END;


  M2AmigaBasePtr = POINTER TO M2AmigaBase;
  GlobVarPtr = POINTER TO GlobVars;
  M2AmigaBase = RECORD
    lib:	Library;
    pad:	INTEGER; (* auf Langwort kommen *)
    globs:	GlobVarPtr; (* viel effektiver! direkt in Library *)
  END;

  GlobVars = RECORD
      (* private: *)
    filler:	INTEGER; (* longalign *)
      (* für m2errors: *)
    errOpenCnt:	INTEGER;
    errBuffer:	ADDRESS;
    errSize:	LONGINT;

      (* für Syms und Objs *)
      (*
       * MAX positiv: maximal ca. soviel halten,
       * MAX negativ: mindestens ca. soviel Speicher freihalten
       * Voreinstellung: -300KB
       *)
      (* public: *)
    objMaxMem:	LONGINT;

      (* private *)
    objUsedMem,
    objUseCnt:	LONGINT;
    objList:	ObjList;
  END;


CONST
  baseSize = SIZE(M2AmigaBase); (* Nur für M2LibLink wichtig *)


PROCEDURE LibOpen(myLib{R.A6}:M2AmigaBasePtr):ADDRESS;
PROCEDURE LibClose(myLib{R.A6}:M2AmigaBasePtr):ADDRESS;
PROCEDURE LibExpunge(myLib{R.A6}:M2AmigaBasePtr):ADDRESS;
PROCEDURE LibExtFunc(myLib{R.A6}:M2AmigaBasePtr):ADDRESS;

(* Eigene Prozeduren: *)

TYPE
  ErrorMsg	= ARRAY [0..255] OF CHAR;
  ErrorPtr	= POINTER TO Error;
  Error	= RECORD
    next:	ErrorPtr;
    no:		INTEGER;
    msg:	ErrorMsg
  END;

(*
 * GetErrMsgs liefert eine Zeiger auf die globale Liste der
 * Fehlermeldungen oder NIL. Jede ERFOLGREICHE Anforderung muß mit
 * FreeErrMsgs wieder freigegeben werden!
 * Eine Expunge-Anforderung oder des Systems löscht die Fehlermeldungen,
 * wenn sie nicht benutzt sind.
 *)
PROCEDURE GetErrMsgs():ErrorPtr;
PROCEDURE FreeErrMsgs;


(*
 * Example: MakeIcon(fileName,"sym");
 * Sucht in m2:icons/ erzeugt KEIN neues Icon, wenn eins da ist!
 * name, icon sind CONST!
 *)
PROCEDURE MakeIcon(name,icon: ARRAY OF CHAR);

(*
 * File-Utilities
 *
 * Exists stellt fest, ob das Objekt existiert, File oder Directory.
 *   errExists = kein Speicher oder Examine-Fehler
 * ObjExists liefert TRUE, wenn ein Lock existiert, egal ob
 *   File oder Dir.
 *)
TYPE
  ExistsResult = (errExists, noExists, fileExists, dirExists);

PROCEDURE Exists(name: ARRAY OF CHAR):ExistsResult;
PROCEDURE ObjExists(name: ARRAY OF CHAR):BOOLEAN;

(*
 * LoadFile holt ein ganzes File in den Speicher und alloziert Speicher
 *   dafür. Bei einem Fehler sind adr, len = 0
 * FreeFile gibt den Speicher wieder frei und setzt die Vars auf 0
 *   Falls adr=NIL ist, wird nur len auf 0 gesetzt.
 *   Darf nur für Sachen aufgerufen werden, die von LoadFile kommen
 *   Zum Freigeben reicht aber ein simples FreeMem!
 *)
TYPE
  LFResult = (lfOk, lfNotFound, lfDosErr, lfNoMem);

PROCEDURE LoadFile(name:ARRAY OF CHAR; VAR adr:ADDRESS; VAR len:LONGINT):LFResult;
PROCEDURE FreeFile(VAR adr:ADDRESS; VAR len:LONGINT);


(*
 * Routinen für M2File, dürfen NUR von M2File aufgerufen werden!!!!!!!!!!
 *)

(*
 * Now we're up to 11 different file types, we started with just 3 types.
 * This should cover all possibilities used within M2Amiga. Did I/we miss
 * one? For each of these types a extension and a subdirectory are defined.
 * These definitions cannot be changed by the user. I don't think it is
 * necessary but maybe you or the users want it badly.
 *
 * These definitions are:	FileType	dir	ext
 *				defFile		src	.def
 *				modFile		src	.mod
 *				symFile		sym	.sym
 *				objFile		obj	.obj,.ob1....
 *				refFile		ref	.ref
 *				binFile		bin
 *
 * M2Amiga should allow you to use a main project directory containing
 * just subdirectories, their icons and eventually a local m2path file.
 *)

TYPE
  PathEntryPtr;
  MFPars = RECORD (* den benutzt nur M2File!! *)
    userPath,
    defaultPath:	PathEntryPtr;
    originalDirectory,
    newDir:		FileLockPtr;
  END;

PROCEDURE GetFileName(VAR p:MFPars; VAR name: ARRAY OF CHAR;
                      type: FileType; module: ARRAY OF CHAR; new: BOOLEAN);
(*
 * GetFileName is used to find the filename of a file of <type> for <module>
 * which is returned in <name>.
 * If <new> is FALSE, it is assumed that an appropriate file must exist
 * somewhere along the path. If such a file is found its complete name
 * is returned else this procedure returns the local name as generated with
 * <new> set to TRUE.
 * If <new> is TRUE only a local filename suitable for opening such a
 * file is generated. Setting <new> to TRUE can also be used to limit the
 * search for the local directory and subdirectories, however you have to check
 * for yourself if such a file already exists.
 *)

PROCEDURE ReadPathTable(VAR p: MFPars; name: ARRAY OF CHAR);
(*
 * The global path table is read in the initialization of this module, local
 * path tables must be read after each change of directory.This local path
 * table then is used until a next call to ForgetPathTable. The default name
 * is defined in this module <pathFileName>.
 * If the current directory is a subdirectory within a project structure,
 * ReadPathTable changes the directory to the project's main directory.
 *)

PROCEDURE ForgetPathTable(VAR p: MFPars);
(*
 * Geht wieder ins HauptDirectory, UnLock alle neuen Locks
 * Dies ist nötig geworden, weil m2l und m2c nun ein cd-Kommando besitzen!
 * Muß VOR einem CD-Wechsel aufgerufen werden!
 * Die anderen Programme können so bleiben, ReadPathTable macht auch Forget.
 *)

PROCEDURE GetInputFile(VAR p: MFPars; VAR name: ARRAY OF CHAR;
                       type: FileType; givenName: ARRAY OF CHAR);
(*
 * GetInputFile now allows you to get an input file name from incomplete
 * user specifications. This allows to use programs like m2c and m2l easier.
 * Now the module name is sufficient to find the appropriate input file.
 * GetInputFile first checks if <givenName> contains a path and/or the correct
 * extension for this type. Then the missing parts are added to create a
 * valid filename for <type> in the current project.
 *
 * Examples:	givenName		name
 *		obj/dummy.obj		obj/dummy.obj
 *		obj/dummy		obj/dummy.obj
 *		dummy.obj		obj/dummy.obj
 *		dummy			obj/dummy.obj
 * BUT:		dummy.mod		obj/dummy.mod.obj
 *		src/dummy		src/dummy.obj
 *
 * NOTE:
 *
 * The compiler has to be careful using this routine, there modFile is only
 * a default but not the only type of files allowed. This may also apply to
 * other programs of M2Amiga. My solution checks for a '.' in the filename
 * at len-4 and if there is one it assumes a correct filename already given.
 * If YOU have any idea to solve this problem, you're welcome to tell me
 * you proposal. NO, checking if the given name already is a file does not
 * work because usually the binary file has the module name as its filename.
 * => m2l dummy would find an earlier version of <dummy>.
 *)




(*
 * Sym- und Obj-Prozeduren
 *
 * FlushAll löscht alle entsprechenden Objekte aus dem Speicher
 * Get... lädt das Ding gepackt in den Speicher,
 * das zurückgegebene Objekt darf NICHT verändert werden!!!
 * Es muß mit Free.. wieder freigegeben werden.
 * GeneratingNew... erzeugt ein Flush auf das einzelne Objekt
 *    Unsinn! Das kann GetFileName machen, wenn new=TRUE! tut es aber nicht!
 *
 *)

PROCEDURE FlushAll; (* löscht auch ErrMsgs! *)

PROCEDURE GeneratingNew(modName: ARRAY OF CHAR; t:FileType);

(*
 * holt das Ding aus Liste oder lädt es.
 * sucht automatisch von ob8 bis ob0 runter
 * Der volle Pfad steht in o^.pathName
 *
 * ACHTUNG: m2l muß den Puffer noch kopieren, weil er ihn verändert!
 *)
PROCEDURE GetObj(VAR p:MFPars; VAR fullName:ARRAY OF CHAR; t:FileType;
		 modName: ARRAY OF CHAR): ObjFilePtr;
PROCEDURE FreeObj(VAR o: ObjFilePtr; killIt:BOOLEAN);

(*
 * Um alle Objecte eines bestimmten Typs (NICHT ob1..ob8!) zu löschen
 *
 *)
PROCEDURE FlushType(t:FileType);

(*
 * Um alle lokalen Objecte zu löschen.
 * Die haben im pathName nur die Dir am Anfang ("???/...")
 *)
PROCEDURE FlushLocals;

END M2AmigaLib.def
