Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(13)

Side by Side Diff: translate/storage/cpo.py

Issue 81: Fix CPO memory leak SVN Base: https://translate.svn.sourceforge.net/svnroot/translate/src/trunk/
Patch Set: Using low leve accessors Created 1 year, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*- 2 # -*- coding: utf-8 -*-
3 # 3 #
4 # Copyright 2002-2007 Zuza Software Foundation 4 # Copyright 2002-2007 Zuza Software Foundation
5 # 5 #
6 # This file is part of translate. 6 # This file is part of translate.
7 # 7 #
8 # translate is free software; you can redistribute it and/or modify 8 # translate is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by 9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or 10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version. 11 # (at your option) any later version.
12 # 12 #
13 # translate is distributed in the hope that it will be useful, 13 # translate is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details. 16 # GNU General Public License for more details.
17 # 17 #
18 # You should have received a copy of the GNU General Public License 18 # You should have received a copy of the GNU General Public License
19 # along with translate; if not, write to the Free Software 19 # along with translate; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 21
22 """Classes that hold units of .po files (pounit) or entire files (pofile). 22 """Classes that hold units of .po files (pounit) or entire files (pofile).
23 23
24 Gettext-style .po (or .pot) files are used in translations for KDE, GNOME and 24 Gettext-style .po (or .pot) files are used in translations for KDE, GNOME and
25 many other projects. 25 many other projects.
26 26
27 This uses libgettextpo from the gettext package. Any version before 0.17 will 27 This uses libgettextpo from the gettext package. Any version before 0.17 will
28 at least cause some subtle bugs or may not work at all. Developers might want 28 at least cause some subtle bugs or may not work at all. Developers might want
29 to have a look at gettext-tools/libgettextpo/gettext-po.h from the gettext 29 to have a look at gettext-tools/libgettextpo/gettext-po.h from the gettext
30 package for the public API of the library. 30 package for the public API of the library.
31 """ 31 """
32 32
33 from translate.misc.multistring import multistring 33 from translate.misc.multistring import multistring
34 from translate.storage import pocommon 34 from translate.storage import pocommon
35 from translate.misc import quote 35 from translate.misc import quote
36 from translate.lang import data 36 from translate.lang import data
37 from ctypes import * 37 from ctypes import *
38 import ctypes.util 38 import ctypes.util
39 try: 39 try:
40 import cStringIO as StringIO 40 import cStringIO as StringIO
41 except ImportError: 41 except ImportError:
42 import StringIO 42 import StringIO
43 import os 43 import os
44 import pypo 44 import pypo
45 import re 45 import re
46 import sys 46 import sys
47 import tempfile 47 import tempfile
48 48
49 lsep = " " 49 lsep = " "
50 """Seperator for #: entries""" 50 """Seperator for #: entries"""
(...skipping 273 matching lines...) Show 10 above Show 10 below
324 else: 324 else:
325 raise ValueError("Comment type not valid") 325 raise ValueError("Comment type not valid")
326 326
327 if comments and get_libgettextpo_version() < (0, 17, 0): 327 if comments and get_libgettextpo_version() < (0, 17, 0):
328 comments = "\n".join([line.strip() for line in comments.split("\n")] ) 328 comments = "\n".join([line.strip() for line in comments.split("\n")] )
329 # Let's drop the last newline 329 # Let's drop the last newline
330 return comments[:-1].decode(self._encoding) 330 return comments[:-1].decode(self._encoding)
331 331
332 def addnote(self, text, origin=None, position="append"): 332 def addnote(self, text, origin=None, position="append"):
333 # ignore empty strings and strings without non-space characters 333 # ignore empty strings and strings without non-space characters
334 if (not text) or (not text.strip()): 334 if (not text) or (not text.strip()):
335 return 335 return
336 text = data.forceunicode(text) 336 text = data.forceunicode(text)
337 oldnotes = self.getnotes(origin) 337 oldnotes = self.getnotes(origin)
338 newnotes = None 338 newnotes = None
339 if oldnotes: 339 if oldnotes:
340 if position == "append": 340 if position == "append":
341 newnotes = oldnotes + "\n" + text 341 newnotes = oldnotes + "\n" + text
342 elif position == "merge": 342 elif position == "merge":
343 if oldnotes != text: 343 if oldnotes != text:
344 oldnoteslist = oldnotes.split("\n") 344 oldnoteslist = oldnotes.split("\n")
345 for newline in text.split("\n"): 345 for newline in text.split("\n"):
346 newline = newline.rstrip() 346 newline = newline.rstrip()
347 # avoid duplicate comment lines (this might cause some p roblems) 347 # avoid duplicate comment lines (this might cause some p roblems)
348 if newline not in oldnotes or len(newline) < 5: 348 if newline not in oldnotes or len(newline) < 5:
349 oldnoteslist.append(newline) 349 oldnoteslist.append(newline)
350 newnotes = "\n".join(oldnoteslist) 350 newnotes = "\n".join(oldnoteslist)
351 else: 351 else:
352 newnotes = text + '\n' + oldnotes 352 newnotes = text + '\n' + oldnotes
353 else: 353 else:
354 newnotes = "\n".join([line.rstrip() for line in text.split("\n")]) 354 newnotes = "\n".join([line.rstrip() for line in text.split("\n")])
355 355
356 if newnotes: 356 if newnotes:
357 newlines = [] 357 newlines = []
358 needs_space = get_libgettextpo_version() < (0, 17, 0) 358 needs_space = get_libgettextpo_version() < (0, 17, 0)
359 for line in newnotes.split("\n"): 359 for line in newnotes.split("\n"):
360 if line and needs_space: 360 if line and needs_space:
361 newlines.append(" " + line) 361 newlines.append(" " + line)
362 else: 362 else:
363 newlines.append(line) 363 newlines.append(line)
364 newnotes = "\n".join(newlines) 364 newnotes = "\n".join(newlines)
365 if origin in ["programmer", "developer", "source code"]: 365 if origin in ["programmer", "developer", "source code"]:
366 gpo.po_message_set_extracted_comments(self._gpo_message, newnote s) 366 gpo.po_message_set_extracted_comments(self._gpo_message, newnote s)
367 else: 367 else:
368 gpo.po_message_set_comments(self._gpo_message, newnotes) 368 gpo.po_message_set_comments(self._gpo_message, newnotes)
369 369
370 def removenotes(self): 370 def removenotes(self):
371 gpo.po_message_set_comments(self._gpo_message, "") 371 gpo.po_message_set_comments(self._gpo_message, "")
372 372
373 def copy(self): 373 def copy(self):
374 newpo = self.__class__() 374 """Returns a copy of the this unit that can be used independently.
375 newpo._gpo_message = self._gpo_message 375 """
376 return newpo 376 unit = pounit()
377 unit.source = self.source
378 unit.target = self.target
379 unit.markfuzzy(self.isfuzzy())
380 if self.isobsolete():
381 unit.makeobsolete()
382 for location in self.getlocations():
383 unit.addlocation(location)
384 notes = []
385 origins = ['translator', 'developer', 'programmer', 'source code']
386 for origin in origins:
387 note = self.getnotes(origin=origin)
388 if note in notes:
389 continue
390 if note:
391 unit.addnote(note, origin=origin)
392 notes.append(note)
393 context = gpo.po_message_msgctxt(self._gpo_message)
394 if context:
395 unit.setcontext(context)
396 comments = self._extract_msgidcomments()
397 if comments:
398 unit.setmsgidcomment(comments)
399 return unit
377 400
378 def merge(self, otherpo, overwrite=False, comments=True, authoritative=False ): 401 def merge(self, otherpo, overwrite=False, comments=True, authoritative=False ):
379 """Merges the otherpo (with the same msgid) into this one. 402 """Merges the otherpo (with the same msgid) into this one.
380 403
381 Overwrite non-blank self.msgstr only if overwrite is True 404 Overwrite non-blank self.msgstr only if overwrite is True
382 merge comments only if comments is True 405 merge comments only if comments is True
383 406
384 """ 407 """
385 408
386 if not isinstance(otherpo, pounit): 409 if not isinstance(otherpo, pounit):
387 super(pounit, self).merge(otherpo, overwrite, comments) 410 super(pounit, self).merge(otherpo, overwrite, comments)
388 return 411 return
389 if comments: 412 if comments:
390 self.addnote(otherpo.getnotes("translator"), origin="translator", po sition="merge") 413 self.addnote(otherpo.getnotes("translator"), origin="translator", po sition="merge")
391 # FIXME mergelists(self.typecomments, otherpo.typecomments) 414 # FIXME mergelists(self.typecomments, otherpo.typecomments)
392 if not authoritative: 415 if not authoritative:
393 # We don't bring across otherpo.automaticcomments as we consider ourself 416 # We don't bring across otherpo.automaticcomments as we consider ourself
394 # to be the the authority. Same applies to otherpo.msgidcomment s 417 # to be the the authority. Same applies to otherpo.msgidcomment s
395 self.addnote(otherpo.getnotes("developer"), origin="developer", position="merge") 418 self.addnote(otherpo.getnotes("developer"), origin="developer", position="merge")
396 self.msgidcomment = otherpo._extract_msgidcomments() or None 419 self.msgidcomment = otherpo._extract_msgidcomments() or None
397 self.addlocations(otherpo.getlocations()) 420 self.addlocations(otherpo.getlocations())
398 if not self.istranslated() or overwrite: 421 if not self.istranslated() or overwrite:
399 # Remove kde-style comments from the translation (if any). 422 # Remove kde-style comments from the translation (if any).
400 if self._extract_msgidcomments(otherpo.target): 423 if self._extract_msgidcomments(otherpo.target):
401 otherpo.target = otherpo.target.replace('_: ' + otherpo._extract _msgidcomments()+ '\n', '') 424 otherpo.target = otherpo.target.replace('_: ' + otherpo._extract _msgidcomments()+ '\n', '')
402 self.target = otherpo.target 425 self.target = otherpo.target
403 if self.source != otherpo.source: 426 if self.source != otherpo.source:
404 self.markfuzzy() 427 self.markfuzzy()
405 else: 428 else:
406 self.markfuzzy(otherpo.isfuzzy()) 429 self.markfuzzy(otherpo.isfuzzy())
407 elif not otherpo.istranslated(): 430 elif not otherpo.istranslated():
408 if self.source != otherpo.source: 431 if self.source != otherpo.source:
409 self.markfuzzy() 432 self.markfuzzy()
410 else: 433 else:
411 if self.target != otherpo.target: 434 if self.target != otherpo.target:
412 self.markfuzzy() 435 self.markfuzzy()
413 436
414 def isheader(self): 437 def isheader(self):
415 #return self.source == u"" and self.target != u"" 438 #return self.source == u"" and self.target != u""
416 # we really want to make sure that there is no msgidcomment or msgctxt 439 # we really want to make sure that there is no msgidcomment or msgctxt
417 return self.getid() == "" and len(self.target) > 0 440 return self.getid() == "" and len(self.target) > 0
418 441
419 def isblank(self): 442 def isblank(self):
420 return len(self.source) == 0 and len(self.target) == 0 443 return len(self.source) == 0 and len(self.target) == 0
421 444
422 def hastypecomment(self, typecomment): 445 def hastypecomment(self, typecomment):
423 return gpo.po_message_is_format(self._gpo_message, typecomment) 446 return gpo.po_message_is_format(self._gpo_message, typecomment)
424 447
425 def hasmarkedcomment(self, commentmarker): 448 def hasmarkedcomment(self, commentmarker):
426 commentmarker = "(%s)" % commentmarker 449 commentmarker = "(%s)" % commentmarker
427 for comment in self.getnotes("translator").split("\n"): 450 for comment in self.getnotes("translator").split("\n"):
428 if comment.startswith(commentmarker): 451 if comment.startswith(commentmarker):
429 return True 452 return True
430 return False 453 return False
431 454
432 def istranslated(self): 455 def istranslated(self):
433 return super(pounit, self).istranslated() and not self.isobsolete() 456 return super(pounit, self).istranslated() and not self.isobsolete()
434 457
435 def istranslatable(self): 458 def istranslatable(self):
436 return not (self.isheader() or self.isblank() or self.isobsolete()) 459 return not (self.isheader() or self.isblank() or self.isobsolete())
437 460
438 def isfuzzy(self): 461 def isfuzzy(self):
439 return gpo.po_message_is_fuzzy(self._gpo_message) 462 return gpo.po_message_is_fuzzy(self._gpo_message)
440 463
441 def markfuzzy(self, present=True): 464 def markfuzzy(self, present=True):
442 gpo.po_message_set_fuzzy(self._gpo_message, present) 465 gpo.po_message_set_fuzzy(self._gpo_message, present)
443 466
444 def isreview(self): 467 def isreview(self):
445 return self.hasmarkedcomment("review") or self.hasmarkedcomment("pofilte r") 468 return self.hasmarkedcomment("review") or self.hasmarkedcomment("pofilte r")
446 469
447 def isobsolete(self): 470 def isobsolete(self):
448 return gpo.po_message_is_obsolete(self._gpo_message) 471 return gpo.po_message_is_obsolete(self._gpo_message)
449 472
450 def makeobsolete(self): 473 def makeobsolete(self):
451 # FIXME: libgettexpo currently does not reset other data, we probably wa nt to do that 474 # FIXME: libgettexpo currently does not reset other data, we probably wa nt to do that
452 # but a better solution would be for libgettextpo to output correct data on serialisation 475 # but a better solution would be for libgettextpo to output correct data on serialisation
453 gpo.po_message_set_obsolete(self._gpo_message, True) 476 gpo.po_message_set_obsolete(self._gpo_message, True)
454 477
455 def resurrect(self): 478 def resurrect(self):
456 gpo.po_message_set_obsolete(self._gpo_message, False) 479 gpo.po_message_set_obsolete(self._gpo_message, False)
457 480
458 def hasplural(self): 481 def hasplural(self):
459 return gpo.po_message_msgid_plural(self._gpo_message) is not None 482 return gpo.po_message_msgid_plural(self._gpo_message) is not None
460 483
461 def _extract_msgidcomments(self, text=None): 484 def _extract_msgidcomments(self, text=None):
462 """Extract KDE style msgid comments from the unit. 485 """Extract KDE style msgid comments from the unit.
463 486
464 @rtype: String 487 @rtype: String
465 @return: Returns the extracted msgidcomments found in this unit's msgid. 488 @return: Returns the extracted msgidcomments found in this unit's msgid.
466 489
467 """ 490 """
468 491
469 if not text: 492 if not text:
470 text = gpo.po_message_msgid(self._gpo_message) 493 text = gpo.po_message_msgid(self._gpo_message)
471 if text: 494 if text:
472 msgidcomment = re.search("_: (.*)\n", text) 495 msgidcomment = re.search("_: (.*)\n", text)
473 if msgidcomment: 496 if msgidcomment:
474 return msgidcomment.group(1).decode(self._encoding) 497 return msgidcomment.group(1).decode(self._encoding)
475 return u"" 498 return u""
476 499
477 def __str__(self): 500 def __str__(self):
478 pf = pofile() 501 pf = pofile()
479 pf.addunit(self) 502 unit = self.copy()
503 pf.addunit(unit)
480 return str(pf) 504 return str(pf)
481 505
482 def getlocations(self): 506 def getlocations(self):
483 locations = [] 507 locations = []
484 i = 0 508 i = 0
485 location = gpo.po_message_filepos(self._gpo_message, i) 509 location = gpo.po_message_filepos(self._gpo_message, i)
486 while location: 510 while location:
487 locname = gpo.po_filepos_file(location) 511 locname = gpo.po_filepos_file(location)
488 locline = gpo.po_filepos_start_line(location) 512 locline = gpo.po_filepos_start_line(location)
489 if locline == -1: 513 if locline == -1:
490 locstring = locname 514 locstring = locname
491 else: 515 else:
492 locstring = locname + ":" + str(locline) 516 locstring = locname + ":" + str(locline)
493 locations.append(locstring) 517 locations.append(locstring)
494 i += 1 518 i += 1
495 location = gpo.po_message_filepos(self._gpo_message, i) 519 location = gpo.po_message_filepos(self._gpo_message, i)
496 return locations 520 return locations
497 521
498 def addlocation(self, location): 522 def addlocation(self, location):
499 for loc in location.split(): 523 for loc in location.split():
500 parts = loc.split(":") 524 parts = loc.split(":")
501 file = parts[0] 525 file = parts[0]
502 if len(parts) == 2: 526 if len(parts) == 2:
503 line = int(parts[1]) 527 line = int(parts[1])
504 else: 528 else:
505 line = -1 529 line = -1
506 gpo.po_message_add_filepos(self._gpo_message, file, line) 530 gpo.po_message_add_filepos(self._gpo_message, file, line)
531
532 def setcontext(self, context):
533 """Sets the context message"""
534 #FIXME: not complete
535 gpo.po_message_set_msgctxt(self._gpo_message, context)
507 536
508 def getcontext(self): 537 def getcontext(self):
509 msgctxt = gpo.po_message_msgctxt(self._gpo_message) 538 msgctxt = gpo.po_message_msgctxt(self._gpo_message)
510 msgidcomment = self._extract_msgidcomments() 539 msgidcomment = self._extract_msgidcomments()
511 if msgctxt: 540 if msgctxt:
512 return msgctxt + msgidcomment 541 return msgctxt + msgidcomment
513 else: 542 else:
514 return msgidcomment 543 return msgidcomment
515 544
516 class pofile(pocommon.pofile): 545 class pofile(pocommon.pofile):
517 UnitClass = pounit 546 UnitClass = pounit
518 def __init__(self, inputfile=None, encoding=None, unitclass=pounit): 547 def __init__(self, inputfile=None, encoding=None, unitclass=pounit):
519 self.UnitClass = unitclass 548 self.UnitClass = unitclass
520 pocommon.pofile.__init__(self, unitclass=unitclass) 549 pocommon.pofile.__init__(self, unitclass=unitclass)
521 self._gpo_memory_file = None 550 self._gpo_memory_file = None
522 self._gpo_message_iterator = None 551 self._gpo_message_iterator = None
523 self._encoding = encodingToUse(encoding) 552 self._encoding = encodingToUse(encoding)
524 if inputfile is not None: 553 if inputfile is not None:
525 self.parse(inputfile) 554 self.parse(inputfile)
526 else: 555 else:
527 self._gpo_memory_file = gpo.po_file_create() 556 self._gpo_memory_file = gpo.po_file_create()
528 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memor y_file, None) 557 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memor y_file, None)
529 558
530 def addunit(self, unit): 559 def addunit(self, unit):
531 gpo.po_message_insert(self._gpo_message_iterator, unit._gpo_message) 560 unitcopy = unit.copy()
532 self.units.append(unit) 561 gpo.po_message_insert(self._gpo_message_iterator, unitcopy._gpo_message)
562 self.units.append(unitcopy)
533 563
534 def removeduplicates(self, duplicatestyle="merge"): 564 def removeduplicates(self, duplicatestyle="merge"):
535 """make sure each msgid is unique ; merge comments etc from duplicates i nto original""" 565 """make sure each msgid is unique ; merge comments etc from duplicates i nto original"""
536 msgiddict = {} 566 msgiddict = {}
537 uniqueunits = [] 567 uniqueunits = []
538 # we sometimes need to keep track of what has been marked 568 # we sometimes need to keep track of what has been marked
539 # TODO: this is using a list as the pos aren't hashable, but this is slo w... 569 # TODO: this is using a list as the pos aren't hashable, but this is slo w...
540 markedpos = [] 570 markedpos = []
541 def addcomment(thepo): 571 def addcomment(thepo):
542 thepo.msgidcomment = " ".join(thepo.getlocations()) 572 thepo.msgidcomment = " ".join(thepo.getlocations())
543 markedpos.append(thepo) 573 markedpos.append(thepo)
544 for thepo in self.units: 574 for thepo in self.units:
545 if thepo.isheader(): 575 if thepo.isheader():
546 uniqueunits.append(thepo) 576 uniqueunits.append(thepo)
547 continue 577 continue
548 if duplicatestyle.startswith("msgid_comment"): 578 if duplicatestyle.startswith("msgid_comment"):
549 msgid = thepo._extract_msgidcomments() + thepo.source 579 msgid = thepo._extract_msgidcomments() + thepo.source
550 else: 580 else:
551 msgid = thepo.source 581 msgid = thepo.source
552 if duplicatestyle == "msgid_comment_all": 582 if duplicatestyle == "msgid_comment_all":
553 addcomment(thepo) 583 addcomment(thepo)
554 uniqueunits.append(thepo) 584 uniqueunits.append(thepo)
555 elif msgid in msgiddict: 585 elif msgid in msgiddict:
556 if duplicatestyle == "merge": 586 if duplicatestyle == "merge":
557 if msgid: 587 if msgid:
558 msgiddict[msgid].merge(thepo) 588 msgiddict[msgid].merge(thepo)
559 else: 589 else:
560 addcomment(thepo) 590 addcomment(thepo)
561 uniqueunits.append(thepo) 591 uniqueunits.append(thepo)
562 elif duplicatestyle == "keep": 592 elif duplicatestyle == "keep":
563 uniqueunits.append(thepo) 593 uniqueunits.append(thepo)
564 elif duplicatestyle == "msgid_comment": 594 elif duplicatestyle == "msgid_comment":
565 origpo = msgiddict[msgid] 595 origpo = msgiddict[msgid]
566 if origpo not in markedpos: 596 if origpo not in markedpos:
567 addcomment(origpo) 597 addcomment(origpo)
568 addcomment(thepo) 598 addcomment(thepo)
569 uniqueunits.append(thepo) 599 uniqueunits.append(thepo)
570 elif duplicatestyle == "msgctxt": 600 elif duplicatestyle == "msgctxt":
571 origpo = msgiddict[msgid] 601 origpo = msgiddict[msgid]
572 if origpo not in markedpos: 602 if origpo not in markedpos:
573 gpo.po_message_set_msgctxt(origpo._gpo_message, " ".join (origpo.getlocations())) 603 gpo.po_message_set_msgctxt(origpo._gpo_message, " ".join (origpo.getlocations()))
574 markedpos.append(thepo) 604 markedpos.append(thepo)
575 gpo.po_message_set_msgctxt(thepo._gpo_message, " ".join(thep o.getlocations())) 605 gpo.po_message_set_msgctxt(thepo._gpo_message, " ".join(thep o.getlocations()))
576 uniqueunits.append(thepo) 606 uniqueunits.append(thepo)
577 else: 607 else:
578 if not msgid and duplicatestyle != "keep": 608 if not msgid and duplicatestyle != "keep":
579 addcomment(thepo) 609 addcomment(thepo)
580 msgiddict[msgid] = thepo 610 msgiddict[msgid] = thepo
581 uniqueunits.append(thepo) 611 uniqueunits.append(thepo)
582 new_gpo_memory_file = gpo.po_file_create() 612 new_gpo_memory_file = gpo.po_file_create()
583 new_gpo_message_iterator = gpo.po_message_iterator(new_gpo_memory_file, None) 613 new_gpo_message_iterator = gpo.po_message_iterator(new_gpo_memory_file, None)
584 for unit in uniqueunits: 614 for unit in uniqueunits:
585 gpo.po_message_insert(new_gpo_message_iterator, unit._gpo_message) 615 gpo.po_message_insert(new_gpo_message_iterator, unit._gpo_message)
586 gpo.po_message_iterator_free(self._gpo_message_iterator) 616 gpo.po_message_iterator_free(self._gpo_message_iterator)
587 self._gpo_message_iterator = new_gpo_message_iterator 617 self._gpo_message_iterator = new_gpo_message_iterator
588 self._gpo_memory_file = new_gpo_memory_file 618 self._gpo_memory_file = new_gpo_memory_file
589 self.units = uniqueunits 619 self.units = uniqueunits
590 620
591 def __str__(self): 621 def __str__(self):
592 def obsolete_workaround(): 622 def obsolete_workaround():
593 # Remove all items that are not output by msgmerge when a unit is ob solete. This is a work 623 # Remove all items that are not output by msgmerge when a unit is ob solete. This is a work
594 # around for bug in libgettextpo 624 # around for bug in libgettextpo
595 # FIXME Do version test in case they fix this bug 625 # FIXME Do version test in case they fix this bug
596 for unit in self.units: 626 for unit in self.units:
597 if unit.isobsolete(): 627 if unit.isobsolete():
598 gpo.po_message_set_extracted_comments(unit._gpo_message, "") 628 gpo.po_message_set_extracted_comments(unit._gpo_message, "")
599 location = gpo.po_message_filepos(unit._gpo_message, 0) 629 location = gpo.po_message_filepos(unit._gpo_message, 0)
600 while location: 630 while location:
601 gpo.po_message_remove_filepos(unit._gpo_message, 0) 631 gpo.po_message_remove_filepos(unit._gpo_message, 0)
602 location = gpo.po_message_filepos(unit._gpo_message, 0) 632 location = gpo.po_message_filepos(unit._gpo_message, 0)
603 outputstring = "" 633 outputstring = ""
604 if self._gpo_memory_file: 634 if self._gpo_memory_file:
605 obsolete_workaround() 635 obsolete_workaround()
606 f = tempfile.NamedTemporaryFile(prefix='translate', suffix='.po') 636 f = tempfile.NamedTemporaryFile(prefix='translate', suffix='.po')
607 self._gpo_memory_file = gpo.po_file_write_v2(self._gpo_memory_file, f.name, xerror_handler) 637 self._gpo_memory_file = gpo.po_file_write_v2(self._gpo_memory_file, f.name, xerror_handler)
608 f.seek(0) 638 f.seek(0)
609 outputstring = f.read() 639 outputstring = f.read()
610 f.close() 640 f.close()
611 return outputstring 641 return outputstring
612 642
613 def isempty(self): 643 def isempty(self):
614 """Returns True if the object doesn't contain any translation units.""" 644 """Returns True if the object doesn't contain any translation units."""
615 if len(self.units) == 0: 645 if len(self.units) == 0:
616 return True 646 return True
617 # Skip the first unit if it is a header. 647 # Skip the first unit if it is a header.
618 if self.units[0].isheader(): 648 if self.units[0].isheader():
619 units = self.units[1:] 649 units = self.units[1:]
620 else: 650 else:
621 units = self.units 651 units = self.units
622 652
623 for unit in units: 653 for unit in units:
624 if not unit.isblank() and not unit.isobsolete(): 654 if not unit.isblank() and not unit.isobsolete():
625 return False 655 return False
626 return True 656 return True
627 657
628 def parse(self, input): 658 def parse(self, input):
629 if hasattr(input, 'name'): 659 if hasattr(input, 'name'):
630 self.filename = input.name 660 self.filename = input.name
631 elif not getattr(self, 'filename', ''): 661 elif not getattr(self, 'filename', ''):
632 self.filename = '' 662 self.filename = ''
633 663
634 if hasattr(input, "read"): 664 if hasattr(input, "read"):
635 posrc = input.read() 665 posrc = input.read()
636 input.close() 666 input.close()
637 input = posrc 667 input = posrc
638 668
639 needtmpfile = not os.path.isfile(input) 669 needtmpfile = not os.path.isfile(input)
640 if needtmpfile: 670 if needtmpfile:
641 # This is not a file - we write the string to a temporary file 671 # This is not a file - we write the string to a temporary file
642 fd, fname = tempfile.mkstemp(prefix='translate', suffix='.po') 672 fd, fname = tempfile.mkstemp(prefix='translate', suffix='.po')
643 os.write(fd, input) 673 os.write(fd, input)
644 input = fname 674 input = fname
645 os.close(fd) 675 os.close(fd)
646 676
647 self._gpo_memory_file = gpo.po_file_read_v3(input, xerror_handler) 677 self._gpo_memory_file = gpo.po_file_read_v3(input, xerror_handler)
648 if self._gpo_memory_file is None: 678 if self._gpo_memory_file is None:
649 print >> sys.stderr, "Error:" 679 print >> sys.stderr, "Error:"
650 680
651 if needtmpfile: 681 if needtmpfile:
652 os.remove(input) 682 os.remove(input)
653 683
654 # Handle xerrors here 684 # Handle xerrors here
655 self._header = gpo.po_file_domain_header(self._gpo_memory_file, None) 685 self._header = gpo.po_file_domain_header(self._gpo_memory_file, None)
656 if self._header: 686 if self._header:
657 charset = gpo.po_header_field(self._header, "Content-Type") 687 charset = gpo.po_header_field(self._header, "Content-Type")
658 if charset: 688 if charset:
659 charset = re.search("charset=([^\\s]+)", charset).group(1) 689 charset = re.search("charset=([^\\s]+)", charset).group(1)
660 self._encoding = encodingToUse(charset) 690 self._encoding = encodingToUse(charset)
661 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memory_fi le, None) 691 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memory_fi le, None)
662 newmessage = gpo.po_next_message(self._gpo_message_iterator) 692 newmessage = gpo.po_next_message(self._gpo_message_iterator)
663 while newmessage: 693 while newmessage:
664 newunit = pounit(gpo_message=newmessage) 694 newunit = pounit(gpo_message=newmessage)
665 self.units.append(newunit) 695 self.units.append(newunit)
666 newmessage = gpo.po_next_message(self._gpo_message_iterator) 696 newmessage = gpo.po_next_message(self._gpo_message_iterator)
667 self._free_iterator()
668 697
669 def __del__(self): 698 def __del__(self):
670 # We currently disable this while we still get segmentation faults. 699 # We currently disable this while we still get segmentation faults.
671 # Note that this is definitely leaking memory because of this. 700 # Note that this is definitely leaking memory because of this.
672 return
673 self._free_iterator() 701 self._free_iterator()
674 if self._gpo_memory_file is not None: 702 if self._gpo_memory_file is not None:
675 gpo.po_file_free(self._gpo_memory_file) 703 gpo.po_file_free(self._gpo_memory_file)
676 self._gpo_memory_file = None 704 self._gpo_memory_file = None
677 705
678 def _free_iterator(self): 706 def _free_iterator(self):
679 # We currently disable this while we still get segmentation faults. 707 # We currently disable this while we still get segmentation faults.
680 # Note that this is definitely leaking memory because of this. 708 # Note that this is definitely leaking memory because of this.
681 return
682 if self._gpo_message_iterator is not None: 709 if self._gpo_message_iterator is not None:
683 gpo.po_message_iterator_free(self._gpo_message_iterator) 710 gpo.po_message_iterator_free(self._gpo_message_iterator)
684 self._gpo_message_iterator = None 711 self._gpo_message_iterator = None
OLDNEW

Powered by Google App Engine
This is Rietveld r159