You use your old friend **FORMAT** to emit a prompt. Note that there’s no ~% in the format string, so the cursor will stay on the same line. The call to **FORCE-OUTPUT** is necessary in some implementations to ensure that Lisp doesn’t wait for a newline before it prints the prompt.

    Then you can read a single line of text with the aptly named **READ-LINE** function. The variable *query-io* is a global variable (which you can tell because of the * naming convention for global variables) that contains the input stream connected to the terminal. The return value of prompt-read will be the value of the last form, the call to **READ-LINE**, which returns the string it read (without the trailing newline.)

    You can combine your existing make-cd function with prompt-read to build a function that makes a new CD record from data it gets by prompting for each value in turn.

    1. (defun prompt-for-cd ()
    2. (make-cd
    3. (prompt-read "Title")
    4. (prompt-read "Artist")
    5. (prompt-read "Rating")
    6. (prompt-read "Ripped [y/n]")))
    1. (parse-integer (prompt-read "Rating"))

    Unfortunately, the default behavior of **PARSE-INTEGER** is to signal an error if it can’t parse an integer out of the string or if there’s any non-numeric junk in the string. However, it takes an optional keyword argument :junk-allowed, which tells it to relax a bit.

    But there’s still one problem: if it can’t find an integer amidst all the junk, **PARSE-INTEGER** will return NIL rather than a number. In keeping with the quick-and-dirty approach, you may just want to call that 0 and continue. Lisp’s **OR** macro is just the thing you need here. It’s similar to the “short-circuiting” || in Perl, Python, Java, and C; it takes a series of expressions, evaluates them one at a time, and returns the first non-nil value (or **NIL** if they’re all **NIL**). So you can use the following:

    1. (or (parse-integer (prompt-read "Rating") :junk-allowed t) 0)

    to get a default value of 0.

    1. (y-or-n-p "Ripped [y/n]: ")

    In fact, this will be the most robust part of prompt-for-cd, as **Y-OR-N-P** will reprompt the user if they enter something that doesn’t start with y, Y, n, or N.

    Putting those pieces together you get a reasonably robust prompt-for-cd function.

    Finally, you can finish the “add a bunch of CDs” interface by wrapping prompt-for-cd in a function that loops until the user is done. You can use the simple form of the **LOOP** macro, which repeatedly executes a body of expressions until it’s exited by a call to **RETURN**. For example:

    1. (loop (add-record (prompt-for-cd))
    2. (if (not (y-or-n-p "Another? [y/n]: ")) (return))))
    1. CL-USER> (add-cds)
    2. Title: Rockin' the Suburbs
    3. Artist: Ben Folds
    4. Rating: 6
    5. Ripped [y/n]: y
    6. Another? [y/n]: y
    7. Title: Give Us a Break
    8. Rating: 10
    9. Ripped [y/n]: y
    10. Another? [y/n]: y
    11. Title: Lyle Lovett
    12. Artist: Lyle Lovett
    13. Rating: 9
    14. Ripped [y/n]: y
    15. NIL