From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: pjb@informatimago.com (Pascal J. Bourguignon) Newsgroups: gmane.emacs.help Subject: Re: Writing to buffer/file Date: Tue, 14 Sep 2010 16:13:50 +0200 Organization: Informatimago Message-ID: References: <87eicwfpjq.fsf@cecilia.trollope> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: dough.gmane.org 1291866052 31546 80.91.229.12 (9 Dec 2010 03:40:52 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Thu, 9 Dec 2010 03:40:52 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Thu Dec 09 04:40:47 2010 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1PQXN8-0003BG-IC for geh-help-gnu-emacs@m.gmane.org; Thu, 09 Dec 2010 04:40:46 +0100 Original-Received: from localhost ([127.0.0.1]:49468 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PQXN7-000194-TV for geh-help-gnu-emacs@m.gmane.org; Wed, 08 Dec 2010 22:40:45 -0500 Original-Path: usenet.stanford.edu!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail Original-Newsgroups: gnu.emacs.help Original-Lines: 218 Original-X-Trace: individual.net sbJTIBQGA5ykpDwN+GQl7AeE6LEnumn0p6819hh123I/r4sjTh Cancel-Lock: sha1:MzViYTllNjk0MDRjN2JlMjY1NjE4ZDhlNDU1OGE5Y2VlNjM4YjhhMQ== sha1:euX1Pkk+AkxRCUPOwOShXtM6g/g= User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (darwin) Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAABlBMVEUAAAD///+l2Z/dAAAA oElEQVR4nK3OsRHCMAwF0O8YQufUNIQRGIAja9CxSA55AxZgFO4coMgYrEDDQZWPIlNAjwq9 033pbOBPtbXuB6PKNBn5gZkhGa86Z4x2wE67O+06WxGD/HCOGR0deY3f9Ijwwt7rNGNf6Oac l/GuZTF1wFGKiYYHKSFAkjIo1b6sCYS1sVmFhhhahKQssRjRT90ITWUk6vvK3RsPGs+M1RuR mV+hO/VvFAAAAABJRU5ErkJggg== X-Accept-Language: fr, es, en X-Disabled: X-No-Archive: no Original-Xref: usenet.stanford.edu gnu.emacs.help:181295 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:76566 Archived-At: Michael Powe writes: > Hello, > > I am writing a function in elisp to do the following: > > open and read an .ini file > search the file for header lines of format [someheader] > put header value as key of hash > continue to search for string value (e.g., "profilename=.*") > add found string value to list which is set as value for the header key > for each header, a small number of items will be added to the list > after reading through ini file and filling the hash: > open another buffer and write the contents of the hash to the buffer > write the buffer to file > > Here is my function: > > (defun extract-ini-settings () > (interactive) > (let (myhash mybuff myfile header strmatch results output strvalues mylist) > (setq myfile "c:\\share\\reports_default.ini") > (setq myhash (make-hash-table :test 'equal)) > (setq mybuff (find-file myfile)) > (set-buffer mybuff) > (setq strvalues "") > (while > (re-search-forward > "\\[customtableprofile[0-9]+\\]" > nil t) > (when (match-string 0) > (setq header (match-string 0)) > (puthash header '() myhash) > (while > (re-search-forward > "profilename=.*" nil t) > (when (match-string 0) > (setq strmatch (match-string 0)) > (puthash header (cons strmatch (gethash header myhash)) myhash))))) > (kill-buffer mybuff) > (message (number-to-string (hash-table-count myhash))) > (setq output "c:\\share\\reports_headers.txt") > (setq results (find-file output)) > (set-buffer results) > (point-min) > ;; this works, i.e. writes the string to the `results' buffer > ;; and each time I run the function, a new copy of the string > ;; is appended to the buffer. > (insert "Start of file\n") > (point-max) > (hash-to-list (myhash mylist)) > (insert mylist) > )) > > Here is the helper function hash-to-list: > > (defun hash-to-list (hashtable mylist) > "Return a list that represent the hashtable." > (maphash (lambda (kk vv) (setq mylist (cons (list kk vv) mylist))) hashtable) > mylist) > > I am evidently grossly misunderstanding the mechanism for writing to > file. Even before that, you're misunderstanding the basic syntaxis for Lisp. To call a function in lisp, we write a LIST, whose first element is the name of the function, and whose other elements are the arguments to that function. To write a list, we write an open parenthesis, the elements of the list separated by spaces, and a close parenthesis. sexp ::= atom | '(' {sexp} ')' . function-call ::= '(' function-name {argument} ')' (hash-to-list (myhash mylist)) Since myhash is not the name of a function the subexpression (myhash mylist) is meaningless, and since hash-to-list is defined to take two arguments, this function call is wrong since you're trying to pass only one (erronous) argument. Finally, as you have noted, arguments are passed by value, so when you call: (hash-to-list myhash mylist) hash-to-list has no way to modify mylist. I assume this is why you're correctly returning from hash-to-list the local variable mylist which contains the result of hash-to-list. In any case, you will have to rebind this result to the mylist of extract-ini-settings: (setf mylist (hash-to-list myhash mylist)) (insert mylist) or even better, just insert it directly: (insert (prin1-to-string (hash-to-list myhash mylist))) Notice that insert can insert only strings, so you have to convert your list into a string first. Since mylist is bound to nil, there's not really any point in passing it to hash-to-list. So you could write: (require 'cl) (defun hash-to-list (hashtable) "Return a list that represent the hashtable." (let ((result '())) (maphash (lambda (kk vv) (push (list kk vv) result)) hashtable) result)) (let ((h (make-hash-table))) (setf (gethash :one h) 1 (gethash :two h) 2 (gethash :six h) 6) (insert (prin1-to-string (hash-to-list h)))) inserts: ((:six 6) (:two 2) (:one 1)) In general, it is better of you can write functionnal code, that is, if you can avoid modifying the bindings of the variables (avoid using setq of setf). This means that when you use let, you SHOULD give a value to be bound to each variable, and not change it thereafter. Also, it would be better if you parameterized your functions, ie. avoid putting constants, such as pathnames inside your functions. It would be nice if you avoided to to define variables that you don't use. (But do define variables that you use!). (defun extract-ini-settings (ini-file dictionary-file) (interactive) (let ((dictionary (make-hash-table :test (function equal)))) (with-temp-buffer (insert-file-contents ini-file) (while (re-search-forward "\\[customtableprofile[0-9]+\\]" nil t) (when (match-string 0) (let ((section (match-string 0)) (profiles '()) (start (point)) ; save the beginning of the section (end (if (re-search-forward "\\[customtableprofile[0-9]+\\]" nil t) (point) ; don't search profilename beyond the next section! (point-max)))) (goto-char start) (while (re-search-forward "profilename=.*" end t) (when (match-string 0) (push (match-string 0) profiles))) (setf (gethash section dictionary) profiles))))) ;; Are you sure you want to accumulate dictionaries in the output ;; file? ;; Here, I'm just replacing the whole contents with a single list: (find-file dictionary-file) (erase-buffer) (insert ";; -*- mode:lisp; coding: utf-8 -*-\n") (insert (format ";; Data extracted from %s\n\n" ini-file)) (insert (prin1-to-string (hash-to-list dictionary))) (save-buffer) (kill-buffer))) (extract-ini-settings "c:\\share\\reports_default.ini" "c:\\share\\reports_headers.txt") (extract-ini-settings "/tmp/a.ini" "/tmp/a.txt") (insert-file-contents "/tmp/a.txt") ;; -*- mode:lisp; coding: utf-8 -*- ;; Data extracted from /tmp/a.ini (("[customtableprofile1]" ("profilename=tutu\"" "profilename=tata")) ("[customtableprofile0]" ("profilename=titi\"" "profilename=toto"))) > Any help in correcting my errors would be greatly appreciated. Finally, as you can see with my test file, using regular expressions is a big source of errors. Well, if your ini file don't contain such "pathological" cases, they could work, but in general, it would be better to write a parser. -- __Pascal Bourguignon__ http://www.informatimago.com