This file is indexed.

/usr/lib/ocaml/gettext/gettextPo.ml is in libgettext-ocaml-dev 0.3.5-2build1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
(**************************************************************************)
(*  ocaml-gettext: a library to translate messages                        *)
(*                                                                        *)
(*  Copyright (C) 2003-2008 Sylvain Le Gall <sylvain@le-gall.net>         *)
(*                                                                        *)
(*  This library is free software; you can redistribute it and/or         *)
(*  modify it under the terms of the GNU Lesser General Public            *)
(*  License as published by the Free Software Foundation; either          *)
(*  version 2.1 of the License, or (at your option) any later version;    *)
(*  with the OCaml static compilation exception.                          *)
(*                                                                        *)
(*  This library 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     *)
(*  Lesser General Public License for more details.                       *)
(*                                                                        *)
(*  You should have received a copy of the GNU Lesser General Public      *)
(*  License along with this library; if not, write to the Free Software   *)
(*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307   *)
(*  USA                                                                   *)
(**************************************************************************)

(**
    @author Sylvain Le Gall
  *)

open GettextUtils;;
open GettextTypes;;
open GettextMo;;

open FileUtil;;
open FilePath;;

(** empty_po : value representing an empty PO *)
let empty_po = 
  GettextPo_utils.empty_po
;;

(** add_po_translation_no_domain po (comment_lst,location_lst,translation) : add a translation 
    to a corpus of already defined translation with no domain defined. If the 
    translation already exist, they are merged concerning location, and 
    follow these rules for the translation itself : 
      - singular and singular : if there is an empty string ( "" ) in one
        of the translation, use the other translation,
      - plural and plural : if there is an empty string list ( [ "" ; "" ] ) in
        one of the translaiton, use the other translation,
      - singular and plural : merge into a plural form.
    There is checks during the merge that can raise PoInconsistentMerge : 
      - for one singular string if the two plural strings differs
      - if there is some elements that differs ( considering the special case of 
        the empty string ) in the translation
*)
let add_po_translation_no_domain po po_translation =
  try 
    GettextPo_utils.add_po_translation_no_domain po po_translation
  with PoInconsistentMerge(str1,str2) ->
    raise (PoInconsistentMerge(str1,str2))
;;

(** add_po_translation_domain po domain (comment_lst,location_lst,translation) : add a
    translation to the already defined translation with the domain defined. 
    See add_translation_no_domain for details.
*)
let add_po_translation_domain po domain po_translation =
  try
    GettextPo_utils.add_po_translation_domain po domain po_translation
  with PoInconsistentMerge(str1,str2) ->
    raise (PoInconsistentMerge(str1,str2))
;;

(** merge_po po1 po2 : merge two PO. The rule for merging are the same as
    defined in add_po_translation_no_domain. Can raise PoInconsistentMerge 
*)
let merge_po po1 po2 = 
  (* We take po2 as the initial set, we merge po1 into po2 beginning with
    po1.no_domain and then po1.domain *)
  let merge_no_domain =
    MapString.fold ( 
      fun _ translation po -> 
        add_po_translation_no_domain po translation
    ) po1.no_domain po2
  in
  let merge_one_domain domain map_domain po = 
    MapString.fold ( 
      fun _ translation po ->
        add_po_translation_domain domain po translation
    ) map_domain po
  in
  MapTextdomain.fold merge_one_domain po1.domain merge_no_domain
;;

(** merge_pot po pot : merge a PO with a POT. Only consider strings that
    exists in the pot. Always use location as defined in the POT. If a string 
    is not found, use the translation provided in the POT. If a plural is found
    and a singular should be used, downgrade the plural to singular. If a
    singular is found and a plural should be used, upgrade singular to plural,
    using the strings provided in the POT for ending the translation.
  *)
let merge_pot pot po =
  let order_po_map ?(domain) () = 
    match domain with 
      None ->
        po.no_domain :: ( 
          MapTextdomain.fold ( fun _ x lst -> x :: lst ) 
          po.domain []
        )
    | Some domain ->
        let tl = 
          po.no_domain :: (
            MapTextdomain.fold ( 
              fun key x lst -> 
                if key = domain then 
                  lst 
                else 
                  x :: lst 
            ) po.domain []
          )
        in
        try
          (MapTextdomain.find domain po.domain) :: tl
        with Not_found ->
          tl
  in
  let merge_translation map_lst key commented_translation_pot =
    let translation_pot =
      commented_translation_pot.po_comment_translation
    in
    let translation_merged = 
      try 
        let (commented_translation_po) = 
          let map_po = 
            List.find (MapString.mem key) map_lst
          in
          MapString.find key map_po
        in
        let translation_po =
          commented_translation_po.po_comment_translation
        in
        (* Implementation of the rule given above *)
        match (translation_pot,translation_po) with
          PoSingular(str_id,_), PoPlural(_, _, str :: _ ) -> 
            PoSingular(str_id, str)
        | PoPlural(str_id, str_plural, _ :: tl ), PoSingular(_, str) ->
            PoPlural(str_id, str_plural, str :: tl)
        | PoPlural(str_id, str_plural, []), PoSingular(_, str) ->
            PoPlural(str_id, str_plural, str :: [])
        | _, translation ->
            translation
      with Not_found ->
        (* Fallback to the translation provided in the POT *)
        translation_pot
    in
      {
        commented_translation_pot with
            po_comment_translation = translation_merged
      }
  in
  (* We begin with an empty po, and merge everything according to the rule 
     above. *)
  let merge_no_domain = 
    MapString.fold ( 
      fun key pot_translation po ->
        add_po_translation_no_domain po 
        (merge_translation (order_po_map ()) key pot_translation)
    ) pot.no_domain empty_po
  in
  let merge_one_domain domain map_domain po = 
    MapString.fold ( 
      fun key pot_translation po ->
        add_po_translation_domain domain po 
        (merge_translation (order_po_map ~domain:domain ()) key pot_translation)
    ) map_domain po
  in
  MapTextdomain.fold merge_one_domain pot.domain merge_no_domain
;;

let input_po chn =
  let lexbuf = Lexing.from_channel chn
  in
  try 
    GettextPo_parser.msgfmt GettextPo_lexer.token lexbuf
  with 
    Parsing.Parse_error ->
      raise (PoInvalidFile ("parse error",lexbuf,chn))
  | Failure(s) ->
      raise (PoInvalidFile (s,lexbuf,chn))
  | PoInconsistentMerge(str1,str2) ->
      raise (PoInconsistentMerge(str1,str2))
;;

let output_po chn po =
  let comment_max_length = 
    80
  in
  let fpf x = 
    Printf.fprintf chn x
  in
  let escape_string str =
    let rec escape_string_aux buff i =
      if i < String.length str then
        let () =
          match String.get str i with 
            | '\n'   -> Buffer.add_string buff "\\n"
            | '\t'   -> Buffer.add_string buff "\\t" 
            | '\b'   -> Buffer.add_string buff "\\b" 
            | '\r'   -> Buffer.add_string buff "\\r" 
            | '\012' -> Buffer.add_string buff "\\f" 
            | '\011' -> Buffer.add_string buff "\\v" 
            | '\007' -> Buffer.add_string buff "\\a" 
            | '"'    -> Buffer.add_string buff "\\\""
            | '\\'   -> Buffer.add_string buff "\\\\"
            | e ->
                Buffer.add_char buff e
        in
          escape_string_aux buff (i+1)
      else
        (
        )
    in
    let buff = 
      Buffer.create ((String.length str) + 2)
    in
      Buffer.add_char buff '"';
      escape_string_aux buff 0;
      Buffer.add_char buff '"';
      Buffer.contents buff
  in

  let hyphens chn lst = 
    match lst with
      [] ->
        ()
    | lst ->
        Printf.fprintf chn 
          "%s" 
          (String.concat "\n" (List.map escape_string lst))
  in

  let comment_line str_hyphen str_sep line_max_length token_lst =
    let str_len =
      (List.fold_left (fun acc str -> acc + (String.length str)) 0 token_lst)
      +
      ((List.length token_lst) * (String.length str_sep))
    in
    let buff =
      Buffer.create 
        (str_len + (String.length str_hyphen) * (str_len / line_max_length))
    in
    let rec comment_line_aux first_token line_length lst =
      match lst with 
        | str :: tl ->
            let sep_length =
              if first_token then
                0
              else if  (String.length str) + line_length > line_max_length then
                (
                  Buffer.add_char buff '\n';
                  Buffer.add_string buff str_hyphen;
                  Buffer.add_string buff str_sep;
                  (String.length str_hyphen) + (String.length str_sep)
                )
              else
                (
                  Buffer.add_string buff str_sep;
                  String.length str_sep
                )
            in
            Buffer.add_string buff str;
            comment_line_aux false (sep_length + (String.length str) + line_length)  tl
        | [] ->
            Buffer.contents buff
    in
      comment_line_aux true 0 token_lst
  in


  let rec output_po_translation_aux _ commented_translation = 
    (
      match commented_translation.po_comment_filepos with
        |  [] -> 
            ()
        | lst ->
            fpf "%s\n"
              (comment_line
                 "#."
                 " "
                 comment_max_length
                 ("#:" :: (List.map (fun (str,line) -> Printf.sprintf "%s:%d" str line) lst)))
    );
    (
      match commented_translation.po_comment_special with
        | [] ->
            ()
        | lst ->
            fpf "%s\n"
              (comment_line
                 "#."
                 " "
                 comment_max_length
                 ("#," :: lst))
    );
    (
      match commented_translation.po_comment_translation with
        PoSingular(id,str) ->
          (
            fpf "msgid %a\n" hyphens id;
            fpf "msgstr %a\n" hyphens str
          )
      | PoPlural(id,id_plural,lst) ->
          (
            fpf "msgid %a\n" hyphens id;
            fpf "msgid_plural %a\n" hyphens id_plural;
            let _ = List.fold_left 
              ( fun i s -> 
                fpf "msgstr[%i] %a\n" i hyphens s; 
                i + 1
              ) 0 lst
            in
            ()
          )
    );
    fpf "\n"
  in
  MapString.iter output_po_translation_aux po.no_domain;
  MapTextdomain.iter ( 
    fun domain map ->
        fpf "domain %S\n\n" domain;
        MapString.iter output_po_translation_aux map
  ) po.domain
;; 


let translation_of_po_translation po_translation = 
  match po_translation with
    PoSingular(id, str) ->
      Singular(String.concat "" id, String.concat "" str)
  | PoPlural(id, id_plural, lst) ->
      Plural ( 
        String.concat "" id, 
        String.concat "" id_plural, 
        List.map (String.concat "") lst
      )
;;