;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; Package: umlisp -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:     parse-macros.lisp
;;;; Purpose:  Macros for UMLS file parsing
;;;; Author:   Kevin M. Rosenberg
;;;; Created:  Apr 2000
;;;;
;;;; $Id$
;;;;
;;;; This file, part of UMLisp, is
;;;;    Copyright (c) 2000-2006 by Kevin M. Rosenberg, M.D.
;;;;
;;;; UMLisp users are granted the rights to distribute and use this software
;;;; as governed by the terms of the GNU General Public License.
;;;; *************************************************************************

(in-package #:umlisp)

(defun read-umls-line (strm &optional (eof 'eof))
  "Read a line from a UMLS stream, split into fields"
  (let ((line (read-line strm nil eof)))
    (if (eq line eof)
        eof
        (delimited-string-to-list line #\| t))))

(defun source-files (path)
  (if (probe-file path)
      (list path)
    (sort
     (directory (make-pathname :defaults path
                               :type :wild
                               :name (concatenate 'string (pathname-name path)
                                                  (aif (pathname-type path)
                                                       (concatenate 'string "." it)
                                                       ""))))
     #'(lambda (a b)
         (string-lessp (pathname-type a) (pathname-type b))))))

(defmacro with-buffered-reading-umls-file ((line path) &body body)
  "Opens a UMLS and processes each parsed line with (body) argument"
  (let ((ustream (gensym "STRM-"))
        (buffer (gensym "BUF-"))
        (eof (gensym "EOF-"))
        (files (gensym "FILES-")))
    `(let ((,eof (gensym "EOFSYM-"))
           (,buffer (make-fields-buffer))
           (,files (source-files ,path)))
       (with-open-file (,ustream (first ,files) :direction :input
                        #+(and clisp unicode) :external-format
                        #+(and clisp unicode) charset:utf-8)
         (do ((,line (read-buffered-fields ,buffer ,ustream #\| ,eof)
                     (read-buffered-fields ,buffer ,ustream #\| ,eof)))
             ((eq ,line ,eof) t)
           (setq ,line (coerce ,line 'list))
           (print ,line)
           ,@body)))))

(defmacro with-reading-umls-file ((line path) &body body)
  "Opens a UMLS and processes each parsed line with (body) argument"
  (let ((ustream (gensym "STRM-"))
        (eof (gensym "EOF-"))
        (files (gensym "FILES-")))
    `(let ((,eof (gensym "EOFSYM-"))
           (,files (source-files ,path)))
      (unless ,files
        (error "Can't find files for ~A~%" (namestring ,path)))
      (with-open-file (,ustream (first ,files) :direction :input
                       #+(and clisp unicode) :external-format
                       #+(and clisp unicode) charset:utf-8)
        (do ((,line (read-umls-line ,ustream ,eof)
                    (read-umls-line ,ustream ,eof)))
            ((eq ,line ,eof) t)
          (locally (declare (type list ,line))
                   ,@body))))))

(defmacro with-umls-ufile ((line ufile) &body body)
  "Opens a UMLS and processes each parsed line with (body) argument"
  `(with-reading-umls-file (,line (ufile-pathname ,ufile))
     ,@body))

(defmacro with-umls-file ((line ufile) &body body)
  "Opens a UMLS and processes each parsed line with (body) argument"
  `(with-reading-umls-file (,line (umls-pathname ,ufile))
     ,@body))

(defmacro with-buffered-umls-file ((line filename) &body body)
  "Opens a UMLS and processes each parsed line with (body) argument"
  (let ((ustream (gensym "STRM-"))
        (buffer (gensym "BUF-"))
        (eof (gensym "EOF-")))
    `(let ((,buffer (make-fields-buffer))
           (,eof (gensym "EOFSYM-")))
      (with-open-file
          (,ustream (umls-pathname ,filename) :direction :input)
        (do ((,line (read-buffered-fields ,buffer ,ustream #\| ,eof)
                    (read-buffered-fields ,buffer ,ustream #\| ,eof)))
            ((eq ,line ,eof) t)
          ,@body)))))


