private/frtime/demos/spreadsheet/quotes.ss
(module quotes mzscheme
  (require (lib "url.ss" "net"))
  (require (lib "list.ss"))
  
  (provide no-quote? stock-quote no-quote-reason)
  
  (define-struct no-quote (company reason))
  
  #| ----------------------------------------------------------------------------
  Stock and Fund Quotes
  ---------------------
  
  procedures: 
  stock-quote : String -> Number 
  
  exceptions: 
  no-quote : (structure:no-quote String Symbol)
  
  The goal is to send a request to some quote server, 
  read the page line by line, and identify the quote. 
  
  -----------------------------------------------------
  
  First: where the information comes from and 
  how to indentify it within the page: 
  - the current source is Yahoo's page
  - we look for a table cell that looks like
  this: <td nowrap><b>DIGIT*.DIGITDIGIT</b></td>
  |#   
  
  ; String[format: String[company name]]
  (define SOURCE "http://finance.yahoo.com/q?s=~a&d=v1")
  
  ; String -> (union (list String String) #f)
  (define (find x)
    (regexp-match "<b>([0-9\\.]*)</b></big></td>" x))
  
  ; String -> Number
  (define (stock-quote company)
    (let* ([URL (string->url (format SOURCE company))]
           [PG  (call/input-url URL get-pure-port read-a-page)]
	   ; [_ (printf "~s~n" PG)] ; for debugging
           [LN  (filter find PG)]
           [QT  (if (pair? LN)
                    (cadr (find (car LN)))
                    (raise (make-no-quote company 'find)))])
      (cond
        [(string->number QT)]
        [else (raise (make-no-quote company 'no-number))])))
  
  
  ;; Iport -> (listof String)
  ;; reading a page as a list of lines
  (define (read-a-page ip)
    (letrec ([reader (lambda ()
                       (let ([next (read-line)])
                         (cond
                           [(eof-object? next) '()]
                           [else (cons next (reader))])))])
      (parameterize ([current-input-port ip])
        (reader))))
  
  #| TESTS:
  
  (map stock-quote '(; companies 
                     "BAC" "DELL" "IBM" 
                     ; funds 
                     "PRSCX" "NAESX" "FRBAX"))
  
  (with-handlers ([no-quote? (lambda (x) (eq? (no-quote-reason x) 'find))])
    (stock-quote "XXX"))
  
  |#
  
  )