
(*  EXAMPLE OF HOW TO CONVERT CHARACTER INPUT TO INTEGER DATA  *)

(*
  This program uses character data as input, converting
  character strings to integer data internally.  The procedure
  that does the conversion is InputNum below
*)

PROGRAM InsertionDriver (input, output) ;

TYPE link = ^node ;

     node = record
       data : integer ;
       ptr  : link
     end ;

VAR theListPtr    : link ;
    theNewNode    : node ;
    response      : char ;

(* ################################################## *)
PROCEDURE InputNum ( VAR dataVal : integer ) ;

VAR chNow :  char ;
    found, last : boolean ;

BEGIN (* procedure InputNum *)
  REPEAT
    dataVal  :=  0 ;
    found := false ;
    last := false ;

    (* Skip over initial non-digits *)
    WHILE NOT ( eoln OR found )
    DO BEGIN
         read(chNow) ;
         found := ( chNow in [ '0' .. '9'] )
       END ;

    (* Interpret the first series of digits as the number *)
    IF   found
    THEN REPEAT
           dataVal := (dataVal * 10) + ( ord(chNow) - ord('0') ) ;
           IF   eoln
           THEN last := true
           ELSE read(chNow)
         UNTIL last OR  NOT (chNow IN [ '0' .. '9' ]) ;

    (* Ignore the rest of the line *)
    readln ;

    IF NOT found THEN writeln ('Please try again: ')

  UNTIL found
END ;  (* procedure InputNum *)

(* ################################################## *)
PROCEDURE FindInsertLoc (  key            : integer;
                           listPtr        : link;
                           var prevPtr    : link;
                           var curntPtr   : link        ) ;

VAR foundBigger : boolean ;

BEGIN (* procedure FindInsertLoc *)
  foundBigger := false ;
  prevPtr := nil ;
  curntPtr := listPtr ;
  WHILE (curntPtr <> nil) AND (NOT foundBigger)
  DO BEGIN
       IF curntPtr^.data <= key
       THEN BEGIN
              prevPtr := curntPtr ;
              curntPtr := curntPtr^.ptr
            END
       ELSE foundBigger := true
     END
END ; (* procedure FindInsertLoc *)


(* ################################################## *)
PROCEDURE Insert (  newNode        : node;
                    VAR listPtr    : link         ) ;

VAR prevPtrI, curntPtrI, ptrToNew : link ;

BEGIN (* procedure Insert *)
  new(ptrToNew) ;
  ptrToNew^ := newNode ;
  FindInsertLoc( newNode.data, listPtr, prevPtrI, curntPtrI) ;
  ptrToNew^.ptr := curntPtrI ;
  IF prevPtrI = nil
  THEN listPtr := ptrToNew
  ELSE prevPtrI^.ptr := ptrToNew
END ; (* procedure Insert *)


(* ################################################## *)
PROCEDURE PrintList (listPtr : link) ;

VAR curntPtrP : link ;

BEGIN (* procedure PrintList *)
p  IF listPtr = nil
  THEN writeln('The list is empty')
  ELSE BEGIN
         writeln('The list is: ') ;
         curntPtrP := listPtr ;
         REPEAT
           writeln ('             ',curntPtrP^.data) ;
           curntPtrP := curntPtrP^.ptr
         UNTIL curntPtrP = nil
       END
END ; (* procedure PrintList *)

BEGIN (* program InsertionDriver *)
  write ('Hi.  This is a program that maintains an ') ;
  writeln('ordered list of non-negative integers.') ;
  writeln ('You will build the list with your input.') ;
  writeln ;
  theListPtr := nil ;
  REPEAT
    writeln('please type a (non-negative) integer to insert:') ;
    InputNum(theNewNode.data) ;
    Insert(theNewNode, theListPtr) ;
    PrintList(theListPtr) ;
    writeln('Do you want to insert another? (y/n) ') ;
    readln (response) ;
  UNTIL (response = 'n') OR (response = 'N')
END.  (* program InsertionDriver *)
