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

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: 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 unit = self.buildfromunit(self)
375 newpo._gpo_message = self._gpo_message 375 #XXX: adding missing data
376 return newpo 376 if self.isobsolete():
377 unit.makeobsolete()
378 context = gpo.po_message_msgctxt(self._gpo_message)
379 if context:
380 unit.setcontext(context)
381 comments = self._extract_msgidcomments()
382 if comments:
383 print 'HAS COMMENTS', comments
384 unit.setmsgidcomment(comments)
385 return unit
377 386
378 def merge(self, otherpo, overwrite=False, comments=True, authoritative=False ): 387 def merge(self, otherpo, overwrite=False, comments=True, authoritative=False ):
379 """Merges the otherpo (with the same msgid) into this one. 388 """Merges the otherpo (with the same msgid) into this one.
380 389
381 Overwrite non-blank self.msgstr only if overwrite is True 390 Overwrite non-blank self.msgstr only if overwrite is True
382 merge comments only if comments is True 391 merge comments only if comments is True
383 392
384 """ 393 """
385 394
386 if not isinstance(otherpo, pounit): 395 if not isinstance(otherpo, pounit):
387 super(pounit, self).merge(otherpo, overwrite, comments) 396 super(pounit, self).merge(otherpo, overwrite, comments)
388 return 397 return
389 if comments: 398 if comments:
390 self.addnote(otherpo.getnotes("translator"), origin="translator", po sition="merge") 399 self.addnote(otherpo.getnotes("translator"), origin="translator", po sition="merge")
391 # FIXME mergelists(self.typecomments, otherpo.typecomments) 400 # FIXME mergelists(self.typecomments, otherpo.typecomments)
392 if not authoritative: 401 if not authoritative:
393 # We don't bring across otherpo.automaticcomments as we consider ourself 402 # We don't bring across otherpo.automaticcomments as we consider ourself
394 # to be the the authority. Same applies to otherpo.msgidcomment s 403 # to be the the authority. Same applies to otherpo.msgidcomment s
395 self.addnote(otherpo.getnotes("developer"), origin="developer", position="merge") 404 self.addnote(otherpo.getnotes("developer"), origin="developer", position="merge")
396 self.msgidcomment = otherpo._extract_msgidcomments() or None 405 self.msgidcomment = otherpo._extract_msgidcomments() or None
397 self.addlocations(otherpo.getlocations()) 406 self.addlocations(otherpo.getlocations())
398 if not self.istranslated() or overwrite: 407 if not self.istranslated() or overwrite:
399 # Remove kde-style comments from the translation (if any). 408 # Remove kde-style comments from the translation (if any).
400 if self._extract_msgidcomments(otherpo.target): 409 if self._extract_msgidcomments(otherpo.target):
401 otherpo.target = otherpo.target.replace('_: ' + otherpo._extract _msgidcomments()+ '\n', '') 410 otherpo.target = otherpo.target.replace('_: ' + otherpo._extract _msgidcomments()+ '\n', '')
402 self.target = otherpo.target 411 self.target = otherpo.target
403 if self.source != otherpo.source: 412 if self.source != otherpo.source:
404 self.markfuzzy() 413 self.markfuzzy()
405 else: 414 else:
406 self.markfuzzy(otherpo.isfuzzy()) 415 self.markfuzzy(otherpo.isfuzzy())
407 elif not otherpo.istranslated(): 416 elif not otherpo.istranslated():
408 if self.source != otherpo.source: 417 if self.source != otherpo.source:
409 self.markfuzzy() 418 self.markfuzzy()
410 else: 419 else:
411 if self.target != otherpo.target: 420 if self.target != otherpo.target:
412 self.markfuzzy() 421 self.markfuzzy()
413 422
414 def isheader(self): 423 def isheader(self):
415 #return self.source == u"" and self.target != u"" 424 #return self.source == u"" and self.target != u""
416 # we really want to make sure that there is no msgidcomment or msgctxt 425 # we really want to make sure that there is no msgidcomment or msgctxt
417 return self.getid() == "" and len(self.target) > 0 426 return self.getid() == "" and len(self.target) > 0
418 427
419 def isblank(self): 428 def isblank(self):
420 return len(self.source) == 0 and len(self.target) == 0 429 return len(self.source) == 0 and len(self.target) == 0
421 430
422 def hastypecomment(self, typecomment): 431 def hastypecomment(self, typecomment):
423 return gpo.po_message_is_format(self._gpo_message, typecomment) 432 return gpo.po_message_is_format(self._gpo_message, typecomment)
424 433
425 def hasmarkedcomment(self, commentmarker): 434 def hasmarkedcomment(self, commentmarker):
426 commentmarker = "(%s)" % commentmarker 435 commentmarker = "(%s)" % commentmarker
427 for comment in self.getnotes("translator").split("\n"): 436 for comment in self.getnotes("translator").split("\n"):
428 if comment.startswith(commentmarker): 437 if comment.startswith(commentmarker):
429 return True 438 return True
430 return False 439 return False
431 440
432 def istranslated(self): 441 def istranslated(self):
433 return super(pounit, self).istranslated() and not self.isobsolete() 442 return super(pounit, self).istranslated() and not self.isobsolete()
434 443
435 def istranslatable(self): 444 def istranslatable(self):
436 return not (self.isheader() or self.isblank() or self.isobsolete()) 445 return not (self.isheader() or self.isblank() or self.isobsolete())
437 446
438 def isfuzzy(self): 447 def isfuzzy(self):
439 return gpo.po_message_is_fuzzy(self._gpo_message) 448 return gpo.po_message_is_fuzzy(self._gpo_message)
440 449
441 def markfuzzy(self, present=True): 450 def markfuzzy(self, present=True):
442 gpo.po_message_set_fuzzy(self._gpo_message, present) 451 gpo.po_message_set_fuzzy(self._gpo_message, present)
443 452
444 def isreview(self): 453 def isreview(self):
445 return self.hasmarkedcomment("review") or self.hasmarkedcomment("pofilte r") 454 return self.hasmarkedcomment("review") or self.hasmarkedcomment("pofilte r")
446 455
447 def isobsolete(self): 456 def isobsolete(self):
448 return gpo.po_message_is_obsolete(self._gpo_message) 457 return gpo.po_message_is_obsolete(self._gpo_message)
449 458
450 def makeobsolete(self): 459 def makeobsolete(self):
451 # FIXME: libgettexpo currently does not reset other data, we probably wa nt to do that 460 # 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 461 # but a better solution would be for libgettextpo to output correct data on serialisation
453 gpo.po_message_set_obsolete(self._gpo_message, True) 462 gpo.po_message_set_obsolete(self._gpo_message, True)
454 463
455 def resurrect(self): 464 def resurrect(self):
456 gpo.po_message_set_obsolete(self._gpo_message, False) 465 gpo.po_message_set_obsolete(self._gpo_message, False)
457 466
458 def hasplural(self): 467 def hasplural(self):
459 return gpo.po_message_msgid_plural(self._gpo_message) is not None 468 return gpo.po_message_msgid_plural(self._gpo_message) is not None
460 469
461 def _extract_msgidcomments(self, text=None): 470 def _extract_msgidcomments(self, text=None):
462 """Extract KDE style msgid comments from the unit. 471 """Extract KDE style msgid comments from the unit.
463 472
464 @rtype: String 473 @rtype: String
465 @return: Returns the extracted msgidcomments found in this unit's msgid. 474 @return: Returns the extracted msgidcomments found in this unit's msgid.
466 475
467 """ 476 """
468 477
469 if not text: 478 if not text:
470 text = gpo.po_message_msgid(self._gpo_message) 479 text = gpo.po_message_msgid(self._gpo_message)
471 if text: 480 if text:
472 msgidcomment = re.search("_: (.*)\n", text) 481 msgidcomment = re.search("_: (.*)\n", text)
473 if msgidcomment: 482 if msgidcomment:
474 return msgidcomment.group(1).decode(self._encoding) 483 return msgidcomment.group(1).decode(self._encoding)
475 return u"" 484 return u""
476 485
477 def __str__(self): 486 def __str__(self):
478 pf = pofile() 487 pf = pofile()
479 pf.addunit(self) 488 unit = self.copy()
489 pf.addunit(unit)
480 return str(pf) 490 return str(pf)
481 491
482 def getlocations(self): 492 def getlocations(self):
483 locations = [] 493 locations = []
484 i = 0 494 i = 0
485 location = gpo.po_message_filepos(self._gpo_message, i) 495 location = gpo.po_message_filepos(self._gpo_message, i)
486 while location: 496 while location:
487 locname = gpo.po_filepos_file(location) 497 locname = gpo.po_filepos_file(location)
488 locline = gpo.po_filepos_start_line(location) 498 locline = gpo.po_filepos_start_line(location)
489 if locline == -1: 499 if locline == -1:
490 locstring = locname 500 locstring = locname
491 else: 501 else:
492 locstring = locname + ":" + str(locline) 502 locstring = locname + ":" + str(locline)
493 locations.append(locstring) 503 locations.append(locstring)
494 i += 1 504 i += 1
495 location = gpo.po_message_filepos(self._gpo_message, i) 505 location = gpo.po_message_filepos(self._gpo_message, i)
496 return locations 506 return locations
497 507
498 def addlocation(self, location): 508 def addlocation(self, location):
499 for loc in location.split(): 509 for loc in location.split():
500 parts = loc.split(":") 510 parts = loc.split(":")
501 file = parts[0] 511 file = parts[0]
502 if len(parts) == 2: 512 if len(parts) == 2:
503 line = int(parts[1]) 513 line = int(parts[1])
504 else: 514 else:
505 line = -1 515 line = -1
506 gpo.po_message_add_filepos(self._gpo_message, file, line) 516 gpo.po_message_add_filepos(self._gpo_message, file, line)
517
518 def setcontext(self, context):
519 """Sets the context message"""
520 #FIXME: not complete
521 gpo.po_message_set_msgctxt(self._gpo_message, context)
507 522
508 def getcontext(self): 523 def getcontext(self):
509 msgctxt = gpo.po_message_msgctxt(self._gpo_message) 524 msgctxt = gpo.po_message_msgctxt(self._gpo_message)
510 msgidcomment = self._extract_msgidcomments() 525 msgidcomment = self._extract_msgidcomments()
511 if msgctxt: 526 if msgctxt:
512 return msgctxt + msgidcomment 527 return msgctxt + msgidcomment
513 else: 528 else:
514 return msgidcomment 529 return msgidcomment
515 530
516 class pofile(pocommon.pofile): 531 class pofile(pocommon.pofile):
517 UnitClass = pounit 532 UnitClass = pounit
518 def __init__(self, inputfile=None, encoding=None, unitclass=pounit): 533 def __init__(self, inputfile=None, encoding=None, unitclass=pounit):
519 self.UnitClass = unitclass 534 self.UnitClass = unitclass
520 pocommon.pofile.__init__(self, unitclass=unitclass) 535 pocommon.pofile.__init__(self, unitclass=unitclass)
521 self._gpo_memory_file = None 536 self._gpo_memory_file = None
522 self._gpo_message_iterator = None 537 self._gpo_message_iterator = None
523 self._encoding = encodingToUse(encoding) 538 self._encoding = encodingToUse(encoding)
524 if inputfile is not None: 539 if inputfile is not None:
525 self.parse(inputfile) 540 self.parse(inputfile)
526 else: 541 else:
527 self._gpo_memory_file = gpo.po_file_create() 542 self._gpo_memory_file = gpo.po_file_create()
528 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memor y_file, None) 543 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memor y_file, None)
529 544
530 def addunit(self, unit): 545 def addunit(self, unit):
531 gpo.po_message_insert(self._gpo_message_iterator, unit._gpo_message) 546 unitcopy = unit.copy()
532 self.units.append(unit) 547 gpo.po_message_insert(self._gpo_message_iterator, unitcopy._gpo_message)
548 self.units.append(unitcopy)
533 549
534 def removeduplicates(self, duplicatestyle="merge"): 550 def removeduplicates(self, duplicatestyle="merge"):
535 """make sure each msgid is unique ; merge comments etc from duplicates i nto original""" 551 """make sure each msgid is unique ; merge comments etc from duplicates i nto original"""
536 msgiddict = {} 552 msgiddict = {}
537 uniqueunits = [] 553 uniqueunits = []
538 # we sometimes need to keep track of what has been marked 554 # 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... 555 # TODO: this is using a list as the pos aren't hashable, but this is slo w...
540 markedpos = [] 556 markedpos = []
541 def addcomment(thepo): 557 def addcomment(thepo):
542 thepo.msgidcomment = " ".join(thepo.getlocations()) 558 thepo.msgidcomment = " ".join(thepo.getlocations())
543 markedpos.append(thepo) 559 markedpos.append(thepo)
544 for thepo in self.units: 560 for thepo in self.units:
545 if thepo.isheader(): 561 if thepo.isheader():
546 uniqueunits.append(thepo) 562 uniqueunits.append(thepo)
547 continue 563 continue
548 if duplicatestyle.startswith("msgid_comment"): 564 if duplicatestyle.startswith("msgid_comment"):
549 msgid = thepo._extract_msgidcomments() + thepo.source 565 msgid = thepo._extract_msgidcomments() + thepo.source
550 else: 566 else:
551 msgid = thepo.source 567 msgid = thepo.source
552 if duplicatestyle == "msgid_comment_all": 568 if duplicatestyle == "msgid_comment_all":
553 addcomment(thepo) 569 addcomment(thepo)
554 uniqueunits.append(thepo) 570 uniqueunits.append(thepo)
555 elif msgid in msgiddict: 571 elif msgid in msgiddict:
556 if duplicatestyle == "merge": 572 if duplicatestyle == "merge":
557 if msgid: 573 if msgid:
558 msgiddict[msgid].merge(thepo) 574 msgiddict[msgid].merge(thepo)
559 else: 575 else:
560 addcomment(thepo) 576 addcomment(thepo)
561 uniqueunits.append(thepo) 577 uniqueunits.append(thepo)
562 elif duplicatestyle == "keep": 578 elif duplicatestyle == "keep":
563 uniqueunits.append(thepo) 579 uniqueunits.append(thepo)
564 elif duplicatestyle == "msgid_comment": 580 elif duplicatestyle == "msgid_comment":
565 origpo = msgiddict[msgid] 581 origpo = msgiddict[msgid]
566 if origpo not in markedpos: 582 if origpo not in markedpos:
567 addcomment(origpo) 583 addcomment(origpo)
568 addcomment(thepo) 584 addcomment(thepo)
569 uniqueunits.append(thepo) 585 uniqueunits.append(thepo)
570 elif duplicatestyle == "msgctxt": 586 elif duplicatestyle == "msgctxt":
571 origpo = msgiddict[msgid] 587 origpo = msgiddict[msgid]
572 if origpo not in markedpos: 588 if origpo not in markedpos:
573 gpo.po_message_set_msgctxt(origpo._gpo_message, " ".join (origpo.getlocations())) 589 gpo.po_message_set_msgctxt(origpo._gpo_message, " ".join (origpo.getlocations()))
574 markedpos.append(thepo) 590 markedpos.append(thepo)
575 gpo.po_message_set_msgctxt(thepo._gpo_message, " ".join(thep o.getlocations())) 591 gpo.po_message_set_msgctxt(thepo._gpo_message, " ".join(thep o.getlocations()))
576 uniqueunits.append(thepo) 592 uniqueunits.append(thepo)
577 else: 593 else:
578 if not msgid and duplicatestyle != "keep": 594 if not msgid and duplicatestyle != "keep":
579 addcomment(thepo) 595 addcomment(thepo)
580 msgiddict[msgid] = thepo 596 msgiddict[msgid] = thepo
581 uniqueunits.append(thepo) 597 uniqueunits.append(thepo)
582 new_gpo_memory_file = gpo.po_file_create() 598 new_gpo_memory_file = gpo.po_file_create()
583 new_gpo_message_iterator = gpo.po_message_iterator(new_gpo_memory_file, None) 599 new_gpo_message_iterator = gpo.po_message_iterator(new_gpo_memory_file, None)
584 for unit in uniqueunits: 600 for unit in uniqueunits:
585 gpo.po_message_insert(new_gpo_message_iterator, unit._gpo_message) 601 gpo.po_message_insert(new_gpo_message_iterator, unit._gpo_message)
586 gpo.po_message_iterator_free(self._gpo_message_iterator) 602 gpo.po_message_iterator_free(self._gpo_message_iterator)
587 self._gpo_message_iterator = new_gpo_message_iterator 603 self._gpo_message_iterator = new_gpo_message_iterator
588 self._gpo_memory_file = new_gpo_memory_file 604 self._gpo_memory_file = new_gpo_memory_file
589 self.units = uniqueunits 605 self.units = uniqueunits
590 606
591 def __str__(self): 607 def __str__(self):
592 def obsolete_workaround(): 608 def obsolete_workaround():
593 # Remove all items that are not output by msgmerge when a unit is ob solete. This is a work 609 # 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 610 # around for bug in libgettextpo
595 # FIXME Do version test in case they fix this bug 611 # FIXME Do version test in case they fix this bug
596 for unit in self.units: 612 for unit in self.units:
597 if unit.isobsolete(): 613 if unit.isobsolete():
598 gpo.po_message_set_extracted_comments(unit._gpo_message, "") 614 gpo.po_message_set_extracted_comments(unit._gpo_message, "")
599 location = gpo.po_message_filepos(unit._gpo_message, 0) 615 location = gpo.po_message_filepos(unit._gpo_message, 0)
600 while location: 616 while location:
601 gpo.po_message_remove_filepos(unit._gpo_message, 0) 617 gpo.po_message_remove_filepos(unit._gpo_message, 0)
602 location = gpo.po_message_filepos(unit._gpo_message, 0) 618 location = gpo.po_message_filepos(unit._gpo_message, 0)
603 outputstring = "" 619 outputstring = ""
604 if self._gpo_memory_file: 620 if self._gpo_memory_file:
605 obsolete_workaround() 621 obsolete_workaround()
606 f = tempfile.NamedTemporaryFile(prefix='translate', suffix='.po') 622 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) 623 self._gpo_memory_file = gpo.po_file_write_v2(self._gpo_memory_file, f.name, xerror_handler)
608 f.seek(0) 624 f.seek(0)
609 outputstring = f.read() 625 outputstring = f.read()
610 f.close() 626 f.close()
611 return outputstring 627 return outputstring
612 628
613 def isempty(self): 629 def isempty(self):
614 """Returns True if the object doesn't contain any translation units.""" 630 """Returns True if the object doesn't contain any translation units."""
615 if len(self.units) == 0: 631 if len(self.units) == 0:
616 return True 632 return True
617 # Skip the first unit if it is a header. 633 # Skip the first unit if it is a header.
618 if self.units[0].isheader(): 634 if self.units[0].isheader():
619 units = self.units[1:] 635 units = self.units[1:]
620 else: 636 else:
621 units = self.units 637 units = self.units
622 638
623 for unit in units: 639 for unit in units:
624 if not unit.isblank() and not unit.isobsolete(): 640 if not unit.isblank() and not unit.isobsolete():
625 return False 641 return False
626 return True 642 return True
627 643
628 def parse(self, input): 644 def parse(self, input):
629 if hasattr(input, 'name'): 645 if hasattr(input, 'name'):
630 self.filename = input.name 646 self.filename = input.name
631 elif not getattr(self, 'filename', ''): 647 elif not getattr(self, 'filename', ''):
632 self.filename = '' 648 self.filename = ''
633 649
634 if hasattr(input, "read"): 650 if hasattr(input, "read"):
635 posrc = input.read() 651 posrc = input.read()
636 input.close() 652 input.close()
637 input = posrc 653 input = posrc
638 654
639 needtmpfile = not os.path.isfile(input) 655 needtmpfile = not os.path.isfile(input)
640 if needtmpfile: 656 if needtmpfile:
641 # This is not a file - we write the string to a temporary file 657 # This is not a file - we write the string to a temporary file
642 fd, fname = tempfile.mkstemp(prefix='translate', suffix='.po') 658 fd, fname = tempfile.mkstemp(prefix='translate', suffix='.po')
643 os.write(fd, input) 659 os.write(fd, input)
644 input = fname 660 input = fname
645 os.close(fd) 661 os.close(fd)
646 662
647 self._gpo_memory_file = gpo.po_file_read_v3(input, xerror_handler) 663 self._gpo_memory_file = gpo.po_file_read_v3(input, xerror_handler)
648 if self._gpo_memory_file is None: 664 if self._gpo_memory_file is None:
649 print >> sys.stderr, "Error:" 665 print >> sys.stderr, "Error:"
650 666
651 if needtmpfile: 667 if needtmpfile:
652 os.remove(input) 668 os.remove(input)
653 669
654 # Handle xerrors here 670 # Handle xerrors here
655 self._header = gpo.po_file_domain_header(self._gpo_memory_file, None) 671 self._header = gpo.po_file_domain_header(self._gpo_memory_file, None)
656 if self._header: 672 if self._header:
657 charset = gpo.po_header_field(self._header, "Content-Type") 673 charset = gpo.po_header_field(self._header, "Content-Type")
658 if charset: 674 if charset:
659 charset = re.search("charset=([^\\s]+)", charset).group(1) 675 charset = re.search("charset=([^\\s]+)", charset).group(1)
660 self._encoding = encodingToUse(charset) 676 self._encoding = encodingToUse(charset)
661 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memory_fi le, None) 677 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memory_fi le, None)
662 newmessage = gpo.po_next_message(self._gpo_message_iterator) 678 newmessage = gpo.po_next_message(self._gpo_message_iterator)
663 while newmessage: 679 while newmessage:
664 newunit = pounit(gpo_message=newmessage) 680 newunit = pounit(gpo_message=newmessage)
665 self.units.append(newunit) 681 self.units.append(newunit)
666 newmessage = gpo.po_next_message(self._gpo_message_iterator) 682 newmessage = gpo.po_next_message(self._gpo_message_iterator)
667 self._free_iterator() 683 #self._free_iterator()
668 684
669 def __del__(self): 685 def __del__(self):
686 #print 'DELL CALLED', id(self)
670 # We currently disable this while we still get segmentation faults. 687 # We currently disable this while we still get segmentation faults.
671 # Note that this is definitely leaking memory because of this. 688 # Note that this is definitely leaking memory because of this.
672 return 689 #return
673 self._free_iterator() 690 self._free_iterator()
674 if self._gpo_memory_file is not None: 691 if self._gpo_memory_file is not None:
675 gpo.po_file_free(self._gpo_memory_file) 692 gpo.po_file_free(self._gpo_memory_file)
676 self._gpo_memory_file = None 693 self._gpo_memory_file = None
677 694
678 def _free_iterator(self): 695 def _free_iterator(self):
696 #print 'ITERATOR CALLED', id(self)
679 # We currently disable this while we still get segmentation faults. 697 # We currently disable this while we still get segmentation faults.
680 # Note that this is definitely leaking memory because of this. 698 # Note that this is definitely leaking memory because of this.
681 return 699 #return
682 if self._gpo_message_iterator is not None: 700 if self._gpo_message_iterator is not None:
683 gpo.po_message_iterator_free(self._gpo_message_iterator) 701 gpo.po_message_iterator_free(self._gpo_message_iterator)
684 self._gpo_message_iterator = None 702 self._gpo_message_iterator = None
OLDNEW

Powered by Google App Engine
This is Rietveld r159