home *** CD-ROM | disk | FTP | other *** search
- (in-package "AFFI")
-
- (export 'make-partial-affi-file)
-
- (defun read-fd-directive (stream macro-char)
- (declare (ignore macro-char)
- (special *fd-readtable*))
- (unless (eq *readtable* *fd-readtable*)
- (error "Not the FD-readtable: ~S" *readtable*))
- (let ((*package* (find-package "KEYWORD"))
- (case (readtable-case *readtable*)))
- (unwind-protect
- (progn
- (setf (readtable-case *readtable*) :upcase)
- (read stream t nil t))
- (setf (readtable-case *readtable*) case))))
-
- ;;Problem: AmigaGuide uses * in OpenAmigaGuideA()
- ;; Replace it with attrs, see AutoDocs, which gives
- ;; APTR OpenAmigaGuideA( struct NewAmigaGuide *nag, struct TagItem *attrs )(a0/a1);
-
- (defun make-fd-readtable (&optional (readtable-case :upcase))
- (let ((readtable (copy-readtable nil)))
- ;; , and / separate registers
- (set-syntax-from-char #\, #\ readtable)
- (set-syntax-from-char #\/ #\ readtable)
- ;; * serves as a comment
- (set-syntax-from-char #\* #\; readtable)
- ;; ## introduces specials
- (set-macro-character #\# #'read-fd-directive t readtable)
- ;; we choose to preserve case for all function names
- (setf (readtable-case readtable) readtable-case)
- readtable))
-
- ;; TODO maybe better read strings by preserving case, because output will look nicer?
-
- (defvar *fd-readtable* (make-fd-readtable)) ;or :preserve
-
- (defun read-from-fd (stream &optional (eof-error-p t))
- (let* ((unique "EoF")
- (read
- ;; switch readtables very temporarily only
- (let ((*readtable* *fd-readtable*))
- (read stream nil unique))))
- (if (eq read unique)
- (if eof-error-p
- (error "FD file ~S ended" stream)
- :end)
- read)))
-
- ;; funinfo ist {(function . (offset . mask))}*
- (defun read-fd-functions (stream skip offset funinfo)
- (let ((tag (read-from-fd stream nil)))
- (etypecase tag
- ;;(null (return-from read-fd-functions funinfo))
- (keyword
- (ecase tag
- (:base (error "##base only allowed once: ~S"))
- (:bias (setq offset (- (read-from-fd stream))))
- (:public (setq skip nil))
- (:private (setq skip t))
- (:end (return-from read-fd-functions funinfo)))
- (read-fd-functions stream skip offset funinfo))
- (symbol ;tag is function name
- (let ((vars (read-from-fd stream))
- (regs (read-from-fd stream)))
- (unless (listp vars)
- (error "No FFI variable names read from ~S: ~S" stream vars))
- (unless (listp regs)
- (error "No FFI register specification read from ~S: ~S" stream regs))
- (read-fd-functions
- stream skip (- offset 6)
- (if skip funinfo
- ;;TODO hashtable instead of alist
- (cons (list* tag offset (calc-register-mask
- regs #'(lambda (reg sym) (string-equal reg (symbol-name sym)))))
- funinfo))))))))
-
- ;;Problem: cia_lib.fd contains no library base
- ;; libinfo ist (basename . {(function offset . mask)}*)
- (defun parse-fd (name)
- (with-open-file (file name :direction :input)
- (let ((*package* '#.*package*))
- (unless (eq (read-from-fd file) :base)
- (error "FD file does not start with ##base: ~S" file))
- (let ((library (read-from-fd file)))
- (unless (symbolp library)
- (error "Not a library base name: ~S in ~S" library file))
- (cons (if (char= (schar (symbol-name library) 0) #\_) ;strip leading underscore
- (intern (subseq (symbol-name library) 1))
- library)
- (read-fd-functions file nil -30 ()))))))
-
- ;; Problem: current AFFI.D doesn't handle more than 8 args (uint32)
- ;; It's now 16 args (uint64)
- (defun show-large-masks (libinfos)
- (dolist (libinfo libinfos)
- ;;TODO hashtable instead of alist
- (dolist (funinfo (rest libinfo))
- (unless (typep (cddr funinfo) '(unsigned-byte 32))
- (format t "~&;;Maybe too big mask for ~A in ~A~%" (car funinfo) (car libinfo))))))
- ;;Bignum mask for AddAppIconA in _WorkbenchBase
- ;;Bignum mask for CreateBehindHookLayer in _LayersBase
- ;;Bignum mask for CreateUpfrontHookLayer in _LayersBase
- ;;Bignum mask for CreateBehindLayer in _LayersBase
- ;;Bignum mask for CreateUpfrontLayer in _LayersBase
- ;;Bignum mask for ScrollWindowRaster in _IntuitionBase
- ;;Bignum mask for NewModifyProp in _IntuitionBase
- ;;Bignum mask for AutoRequest in _IntuitionBase
- ;;Bignum mask for ModifyProp in _IntuitionBase
- ;;Bignum mask for WriteChunkyPixels in _GfxBase
- ;;Bignum mask for ScrollRasterBF in _GfxBase
- ;;Bignum mask for WritePixelArray8 in _GfxBase
- ;;Bignum mask for ReadPixelArray8 in _GfxBase
- ;;Bignum mask for TextFit in _GfxBase
- ;;Bignum mask for BltMaskBitMapRastPort in _GfxBase
- ;;Bignum mask for BltBitMapRastPort in _GfxBase
- ;;Bignum mask for ClipBlit in _GfxBase
- ;;Bignum mask for ScrollRaster in _GfxBase
- ;;Bignum mask for BltPattern in _GfxBase
- ;;Bignum mask for BltTemplate in _GfxBase
- ;;Bignum mask for BltBitMap in _GfxBase
- ;;Bignum mask for DoPkt in _DOSBase
-
- (defun make-partial-affi-file (name) ; name like "graphics.library"
- ;; writes file to current directory, reads from FD:<base>_lib.fd
- (let ((fdlibinfo (parse-fd (format () "FD:~A_lib.fd" (pathname-name name))))
- (*package* '#.*package*))
- (with-open-file (stream
- (namestring (make-pathname :type "affi" :defaults name))
- :direction :output
- :if-exists :error) ;at least for now
- (princ "(in-package \"AFFI\")" stream)(terpri stream)
- (format stream "(declare-library-base :~A ~S)~%" (car fdlibinfo) name)
- (format stream "(format *error-output* \"~~&;;; Warning: Please adapt the prototypes for ~~S manually!~~%\" ~S)~%~%" name)
- (dolist (ffinfo (nreverse (rest fdlibinfo)))
- ;; the current implementation of AFFI.D is limited:
- (unless (typep (cddr ffinfo) '(unsigned-byte 32))
- (princ ";; This mask may be too large for AFFI:" stream)
- (terpri stream))
- (format stream ";(defflibfun '~S '~S ~D #x~X '*"
- (car ffinfo) ;Function
- (car fdlibinfo) ;Library
- (cadr ffinfo) ;Offset
- (cddr ffinfo)) ;Mask
- ;; Here we abuse the knowledge that AFFI.D:reg_coding is 4:
- (dotimes (i (ceiling (integer-length (cddr ffinfo)) 4))
- (princ " '*" stream))
- (princ ")" stream)(terpri stream))
- (format stream "~%(provide ~S)~%" name)
- (pathname stream))))
-