Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!news.glorb.com!border3.nntp.dca.giganews.com!Xl.tags.giganews.com!border1.nntp.dca.giganews.com!nntp.giganews.com!local2.nntp.dca.giganews.com!news.giganews.com.POSTED!not-for-mail NNTP-Posting-Date: Mon, 03 Dec 2012 15:20:22 -0600 From: John Deubert Organization: Acumen Training Newsgroups: comp.lang.postscript Date: Mon, 3 Dec 2012 13:20:22 -0800 Message-ID: <2012120313202243338-john@acumentrainingcom> References: <87624kp6hc.fsf@Compaq.site.inet> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1; format=flowed Content-Transfer-Encoding: 8bit Subject: Re: Putting lines from a file into an array User-Agent: Unison/2.1.10 Lines: 165 X-Usenet-Provider: http://www.giganews.com X-Trace: sv3-H1KL6KbcOJ431g0UiUTvWlKTiUmkjrdCM0djHGUmkEh1enjSELCOxz92AVPkHONePGbr17z4tBXSy0/!FcykiyNvcam+sItczhK72m+9tjNDbRVjg4mB1IlhPXC+4DN1xYTh+dxLSuc055WtfT2CKqdf X-Complaints-To: abuse@giganews.com X-DMCA-Notifications: http://www.giganews.com/info/dmca.html X-Abuse-and-DMCA-Info: Please be sure to forward a copy of ALL headers X-Abuse-and-DMCA-Info: Otherwise we will be unable to process your complaint properly X-Postfilter: 1.3.40 X-Original-Bytes: 6298 Xref: csiph.com comp.lang.postscript:1137 On 2012-12-02 20:47:26 +0000, Chris said: > On Sun, 02 Dec 2012 21:02:55 +0100, Cecil Westerhof wrote: > >> I have the following script: >> /buffer 80 string def /inputFile INPUT (r) file def { >> inputFile buffer readline { >> = >> }{ >> pop inputFile closefile exit >> } ifelse >> } loop >> >> This displays the file. But instead of displaying I would like to put >> the lines into an array. >> >> Just keeping the values on the stack Like: >> /buffer 80 string def /inputFile INPUT (r) file def { >> inputFile buffer readline { >> % Keep it on the stack >> }{ >> pop inputFile closefile exit >> } ifelse >> } loop stack >> >> does not work, because the lower values are overwritten. >> >> The first script gives: >> They are not only idle who do nothing, >> but they are idle also who might be better employed. >> >> Socrates >> >> While the second gives: >> Socrates >> >> Socratest be better employed. Socratest be better em Socratest be >> better employed. nothing, >> >> How would I get the lines correctly into an array? > > The values get overwritten because you only allocate one string for the > lines to be read into ("/buffer 80 string def"), then reuse it for each > iteration through the loop. > > Something like: > > /inputFile INPUT (r) file def > /linearray > [ > { > inputFile 80 string readline > not > { > pop inputFile closefile > currentdict /inputFile undef > exit > } if > } loop > ] > def > > > will give you the lines of the file in an array called "linearray". > > You can dump the contents thus: > > linearray {print (\n) print } forall > > (Note the explicit new line) > > Chris Note that there is possible error condition implicit in the above method; using brackets to construct the array places the array contents temporarily on the stack. All of the lines in the file are being piled up on the stack, remaining there until the close bracket. If you have a very large file (that is, a file with a large number of lines in it), you will eventually provoke a stack overflow. The maximum size of the operand stack is implementation dependent in Level 2 & 3 devices, so it's hard to say when (or if) you'll encounter the problem. I'm not at all saying this is a bad solution; it's probably how I'd do it. But if you get the very occasional stack overflow from this solution, that's probably the source of the problem. Hmmm. How can we fix this? The problem is that unless you use the brackets to construct your array, PostScript requires you allocate the array ahead of time, which, in turn, requires knowing how many lines there are in the file. You could read the file twice (once counting lines, the second actually constructing the array), but that seems inelegant, somehow. << ... some minutes later ... >> Here's a novel solution based on the fact that PostScript dictionaries automatically expand as needed. Let's read the lines into a dictionary, see how many key-value pairs end up in the dictionary, make an array with room for that many items, and then transfer the strings from the dictionary to the array. A bit convoluted, but should be immune to stackoverflow errors. Lessee here... % ============== Cut here ============== /$lines 100 dict def % Our dictionary of lines; initially room for 100 lines, expandable /inputFile INPUT (r) file def /i 0 def $lines begin % Put the dict on the dict stack for convenience % Let's construct the dictionary { inputFile 100 string readline % read a line of text exch % Bring the string to the top of the stack i exch def % define i and the line as a key-value pair /i i 1 add store % and increment i not { exit } if % leave the loop if that was the last line } loop % At this point, the $lines dictionary contains line numbers and line text as key-value pairs % Now we need to transfer the lines to an array. % First we create the array: /numLines currentdict length def % Note that numLines ends up in our "$lines" dict; this is fine with me. numLines array % Create the new array 0 1 numLines 1 sub % Interate through the lines in the dictionary { % Stack: [ ] i 2 copy % Stack: [ ] i [ ] i dup load % Stack: [ ] i [ ] i (line o' text) put pop % Stack: [ ] } for % The loop exits with our array of strings on the stack end % We don't need $lines anymore % Save the array as a variable, if we wish: /linearray exch def % =============== Cut here ================= As I say, not as simple as Chris' version, but it does work around the stack limitation. I'd go with Chris' code unless the number of lines was likely to be northward of 1000 lines or so. (By the way, there's some cleanup one could do on this code, but lunch is beckoning.) - John -- ======== John Deubert Acumen Training PostScript & PDF Engineering Classes & Consulting www.acumentraining.com Learn PostScript programming techniques Read the free Acumen Journal acumentraining.com/acumenjournal.html