First, is this a fixed query, or an arbitrary one? If it's fixed, you'll have an easier time. Arbitrary queries will have to be run via dbms_sql, so you can return column attributes. That's messy.
Second, keep in mind that SQL*Plus formatting is controllable by settings in the client. Things like line length, page size, column widths, headers, etc. are all able to be changed from execution to execution.
That said, assuming it's a fixed query, then I'd:
- open a cursor for the query
- If there's data, print the column headers (including the '------' lines)
- loop through the cursor, printing each value for the record in proper format
- close the cursor
You should be able to format your output by examining the output from SQL*Plus and copying that.