 (defun eci-process-map-list (string)
   "Parse the output of a map-xxx-list ECI command and return an alist.
 STRING is the string returned by a map-xxx-list command."
-  (mapcar
-   (lambda (elt)
-     (append
-      (list (nth 1 elt) (nth 0 elt) (nth 2 elt))
-      (let (res (count (string-to-number (nth 3 elt))))
-	(setq elt (nthcdr 4 elt))
-	(while (> count 0)
-	  (setq
-	   res
-	   (cons
-	    (list (nth 0 elt) (nth 1 elt)
-		  (string-to-number (nth 2 elt)) ;; default value
-		  (when (string= (nth 3 elt) "1")
-		    (string-to-number (nth 4 elt)))
-		  (when (string= (nth 5 elt) "1")
-		    (string-to-number (nth 6 elt)))
-		  (cond
-		   ((string= (nth 7 elt) "1")
-		    'toggle)
-		   ((string= (nth 8 elt) "1")
-		    'integer)
-		   ((string= (nth 9 elt) "1")
-		    'logarithmic)
-		   ((string= (nth 10 elt) "1")
-		    'output))) res)
-	   elt (nthcdr 11 elt)
-	   count (1- count)))
-	(reverse res))))
-   (mapcar (lambda (str) (split-string str ","))
-	   (split-string string "\n"))))
+  (delq nil
+	(mapcar
+	 (lambda (elt)
+	   (when (stringp (nth 3 elt))
+	     (append
+	      (list (nth 1 elt) (nth 0 elt) (nth 2 elt))
+	      (let (res (count (string-to-number (nth 3 elt))))
+		(setq elt (nthcdr 4 elt))
+		(while (> count 0)
+		  (setq
+		   res
+		   (cons
+		    (list (nth 0 elt) (nth 1 elt)
+			  (string-to-number (nth 2 elt)) ;; default value
+			  (when (string= (nth 3 elt) "1")
+			    (string-to-number (nth 4 elt)))
+			  (when (string= (nth 5 elt) "1")
+			    (string-to-number (nth 6 elt)))
+			  (cond
+			   ((string= (nth 7 elt) "1")
+			    'toggle)
+			   ((string= (nth 8 elt) "1")
+			    'integer)
+			   ((string= (nth 9 elt) "1")
+			    'logarithmic)
+			   ((string= (nth 10 elt) "1")
+			    'output))) res)
+		   elt (nthcdr 11 elt)
+		   count (1- count)))
+		(reverse res)))))
+	 (mapcar (lambda (str) (split-string str ","))
+		 (split-string string "\n")))))
 
 (defeci cs-set-audio-format
   ((format (ecasound-read-from-minibuffer



;;; ECI --- The Ecasound Control Interface

(defgroup eci nil
  "Ecasound Control Interface."
  :group 'ecasound)

(defcustom eci-program (or (getenv "ECASOUND") "ecasound")
  "*Program to invoke when doing `eci-init'."
  :group 'eci
  :type '(choice string (cons string string)))

(defcustom eci-arguments '("-c" "-D" "-d:256")
  "*Arguments used by `eci-init'."
  :group 'eci
  :type 'ecasound-args)

(defvar eci-hide-output nil
  "If non-nil, `eci-command' will remove the output generated.")

(defmacro eci-hide-output (&rest eci-call)
  "Hide the output of this ECI-call.
If a daemon-channel is active, use that, otherwise set `eci-hide-output' to t.
Argument ECI-CALL is a symbol followed by its aruments if any."
  `(if (ecasound-daemon-p)
       ,(append eci-call (list 'ecasound-daemon))
     (let ((eci-hide-output t))
       ,eci-call)))

(defun eci-init ()
  "Initialize a programmatic ECI session.
Every call to this function results in a new sub-process being created
according to `eci-program' and `eci-arguments'.  Returns the newly
created buffer.
The caller is responsible for terminating the subprocess at some point."
  (save-excursion
    (set-buffer
     (apply 'make-comint
	    "eci-ecasound"
	    eci-program
	    nil
	    eci-arguments))
    (ecasound-iam-mode)
    (while (accept-process-output (get-buffer-process (current-buffer)) 1))
    (if (eci-command "int-output-mode-wellformed")
	(current-buffer))))

(defun eci-interactive-startup ()
  "Used to interactively startup a ECI session using `eci-init'.
This will mostly be used for testing sessions and is equivalent
to `ecasound'."
  (interactive)
  (switch-to-buffer (eci-init)))

(defun ecasound-find-buffer (buffer-or-process)
  (cond
   ((bufferp buffer-or-process)
    buffer-or-process)
   ((processp buffer-or-process)
    (process-buffer buffer-or-process))
   ((and (eq major-mode 'ecasound-iam-mode)
	 (comint-check-proc (current-buffer)))
    (current-buffer))
   (t (error "Could not determine suitable ecasound buffer"))))

(defun ecasound-find-parent (buffer-or-process)
  (with-current-buffer (ecasound-find-buffer buffer-or-process)
    (if ecasound-parent
	ecasound-parent
      (current-buffer))))

(defun eci-command (command &optional buffer-or-process)
  "Send a ECI command to a ECI host process.
COMMAND is the string to be sent, without a newline character.
If BUFFER-OR-PROCESS is nil, first look for a ecasound process in the current
buffer, then for a ecasound buffer with the name *ecasound*,
otherwise use the buffer or process supplied.
Return the string we received in reply to the command except
`eci-int-output-mode-wellformed-flag' is set, which means we can parse the
output via `eci-parse' and return a meaningful value."
  (interactive "sECI Command: ")
  (let* ((buf (ecasound-find-buffer buffer-or-process))
	 (proc (get-buffer-process buf))
	 (ecasound-sending-command t))
    (with-current-buffer buf
      (let ((moving (= (point) (point-max))))
	(setq eci-result 'waiting)
	(goto-char (process-mark proc))
	(insert command)
	(let (comint-eol-on-send)
	  (comint-send-input))
	(let ((here (point)) result)
	  (while (eq eci-result 'waiting)
	    (accept-process-output proc 1))
	  (setq result
		(if eci-int-output-mode-wellformed-flag
		    eci-result
		  ;; Backward compatibility.  Just return the string
		  (buffer-substring-no-properties here (save-excursion
					; Strange hack to avoid fields
							 (forward-char -1)
							 (beginning-of-line)
							 (if (not (= here (point)))
							     (forward-char -1))
							 (point)))))
	  (if moving (goto-char (point-max)))
	  (when (and eci-hide-output result)
	    (ecasound-delete-last-in-and-output))
	  result)))))

(defsubst eci-error-p ()
  "Predicate which can be used to check if the last command produced an error."
  (string= eci-return-type "e"))

;;; ECI commands implemented as lisp functions

(defeci int-cmd-list ()

    (if (and result (not (string= result "")))
	result
      default)))

;;; ECI --- The Ecasound Control Interface

(defgroup eci nil
  "Ecasound Control Interface."
  :group 'ecasound)

(defcustom eci-program (or (getenv "ECASOUND") "ecasound")
  "*Program to invoke when doing `eci-init'."
  :group 'eci
  :type '(choice string (cons string string)))

(defcustom eci-arguments '("-c" "-D" "-d:256")
  "*Arguments used by `eci-init'."
  :group 'eci
  :type 'ecasound-args)

(defvar eci-hide-output nil
  "If non-nil, `eci-command' will remove the output generated.")

(defmacro eci-hide-output (&rest eci-call)
  "Hide the output of this ECI-call.
If a daemon-channel is active, use that, otherwise set `eci-hide-output' to t.
Argument ECI-CALL is a symbol followed by its aruments if any."
  `(if (ecasound-daemon-p)
       ,(append eci-call (list 'ecasound-daemon))
     (let ((eci-hide-output t))
       ,eci-call)))

(defun eci-init ()
  "Initialize a programmatic ECI session.
Every call to this function results in a new sub-process being created
according to `eci-program' and `eci-arguments'.  Returns the newly
created buffer.
The caller is responsible for terminating the subprocess at some point."
  (save-excursion
    (set-buffer
     (apply 'make-comint
	    "eci-ecasound"
	    eci-program
	    nil
	    eci-arguments))
    (ecasound-iam-mode)
    (while (accept-process-output (get-buffer-process (current-buffer)) 1))
    (if (eci-command "int-output-mode-wellformed")
	(current-buffer))))

(defun eci-interactive-startup ()
  "Used to interactively startup a ECI session using `eci-init'.
This will mostly be used for testing sessions and is equivalent
to `ecasound'."
  (interactive)
  (switch-to-buffer (eci-init)))

(defun ecasound-find-buffer (buffer-or-process)
  (cond
   ((bufferp buffer-or-process)
    buffer-or-process)
   ((processp buffer-or-process)
    (process-buffer buffer-or-process))
   ((and (eq major-mode 'ecasound-iam-mode)
	 (comint-check-proc (current-buffer)))
    (current-buffer))
   (t (error "Could not determine suitable ecasound buffer"))))

(defun ecasound-find-parent (buffer-or-process)
  (with-current-buffer (ecasound-find-buffer buffer-or-process)
    (if ecasound-parent
	ecasound-parent
      (current-buffer))))

(defun eci-command (command &optional buffer-or-process)
  "Send a ECI command to a ECI host process.
COMMAND is the string to be sent, without a newline character.
If BUFFER-OR-PROCESS is nil, first look for a ecasound process in the current
buffer, then for a ecasound buffer with the name *ecasound*,
otherwise use the buffer or process supplied.
Return the string we received in reply to the command except
`eci-int-output-mode-wellformed-flag' is set, which means we can parse the
output via `eci-parse' and return a meaningful value."
  (interactive "sECI Command: ")
  (let* ((buf (ecasound-find-buffer buffer-or-process))
	 (proc (get-buffer-process buf))
	 (ecasound-sending-command t))
    (with-current-buffer buf
      (let ((moving (= (point) (point-max))))
	(setq eci-result 'waiting)
	(goto-char (process-mark proc))
	(insert command)
	(let (comint-eol-on-send)
	  (comint-send-input))
	(let ((here (point)) result)
	  (while (eq eci-result 'waiting)
	    (accept-process-output proc 1))
	  (setq result
		(if eci-int-output-mode-wellformed-flag
		    eci-result
		  ;; Backward compatibility.  Just return the string
		  (buffer-substring-no-properties here (save-excursion
					; Strange hack to avoid fields
							 (forward-char -1)
							 (beginning-of-line)
							 (if (not (= here (point)))
							     (forward-char -1))
							 (point)))))
	  (if moving (goto-char (point-max)))
	  (when (and eci-hide-output result)
	    (ecasound-delete-last-in-and-output))
	  result)))))

(defsubst eci-error-p ()
  "Predicate which can be used to check if the last command produced an error."
  (string= eci-return-type "e"))

;;; Markers

