#!/usr/bin/php
<?php

/*
 *  Pophorator :: Copyright (C) 2004, 2005 Jarno Elonen <elonen@iki.fi>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

$progname = "pophorator";
$progver = "0.51";

ini_set( "memory_limit", "-1");
assert_options( ASSERT_BAIL, 1);
error_reporting(E_ALL);


// Output the PHP errors into STDERR as the output is written into STDOUT
function myErrorHandler($errno, $errstr, $errfile, $errline)
 {
   switch ($errno)
   {
   case E_USER_ERROR:
    fwrite(STDERR,
      "** INTERNAL FATAL ERROR [$errno] $errstr<br />\n" .
      "  Fatal error in line $errline of file $errfile" .
      ", PHP " . PHP_VERSION . " (" . PHP_OS . ")\n");
    exit(1);
    break;
   case E_USER_WARNING:
    fwrite(STDERR, "** INTERNAL ERROR: [$errno, line $errline] $errstr\n");
    exit(1);
    break;
   case E_USER_NOTICE:
   case E_NOTICE:
    fwrite(STDERR, "** INTERNAL WARNING: [$errno, line $errline] $errstr\n");
    break;
   default:
    fwrite(STDERR, "** INTERNAL UNKOWN ERROR: [$errno, line $errline] $errstr\n");
    exit(1);
    break;
  }
}
set_error_handler("myErrorHandler");


// TODO: support different character encodings
function Find_I10N_Strings( $file )
{
    $file_len = strlen($file);

    // Make a line num / col LUT
    $idx_to_row_col = array();
    $row = $col = 0;
    for ( $i=0; $i<$file_len; ++$i )
    {
        if ( $file[$i] == "\n" )
            { $row++; $col=0; }
        $idx_to_row_col[$i] = array($row, $col++);
    }

    // Find the PHP snippets
    $split = array();
    $php_matches = array();
    preg_match_all( '/<[?]php\s+(.*)\s+[?]>/Usi',
      $file, &$php_matches, PREG_OFFSET_CAPTURE|PREG_SET_ORDER);

    // Find the Javascript snippets
    $javascript_matches = array();
    preg_match_all( '/<\s*script[^>]*>(.*)<\s*[\/]\s*script[^>]*>/Usi', $file, &$javascript_matches, PREG_OFFSET_CAPTURE|PREG_SET_ORDER);

    // Append PHP and Javascript snippets and sort them by occurrence index
    $script_matches = array_merge($php_matches, $javascript_matches);
    usort($script_matches, create_function('$a,$b', 'return $a[0][1]>$b[0][1];'));

    // Merge overlapping script snippets (there might be, e.g. PHP blocks
    // inside <script> tags and overlapping snippets would choke the system later)
    list($prev_i, $prev) = each($script_matches);
    while( list($cur_i, $cur) = each($script_matches))
    {
      $pre_beg = $prev[0][1];
      $cur_beg = $cur[0][1];
      $pre_end = $pre_beg + strlen($prev[0][0]);
      $cur_end = $cur_beg + strlen($cur[0][0]);
      assert( $pre_beg <= $cur_beg );
      if ( $cur_beg <= $pre_end )
      {
        $new_end = max($pre_end, $cur_end);

        $pre_stripped_beg = $prev[1][1];
        $cur_stripped_beg = $cur[1][1];
        $pre_stripped_end = $pre_stripped_beg + strlen($prev[1][0]);
        $cur_stripped_end = $cur_stripped_beg + strlen($cur[1][0]);
        $new_stripped_end = max($pre_stripped_end, $cur_stripped_end);

        $script_matches[$prev_i][0][0] = substr($file, $pre_beg, $new_end-$pre_beg);
        $script_matches[$prev_i][1][0] = substr($file, $pre_stripped_beg, $new_stripped_end-$pre_stripped_beg);

        unset($script_matches[$cur_i]);
      }
      else
      {
        $prev_i = $cur_i;
        $prev = $cur;
      }
    }

    // Split pure HTML and script (PHP+Javascript) fragments into separate arrays
    $html_frags = array();
    $php_frags = array();
    $last_end = 0;
    foreach( $script_matches as $match )
    {
        $php_frags[] = $match[1];
        $new_start = $match[0][1];
        assert($new_start >= $last_end);
        if ( $new_start > $last_end )
            $html_frags[] = array( substr( $file, $last_end, $new_start-$last_end), $last_end);
        $last_end = $new_start + strlen($match[0][0]);
    }
    if ( $last_end < $file_len )
        $html_frags[] = array( substr( $file, $last_end, $file_len-$last_end), $last_end);

    // The found localization strings go here
    $phrases = array();

    // Find PHP/Javascript gettext strings (i.e. _("...") markings )
    foreach( $php_frags as $frag )
    {
        $i10n_strings = array();
        preg_match_all( '/_\(\s*([\'"])(.*)(?<!\\\\)\1\s*(\\/[*](.*)[*]\\/)?\s*\)/Usi',
          $frag[0], &$i10n_strings, PREG_OFFSET_CAPTURE);
        foreach( $i10n_strings[2] as $i => $m)
            $phrases[] = array(
                "txt" => $m[0],
                "cmt" => isset($i10n_strings[4][$i][0]) ? trim($i10n_strings[4][$i][0]) : "",
                "idx" => $frag[1] + $m[1],
                "tagidx" => $frag[1] + $i10n_strings[0][$i][1],
                "tagged" => $i10n_strings[0][$i][0],
                "fmt" => "PHP" );
    }

    // Make a translation table for joined HTML fragments without PHP-snippets
    $i = 0;
    $joined_html_idx_to_full_idx = array();
    foreach( $html_frags as $frag )
    {
        $len = strlen($frag[0]);
        $pos = $frag[1];
        while ( $len-- > 0 )
            $joined_html_idx_to_full_idx[$i++] = $pos++;
    }
    $joined_html = "";
    foreach( $html_frags as $frag )
      $joined_html .= $frag[0];

    // Make sure the translation table works..
    for ($i=0; $i<strlen($joined_html); $i++)
      assert(substr($joined_html, $i, 1) == substr($file, $joined_html_idx_to_full_idx[$i], 1));

    // Find the localizable tag attributes, locattr (e.g. <a title="DAS TEXT" locattr="title">)
    $tags = array();
    preg_match_all( '/<\s*[a-z-]+\s+([^>]+)>/Usi', $joined_html, &$tags, PREG_OFFSET_CAPTURE);
    foreach($tags[1] as $t)
    {
        $attr_matches = array();
        preg_match_all( '/([a-z-]+)\s*=\s*([\'"])(.*)(?<!\\\\)\2/Usi', $t[0], &$attr_matches, PREG_OFFSET_CAPTURE);
        $attrs = array();
        foreach( $attr_matches[1] as $i => $att )
            $attrs[$att[0]] = array( $attr_matches[3][$i][0], $attr_matches[3][$i][1] + $t[1]);
        if ( isset($attrs["locattr"]))
        {
            $loc_attrs = preg_split('/(\s|,|;)+/', $attrs["locattr"][0]);
            foreach( $loc_attrs as $la )
            {
                if ( isset($attrs[$la]))
                    $phrases[] = array(
                        "txt" => $attrs[$la][0],
                        "cmt" => (isset($attrs['loccomment'])) ? $attrs['loccomment'][0] : '',
                        "idx" => $joined_html_idx_to_full_idx[$attrs[$la][1]],
                        "tagidx" => $joined_html_idx_to_full_idx[$attrs[$la][1]],
                        "tagged" => $attrs[$la][0],
                        "fmt" => "HTML" );
                else $warnings[$joined_html_idx_to_full_idx[$t[1]]] = sprintf("No such attribute '%s'", $la);
            }
        }
    }

    // Find HTML <loc> strings
    $i10n_strings = array();
    preg_match_all( '/<\s*loc(?:\s+[^>]*)?(comment\s*=\s*([\'"])(.*)(?<!\\\\)\2)?>(.*)<\s*\/\s*loc(?:\s+[^>]*)?>/Usi', $joined_html, &$i10n_strings, PREG_OFFSET_CAPTURE);
    foreach( $i10n_strings[4] as $i => $m)
        $phrases[] = array(
            "txt" =>  $m[0],
            "cmt" =>  $i10n_strings[3][$i][0],
            "idx" => $joined_html_idx_to_full_idx[$m[1]],
            "tagidx" => $joined_html_idx_to_full_idx[$i10n_strings[0][$i][1]],
            "tagged" => $i10n_strings[0][$i][0],
            "fmt" => "HTML" );

    // Sort the phrases by occurrence position
    usort( $phrases, create_function('$a, $b', 'return $a["idx"] > $b["idx"];' ));

    // Mark the matches with row/col numbers
    foreach($phrases as $i => $a)
    {
        $a['row'] = $idx_to_row_col[$a['idx']][0] + 1;
        $a['col'] = $idx_to_row_col[$a['idx']][1] + 1;
        $phrases[$i] = $a;

        // If this fails, something above doesn't work correctly
        $test = substr($file, $a['idx'], strlen($a['txt']));
        if ( $test !== $a['txt'] && strpos($test, '<?') >= 0 )
        {
            fwrite(STDERR, sprintf(
              "ERROR: Localization strings must not contain PHP code due to code limitations, sorry. " .
              "(Snippet starts at line %d, col %d.)\n",  $a['row'], $a['col']));
            exit(-1);
        }
        else
          assert( $test === $a['txt'] );
    }

    return $phrases;
}

function Split_By_Tags($html)
{
  $res = array();
  preg_match_all( '/(<\s*(\\/?)\s*([a-z-]+)(?:\s+[^>]*)?>)?([^<]*)/si',
    $html, &$res, PREG_SET_ORDER);
  return $res;
}

// E.g. '<a href="#section1">' => '<a>'
function Remove_Tag_Attrs($html)
{
  $res  = "";
  foreach( Split_By_Tags($html) as $part )
  {
    if ( strlen($part[3]))
      $res .= '<' . $part[2] . $part[3] . '>';
    $res .= $part[4];
  }
  return $res;
}

// Apply localization strings from $po into $oldfile.
function Apply_Strings( $oldfile, $po )
{
  $oldfile = utf8_encode($oldfile);

  // "Safe" HTML tags that don't necessarily have to match
  // between the original and translated strings.
  $safe_tags = array('b', 'i', 'u', 'strong', 'em', 'sup', 'sub', 'small', 'br', 'hr');

  // Build an 'msgid' => 'msgstr' array and a respective linenumber array
  $transl = array();
  $po_lineno = array();
  foreach( $po as $id => $arr )
    if ( strlen($arr['msgid']) > 0 && strlen($arr['msgstr']) > 0 )
    {
      $transl[$arr['msgid']] = $arr['msgstr'];
      $po_lineno[$arr['msgid']] = $arr['lineno'];
    }

  $old_strings = Find_I10N_Strings( $oldfile );

  $res = "";

  // Walk through the localizatable snippets of $oldfile
  // and try to replace with $po entries
  $idx = 0;
  $end_idx = strlen( $oldfile );
  foreach( $old_strings as $os )
  {
    if ( $idx < $os['tagidx'] )
      $res .= substr($oldfile, $idx, $os['tagidx']-$idx);

    $txt = $os['txt'];
    if ( $os['fmt'] == "PHP" )
        $txt = stripcslashes($txt);
    if ( $os['fmt'] == "HTML" )
    {
        $txt = html_entity_decode($txt);
        $txt = Remove_Tag_Attrs($txt);
    }

    $repl = $os['txt'];
    if ( isset($transl[$txt]))
    {
      $linedef = sprintf("line %d in .PO and %d in HTML", $po_lineno[$txt], $os['row']);

      if ( $os['fmt'] == "HTML" )
      {
        $comb = "";
        $orig_parts = Split_By_Tags($os['txt']);
        $transl_parts = Split_By_Tags($transl[$txt]);

        $err = 0; // -1=warning, 1=error
        $err_str = "";
        while ( True )
        {
          // Walk past all the non-tag and "safe" tag parts
          // from both original and translated strings
          $op = each($orig_parts);
          while ($op !== False && ($op[1][3] == "" || in_array(strtolower($op[1][3]), $safe_tags)))
            $op = each($orig_parts);

          $tp = each($transl_parts);
          while ($tp !== False && ($tp[1][3] == "" || in_array(strtolower($tp[1][3]), $safe_tags)))
          {
            $comb .= $tp[1][0];
            $tp = each($transl_parts);
          }

          // Original parts ended first: warn if the translated parts contain
          // extra "non-safe" tags
          if ( $op === False )
          {
            while ($tp !== False)
            {
              $comb .= $tp[1][0];
              if ($tp[1][3] != "" && !in_array(strtolower($tp[1][3]), $safe_tags))
              {
                $err = -1;
                if ($err_str == "")
                  $err_str = 'extra "non-safe" tags in translation: ';
                $err_str .= '<'.$tp[1][2].$tp[1][3].'> ';
              }
              $tp = each($transl_parts);
            }
            break;
          }
          // Translation parts ended first: give an error if it didn't contain
          // all required ("non-safe") parts
          else if ( $tp === False )
          {
            while ($op !== False)
            {
              if ($op[1][3] != "" && !in_array(strtolower($op[1][3]), $safe_tags))
              {
                if ($err_str == "")
                  $err_str = "translation was missing tags: ";
                $err_str .= '<'.$op[1][2].$op[1][3].'> ';
                $err = 1;
              }
              $op = each($orig_parts);
            }
            break;
          }
          else if ( strtolower($op[1][3]) !== strtolower($tp[1][3]) ||
                    strtolower($op[1][2]) !== strtolower($tp[1][2]))
          {
            assert( $op[1][3] !== "" );
            assert( !in_array(strtolower($op[1][3]), $safe_tags) );
            assert( $tp[1][3] !== "" );
            assert( !in_array(strtolower($tp[1][3]), $safe_tags) );
            $err_str = "expected <" . $op[1][2].$op[1][3] . "> as in original but found <" .
                 $tp[1][2].$tp[1][3] . "> in translation";
            $err = 1;
            break;
          }
          else $comb .= $op[1][1] . $tp[1][4];
        }

        if ( !$err )
        {
          $repl = $comb;
        }
        else
        {
          if ( $err > 0 )
          {
            fwrite(STDERR, sprintf(
              "ERROR: %s (%s) -- USING NON-TRANSLATED VERSION\n",
              $err_str, $linedef ));
          }
          else
          {
            $repl = $comb;
            fwrite(STDERR, sprintf(
              "WARNING: %s (%s) but applying anyway\n",
              $err_str, $linedef ));
          }
        }
      }
      else
      {
        assert( $os['fmt'] == "PHP" );

        $orig_vars = array();
        preg_match_all( '/%[a-z]/i', $txt, $orig_vars );
        $transl_vars = array();
        preg_match_all( '/%[a-z]/i', $transl[$txt], $transl_vars );
        if ( $orig_vars[0] !== $transl_vars[0] )
        {
            fwrite(STDERR, sprintf(
              "ERROR: non-matching variable placeholders in translation and original " .
              "(%s) -- USING NON-TRANSLATED VERSION\n", $linedef ));
        }
        else $repl = $transl[$txt];
      }
    }

    if ( $os['fmt'] == "PHP" )
    {
      assert( $os['fmt'] == "PHP" );
      $repl = '"' . addcslashes(stripcslashes($repl),  "\"\0..\37\\") . '"';
    }

    $res .= $repl;
    $idx = $os['tagidx'] + strlen($os['tagged']);
  }

  $res .= substr($oldfile, $idx);

  // A bit dirty -- remove the remaining 'locattrs' by a global regexp:
  return preg_replace('/(<[^>]*)\s*locattr\s*=\s*([\'"])[^"\']*\2\s*([^>]*>)/', '\1\3', $res);
}

// Read the whole STDIN into a string
function Read_Stdin()
{
    $file = "";
    while (!feof(STDIN))
        $file .= fread(STDIN, 2048);
    return $file;
}

function Write_Pot_Header()
{
    global $progname, $progver;

    printf(<<<EOS
# SOME DESCRIPTIVE TITLE
# Copyright (C) YEAR THE COPYRIGHT-HOLDER
# This file is distributed under the same license as the SITE site.
# FIRST AUTHOR <EMAIL ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: SITE VERSION\\n"
"POT-Creation-Date: %s\\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
"Last-Translator: FULL NAME <EMAIL ADDRESS>\\n"
"Language-Team: LANGUAGE <LL li org>\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Generated-By: %s %s\\n"

EOS
        , date("r", time()), $progname, $progver );
}

function Print_Pot_Entries( $strings, $filename )
{
    // Bind up duplicate strings
    $occurrances = array();
    foreach ($strings as $s)
    {
        if (!isset($occurrances[$s['txt']]))
            $occurrances[$s['txt']] = array();
        $occurrances[$s['txt']][] = array($s['row'], $s['fmt'], $s['cmt']);
    }

    foreach( $occurrances as $txt => $infos )
    {
        print "\n";

        // Print out line numbers and comments
        $is_c_format = False;
        $occ_str = "#:";
        $comments = array();
        foreach( $infos as $occ )
        {
            $occ_str .= sprintf( " %s:%d", $filename, $occ[0] );
            if ( strlen(trim($occ[2])))
            {
                $cmt = trim($occ[2]);
                if ( $occ[1] == "HTML" )
                    $cmt = html_entity_decode($cmt);
                $comments[$filename . ":" . $occ[0]] = $cmt;
            }
            $is_c_format |= ($occ[1] == "PHP");
        }
        print $occ_str . "\n";
        foreach( $comments as $src => $cmt )
            printf( "#. %s%s\n", (count($infos)>1) ? sprintf("(for %s) ", $src) : "", str_replace("\n", "\\n", utf8_encode($cmt)));

        if ( $is_c_format )
            print "#, php-format\n";

        // Decode PHP/HTML encodings
        if ( $infos[0][1] == "PHP" )
            $txt = stripcslashes($txt);
        else if ( $infos[0][1] == "HTML" )
        {
            $txt = html_entity_decode($txt);
            # remove parameters from all tags
            $txt = preg_replace( '/<\s*(\\/?)\s*([a-z-]+)(?:\s+[^>]*)?>/Usi', '<\\1\\2>', $txt);
        }

        // Split the string if it's very long
        $msgid = sprintf("\"%s\"\n", addcslashes($txt,  "\"\0..\37\\"));
        if ( strlen($txt) > 65 )
        {
            $msgid = "\"\"\n";
            while ( strlen($txt) > 0 )
            {
                $msgid .= "\"" . addcslashes(substr($txt, 0, 65),  "\"\0..\37\\") . "\"\n";
                $txt = substr($txt, 65);
            }
        }
        printf( "msgid %s", utf8_encode($msgid));
        //printf( "msgid %s", $msgid);
        print( "msgstr \"\"\n");
    }
}

function decode_po_quotes($txt)
{
  return stripcslashes(preg_replace('/"[^"]*$/', '', preg_replace('/^[^"]*"/', '', $txt)));
}

// Read a .po[t] file
function parse_po( $lines )
{
  $res = array();
  $last_line_type = "comment";

  $empty_entry = array(
    "comments" => array(),
    "autocomments" => array(),
    "sources" => array(),
    "flags" => array(),
    "msgid" => "",
    "msgstr" => "" );
  $cur = $empty_entry;

  $lineno = 0;
  foreach( $lines as $line )
  {
    $lineno++;
    $line = trim($line);

    if (strlen($line))
    {
      if ( preg_match('/^#/', $line))
      {
        if ( $last_line_type != "comment" )
        {
          if ( strlen($cur["msgid"]) || strlen(join('', $cur["comments"])) )
            $res[] = $cur;
          $cur = $empty_entry;
        }

        $cur["lineno"] = $lineno;

        if ( preg_match('/^#:/', $line))
          $cur["sources"][] = trim(substr($line, 2));
        else if ( preg_match('/^#,/', $line))
          $cur["flags"] = preg_split('/[#, \t]+/', $line, -1, PREG_SPLIT_NO_EMPTY);
        else if ( preg_match('/^#[.]/', $line))
          $cur["autocomments"][] = trim(substr($line, 2));
        else
          $cur["comments"][] = trim(substr($line, 2));

        $last_line_type = "comment";
      }
      else if ( preg_match('/^msgid[ \t]+["]*/', $line))
      {
        if ( $last_line_type != "comment" )
        {
          if ( strlen($cur["msgid"]) || strlen($cur["comments"]) )
            $res[] = $cur;
          $cur = $empty_entry;
        }
        $cur["msgid"] = decode_po_quotes(substr($line, 6));
        $last_line_type = "msgid";
      }
      else if ( preg_match('/^msgstr[ \t]+["]*/', $line))
      {
        if ( $cur === False )
          $cur = $empty_entry;

        $cur["msgstr"] = decode_po_quotes($line);
        $last_line_type = "msgstr";
      }
      else if ( preg_match('/^"/', $line))
      {
        if ( !preg_match( '/msg(id|str)/', $last_line_type ))
          print "Warning: syntax error in PO-file on line $lineno \n";
        else
          $cur[$last_line_type] .= decode_po_quotes($line);
      }
      else
      {
        print "Warning: malformed line $lineno in PO-file.\n";
      }
    }
  }
  if ( strlen($cur["msgid"]) || strlen($cur["comments"]) )
    $res[] = $cur;

  $res2 = array();
  foreach( $res as $r )
    $res2[md5($r["msgid"])] = $r;

  return $res2;
}

function Print_Usage()
{
    global $progname, $progver;
    printf(<<<EOS
%s %s - Tool for localizing PHP, HTML and Javascript statically

Usage: %s -g <INFILE> [INFILE ...]
       %s -p <INFILE>

  -g               Get strings from INFILE(s) and write a .pot into STDOUT
  -p               Apply .po strings from STDIN to INFILE and write to STDOUT
  -h,  --help      Show this help

INFILEs are never modified, -p mode outputs the
changed version into STDOUT. The character encoding of INFILEs
is currently assumed to be in ISO-8859-1 whereas the output is in UTF-8.

HTML tags are abbreviated in the 'get' phase by removing all atributes
from them, e.g. '<a href="...">link</a>' becomes '<a>link</a>'. The
'put' phase puts them back.

Marking localizable strings:

  PHP and Javascript:

    Enclose strings into _() and mark comments with /**/. Example:
    _( "End" /* Verb, end session */  )

  HTML text:

    Enclose text into <loc comment="..."></loc>. Example:
    <a href="..."><loc comment="Verb, end session">End</loc></a>

  HTML tag attributes:

    List the localizable attributes in new attribute 'locattr',
    separated by space, comma or semicolon. Put comments into
    'loccomment' (shared between all the attributes). Example:
    <a href=".." title="End" locattr="title" loccomment="Verb, end session">

Copyright (C) 2004, 2005 by Jarno Elonen <elonen@iki.fi>.
Released under the GNU General Public License version 2.


EOS
, $progname, $progver, $progname, $progname );
}

function main()
{
    global $argv;
    if ( count($argv) < 2)
    {
        Print_Usage();
        return 2;
    }
    else
    {
        if ( $argv[1] == "-h" || $argv[1] == "--help" )
        {
            Print_Usage();
            return 0;
        }
        else if ( $argv[1] == "-g" )
        {
            if ( count($argv) < 3)
                fputs(STDERR, "ERROR: not enough arguments\n");
            else
            {
                Write_Pot_Header();
                for ( $i=2; $i<count($argv); $i++ )
                {
                    $filename = $argv[$i];
                    if ( !file_exists($filename))
                    {
                        fputs(STDERR, "ERROR: file not found '" . $filename . "'\n");
                        exit(-1);
                    }
                    $file =  file_get_contents( $filename );
                    Print_Pot_Entries( Find_I10N_Strings( $file ), $filename );
                    print "\n";
                }
            }
        }
        else if ( $argv[1] == "-p" )
        {
            if ( count($argv) < 3)
                fputs(STDERR, "ERROR: not enough arguments\n");
            else
            {
              $pofile = Array();
              while (!feof(STDIN))
                  $pofile[] = fgets(STDIN);
              $po = parse_po($pofile);

              $filename = $argv[2];
              if ( !file_exists($filename))
              {
                  fputs(STDERR, "ERROR: file not found '" . $filename . "'\n");
                  exit(-1);
              }

              print Apply_Strings( file_get_contents( $filename ), $po );
              exit(-1);
          }
        }
        else
        {
            fputs(STDERR, "ERROR: unknown command '" . $argv[1] . "'\n\n");
            Print_Usage();
            return 2;
        }
    }
}

main();

?>