This file is indexed.

/usr/share/lyx/scripts/lyxpak.py is in lyx-common 2.2.2-1.

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
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# -*- coding: utf-8 -*-

# file lyxpak.py
# This file is part of LyX, the document processor.
# Licence details can be found in the file COPYING.

# author Enrico Forestieri
# author Richard Heck

# Full author contact details are available in file CREDITS

# This script creates a tar or zip archive with a lyx file and all included
# files (graphics and so on). By default, the created archive is the standard
# type on a given platform, such that a zip archive is created on Windows and
# a gzip compressed tar archive on *nix. This can be controlled by command
# line options, however.

import gzip, os, re, string, sys
from getopt import getopt
from cStringIO import StringIO
import subprocess

# The path to the current python executable. sys.executable may fail, so in
# this case we revert to simply calling "python" from the path.
PYTHON_BIN = sys.executable if sys.executable else "python"

running_on_windows = (os.name == 'nt')

if running_on_windows:
    from shutil import copyfile
    from tempfile import NamedTemporaryFile

# Pre-compiled regular expressions.
re_lyxfile = re.compile("\.lyx$")
re_input = re.compile(r'^(.*)\\(input|include){(\s*)(.+)(\s*)}.*$')
re_ertinput = re.compile(r'^(input|include)({)(\s*)(.+)(\s*)}.*$')
re_package = re.compile(r'^(.*)\\(usepackage){(\s*)(.+)(\s*)}.*$')
re_class = re.compile(r'^(\\)(textclass)(\s+)(.+)\s*$')
re_norecur = re.compile(r'^(.*)\\(verbatiminput|lstinputlisting|includegraphics\[*.*\]*){(\s*)(.+)(\s*)}.*$')
re_ertnorecur = re.compile(r'^(verbatiminput|lstinputlisting|includegraphics\[*.*\]*)({)(\s*)(.+)(\s*)}.*$')
re_filename = re.compile(r'^(\s*)(filename)(\s+)(.+)\s*$')
re_options = re.compile(r'^(\s*)options(\s+)(.+)\s*$')
re_bibfiles = re.compile(r'^(\s*)bibfiles(\s+)(.+)\s*$')


def usage(prog_name):
    msg = '''
Usage: %s [-t] [-z] [-l path] [-o output_dir] file.lyx
Options:
-l: Path to lyx2lyx script
-o: Directory for output
-t: Create gzipped tar file
-z: Create zip file
By default, we create file.zip on Windows and file.tar.gz on *nix,
with the file output to where file.lyx is, and we look for lyx2lyx
in the known locations, querying LyX itself if necessary.
'''
    return msg % prog_name


def error(message):
    sys.stderr.write(message + '\n')
    sys.exit(1)


def gzopen(file, mode):
    input = open(unicode(file, 'utf-8'), 'rb')
    magicnum = input.read(2)
    input.close()
    if magicnum == "\x1f\x8b":
        return gzip.open(unicode(file, 'utf-8'), mode)
    return open(unicode(file, 'utf-8'), mode)


def find_exe(candidates, extlist, path):
    for prog in candidates:
        for directory in path:
            for ext in extlist:
                full_path = os.path.join(directory, prog + ext)
                if os.access(full_path, os.X_OK):
                    return prog, full_path
    return None, None


def abspath(name):
    " Resolve symlinks and returns the absolute normalized name."
    newname = os.path.normpath(os.path.abspath(name))
    if not running_on_windows:
        newname = os.path.realpath(newname)
    return newname


def gather_files(curfile, incfiles, lyx2lyx):
    " Recursively gather files."
    curdir = os.path.dirname(abspath(curfile))
    is_lyxfile = re_lyxfile.search(curfile)

    if is_lyxfile:
        if running_on_windows:
            # os.popen cannot cope with unicode arguments and we cannot be
            # sure that curfile can be correctly converted to the current
            # code page. So, we resort to running lyx2lyx on a copy.
            tmp = NamedTemporaryFile(delete=False)
            tmp.close()
            copyfile(unicode(curfile, 'utf-8'), tmp.name)
            try:
                l2l_stdout = subprocess.check_output([PYTHON_BIN, lyx2lyx, tmp.name])
            except subprocess.CalledProcessError:
                error('%s failed to convert "%s"' % (lyx2lyx, curfile))
            os.unlink(tmp.name)
        else:
            try:
                l2l_stdout = subprocess.check_output([PYTHON_BIN, lyx2lyx, curfile])
            except subprocess.CalledProcessError:
                error('%s failed to convert "%s"' % (lyx2lyx, curfile))
        if l2l_stdout.startswith("\x1f\x8b"):
            l2l_stdout = gzip.GzipFile("", "r", 0, StringIO(l2l_stdout)).read()
        lines = l2l_stdout.splitlines()
    else:
        input = gzopen(curfile, 'rU')
        lines = input.readlines()
        input.close()

    maybe_in_ert = False
    i = 0
    while i < len(lines):
        # Gather used files.
        recursive = True
        extlist = ['']
        match = re_filename.match(lines[i])
        if not match:
            if maybe_in_ert:
                match = re_ertinput.match(lines[i])
            else:
                match = re_input.match(lines[i])
            if not match:
                match = re_package.match(lines[i])
                extlist = ['.sty']
                if not match:
                    match = re_class.match(lines[i])
                    extlist = ['.cls']
                    if not match:
                        if maybe_in_ert:
                            match = re_ertnorecur.match(lines[i])
                        else:
                            match = re_norecur.match(lines[i])
                        extlist = ['', '.eps', '.pdf', '.png', '.jpg']
                        recursive = False
        maybe_in_ert = is_lyxfile and lines[i] == "\\backslash"
        if match:
            file = match.group(4).strip('"')
            if not os.path.isabs(file):
                file = os.path.join(curdir, file)
            file_exists = False
            if not os.path.isdir(unicode(file, 'utf-8')):
                for ext in extlist:
                    if os.path.exists(unicode(file + ext, 'utf-8')):
                        file = file + ext
                        file_exists = True
                        break
            if file_exists and not abspath(file) in incfiles:
                incfiles.append(abspath(file))
                if recursive:
                    gather_files(file, incfiles, lyx2lyx)
            i += 1
            continue

        if not is_lyxfile:
            i += 1
            continue

        # Gather bibtex *.bst files.
        match = re_options.match(lines[i])
        if match:
            file = match.group(3).strip('"')
            if file.startswith("bibtotoc,"):
                file = file[9:]
            if not os.path.isabs(file):
                file = os.path.join(curdir, file + '.bst')
            if os.path.exists(unicode(file, 'utf-8')):
                incfiles.append(abspath(file))
            i += 1
            continue

        # Gather bibtex *.bib files.
        match = re_bibfiles.match(lines[i])
        if match:
            bibfiles = match.group(3).strip('"').split(',')
            j = 0
            while j < len(bibfiles):
                if os.path.isabs(bibfiles[j]):
                    file = bibfiles[j] + '.bib'
                else:
                    file = os.path.join(curdir, bibfiles[j] + '.bib')
                if os.path.exists(unicode(file, 'utf-8')):
                    incfiles.append(abspath(file))
                j += 1
            i += 1
            continue

        i += 1

    return 0


def find_lyx2lyx(progloc, path):
    " Find a usable version of the lyx2lyx script. "
    # first we will see if the script is roughly where we are
    # i.e., we will assume we are in $SOMEDIR/scripts and look
    # for $SOMEDIR/lyx2lyx/lyx2lyx.
    ourpath = os.path.dirname(abspath(progloc))
    (upone, discard) = os.path.split(ourpath)
    tryit = os.path.join(upone, "lyx2lyx", "lyx2lyx")
    if os.access(tryit, os.X_OK):
        return tryit

    # now we will try to query LyX itself to find the path.
    extlist = ['']
    if "PATHEXT" in os.environ:
        extlist = extlist + os.environ["PATHEXT"].split(os.pathsep)
    lyx_exe, full_path = find_exe(["lyxc", "lyx"], extlist, path)
    if lyx_exe == None:
        error('Cannot find the LyX executable in the path.')
    try:
        cmd_stdout = subprocess.check_output([lyx_exe, '-version'], stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError:
        error('Cannot query LyX about the lyx2lyx script.')
    re_msvc = re.compile(r'^(\s*)(Host type:)(\s+)(win32)$')
    re_sysdir = re.compile(r'^(\s*)(LyX files dir:)(\s+)(\S+)$')
    lines = cmd_stdout.splitlines()
    for line in lines:
        match = re_msvc.match(line)
        if match:
            # The LyX executable was built with MSVC, so the
            # "LyX files dir:" line is unusable
            basedir = os.path.dirname(os.path.dirname(full_path))
            tryit = os.path.join(basedir, 'Resources', 'lyx2lyx', 'lyx2lyx')
            break
        match = re_sysdir.match(line)
        if match:
            tryit = os.path.join(match.group(4), 'lyx2lyx', 'lyx2lyx')
            break

    if not os.access(tryit, os.X_OK):
        error('Unable to find the lyx2lyx script.')
    return tryit


def main(args):

    ourprog = args[0]

    try:
      (options, argv) = getopt(args[1:], "htzl:o:")
    except:
      error(usage(ourprog))

    # we expect the filename to be left
    if len(argv) != 1:
        error(usage(ourprog))

    makezip = running_on_windows
    outdir = ""
    lyx2lyx = None

    for (opt, param) in options:
      if opt == "-h":
        print usage(ourprog)
        sys.exit(0)
      elif opt == "-t":
        makezip = False
      elif opt == "-z":
        makezip = True
      elif opt == "-l":
        lyx2lyx = param
      elif opt == "-o":
        outdir = param
        if not os.path.isdir(unicode(outdir, 'utf-8')):
          error('Error: "%s" is not a directory.' % outdir)

    lyxfile = argv[0]
    if not running_on_windows:
        lyxfile = unicode(lyxfile, sys.getfilesystemencoding()).encode('utf-8')
    if not os.path.exists(unicode(lyxfile, 'utf-8')):
        error('File "%s" not found.' % lyxfile)

    # Check that it actually is a LyX document
    input = gzopen(lyxfile, 'rU')
    line = input.readline()
    input.close()
    if not (line and line.startswith('#LyX')):
        error('File "%s" is not a LyX document.' % lyxfile)

    if makezip:
        import zipfile
    else:
        import tarfile

    ar_ext = ".tar.gz"
    if makezip:
        ar_ext = ".zip"

    ar_name = re_lyxfile.sub(ar_ext, abspath(lyxfile))
    if outdir:
        ar_name = os.path.join(abspath(outdir), os.path.basename(ar_name))

    path = string.split(os.environ["PATH"], os.pathsep)

    if lyx2lyx == None:
        lyx2lyx = find_lyx2lyx(ourprog, path)

    # Initialize the list with the specified LyX file and recursively
    # gather all required files (also from child documents).
    incfiles = [abspath(lyxfile)]
    gather_files(lyxfile, incfiles, lyx2lyx)

    # Find the topmost dir common to all files
    if len(incfiles) > 1:
        topdir = os.path.commonprefix(incfiles)
        # As os.path.commonprefix() works on a character by character basis,
        # rather than on path elements, we need to remove any trailing bytes.
        topdir = topdir.rpartition(os.path.sep)[0] + os.path.sep
    else:
        topdir = os.path.dirname(incfiles[0]) + os.path.sep

    # Remove the prefix common to all paths in the list
    i = 0
    while i < len(incfiles):
        incfiles[i] = string.replace(incfiles[i], topdir, '', 1)
        i += 1

    # Remove duplicates and sort the list
    incfiles = list(set(incfiles))
    incfiles.sort()

    if topdir != '':
        os.chdir(unicode(topdir, 'utf-8'))

    # Create the archive
    try:
        if makezip:
            zip = zipfile.ZipFile(ar_name, "w", zipfile.ZIP_DEFLATED)
            for file in incfiles:
                zip.write(file.decode('utf-8'), unicode(file, 'utf-8'))
            zip.close()
        else:
            tar = tarfile.open(ar_name, "w:gz")
            for file in incfiles:
                tar.add(file)
            tar.close()
    except:
        error('Failed to create LyX archive "%s"' % ar_name)

    print 'LyX archive "%s" created successfully.' % ar_name
    return 0


if __name__ == "__main__":
    if running_on_windows:
        # This works around <http://bugs.python.org/issue2128> for Python 2.
        # All arguments are retrieved in unicode format and converted to utf-8.
        # In this way, when launched from the command line, lyxpak.py can deal
        # with any non-ascii names. Unfortunately, this is not the case when
        # launched by LyX, because LyX converts the arguments of the converters
        # to the filesystem encoding. On Windows this corresponds to the current
        # code page and not to the UTF-16 encoding used by NTFS, such that they
        # are transliterated if not exactly encodable. As an example, α may
        # become a, β may become ß, and so on. However, this is a problem only
        # if the full path of the LyX document contains an unencodable character
        # as all other paths are extracted from the document in utf-8 format.
        from ctypes import WINFUNCTYPE, windll, POINTER, byref, c_int
        from ctypes.wintypes import LPWSTR, LPCWSTR
        GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32))
        CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))(("CommandLineToArgvW", windll.shell32))
        argc = c_int(0)
        argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc))
        # unicode_argv[0] is the Python interpreter, so skip that.
        argv = [argv_unicode[i].encode('utf-8') for i in xrange(1, argc.value)]
        # Also skip option arguments to the Python interpreter.
        while len(argv) > 0:
            if not argv[0].startswith("-"):
                break
            argv = argv[1:]
        sys.argv = argv

    main(sys.argv)