summaryrefslogtreecommitdiff
path: root/support/pydocstrip/docstrip.py
blob: 99a985967ba255624f9b15c6ba61a3c6d2956704 (plain)
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
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
#!/usr/bin/env python
import string,re,sys,stat,os,getopt,time

## <VERSION
SELF_VER    = 1796
## VERSION>

SELF_INFOR  = "ktv-docstrip (version Python.%d)" % SELF_VER
GEN_DATE    = "%d/%02d/%02d" % time.localtime()[:3]

## :: Regular Expression

## file DTX
re_begin    = re.compile("%<\*([!a-zA-Z(][()a-zA-Z0-9_|&!]*)>")    # begin block
re_end      = re.compile("%</([!a-zA-Z(][()a-zA-Z0-9_|&!]*)>")     # end block
re_sblock   = re.compile("%<([!a-zA-Z(][()a-zA-Z0-9_|&!]*)>(.+\n)")# inline block
re_code     = re.compile("^[^%]")                                  # code

## file KINS
re_from     = re.compile("\$from\(([^)]+)\)")
re_gen      = re.compile("\$gen\(([^)]+)\)[ ]*\(([^)]+)\)[ ]*(.*)")
re_asg      = re.compile("\$([a-z][a-z0-9_]*)[ ]*=[ ]*(.*)")
## re_asg      = re.compile("\$([a-z][a-z0-9_]*)[ ]*=[ ]*(.*)")
re_kasg     = re.compile("([a-z][a-zA-Z0-9_]*)[ ]*=[ ]*(.*)")
re_com      = re.compile("#.*") ## comment line
re_isnum    = re.compile("[+|-]*[0-9]+")
re_local    = re.compile("\$local\(([^)]+)\)")
re_eof      = re.compile("\$eof=([01])")
## re_eoj      = re.compile("\$eoj=([01])")
re_import   = re.compile("\$import\(([^)]+)\)") ## add, Ky Anh, 2003/12/25
re_if       = re.compile("\$if\(([^)]+)\)")
re_elif     = re.compile("\$elif\(([^)]+)\)")
re_exec     = re.compile("\$<<<(.*)")
## re_expand   = re.compile("\$\([a-z][a-z0-9_]*\)")

def _xsplit(st):
    """Tao list cac terminal/guard, bo qua &,|,!,(,)
    Chi tra ve cac list chua co trong danh sach __guards ma thoi
    """
    ## last modify: Ky Anh, 2003/12/27
    ##            : use global __guards
    global __guards
    for ops in ['&', '(', ')', '!', '|', ',', ' ']:
        st = string.replace(st, ops, ':')
    tmp = []
    for ops in string.split(st, ':'):
        if (ops != '') and (not ops in __guards):
            tmp.append(ops)
    __guards.extend(tmp)
    __use(tmp,0)

def _translate(st): #
    """Dich mot bieu thuc logic thanh loi chuan cua PYTHON"""
    st = "(%s)" % st
    idx = 0
    tmpst = ""
    find_next_op = 0
    group_level  = 0
    while idx < len(st):
        if st[idx] == '!':
            tmpst = tmpst + "(not "
            find_next_op = 1
        elif st[idx] == '(':
            tmpst = tmpst + '('
            group_level = group_level + 1
        elif st[idx] == ')':
            tmpst = tmpst + ')'
            group_level = group_level - 1
        else: # !
            if find_next_op:
                while (find_next_op > 0) and (idx < len(st)):
                    if (st[idx] in __block_ops) or (group_level == 0):
                        tmpst = tmpst + ')' + st[idx]
                        find_next_op = 0
                    else:
                        tmpst = tmpst + st[idx]
                        idx = idx + 1
            else:
                tmpst = tmpst + st[idx]
        idx = idx +1

    idx = string.count(tmpst,'(') - string.count(tmpst,')')
    while idx > 0 :
        tmpst = tmpst + ')'
        idx = idx - 1
    return tmpst[1:-1]

def __setval(guard, value=1):
    ## add, Ky Anh, 2003/12/27
    exec("global %s\n%s=%d" % (guard,guard,value))

def __use(options, value=1):
    ## add, Ky Anh, 2003/12/27
    ## mod, Ky Anh, 2003/12/30, v1792, remove __alpha/__beta option check
    for weapon in options:
        tmpst = string.strip(weapon)
        if tmpst: __setval(tmpst,value)
##             if tmpst in __alpha_options:
##                 __setval(tmpst,1)
##             elif tmpst in __beta_options:
##                 __setval(tmpst,0)
##             else:            

def _use(opts_string, value=1):
    __use(string.split(opts_string, ","), value)

def _do_global():
	## add, Ky Anh, 2003/12/27
##  _force_
##  _gonly_
##  _kins_nopre
##  _kins_nopost
##  _kins_debug
##  _kins_destdir
##  jobnames             ## list of job (<kins> files)
##  __guards             ## list of guard in DTX files
##                          add, Ky Anh, 2003/12/27
##  NO                   ## list of NO-equivalent (0, No, NO, etc.)
##  __block_ops          ## list of operators in a DTX guard (block)
##  __kins_vars          ## list of global kins variables
##  __global_kins_vars   ## kins variables that are also the global
##                          variables in this program
##  __no_skip_vars       ## variables appear in the third part of |$gen|
##                          command; these variables arenot the <test>
##  __alpha_options      ## this DTX options will always be set to 1
##  __beta_options       ## - 0
##  _tex_                ## output as the INS file
    global\
        _force_,\
        _gonly_,\
        _kins_nopre,\
        _kins_nopost,\
        _kins_debug,\
        _kins_destdir,\
        jobnames,\
        __guards,\
        NO,\
        __block_ops,\
        __kins_vars,\
        __global_kins_vars,\
        __no_skip_vars,\
        _tex_,\
        _kins_pre_def,\
        _kins_pos_def
##         __alpha_options,\
##         __beta_options

    NO = ['0','no']

    __block_ops = ['&','|']	## donot accept the !. See the _translate()
    __global_kins_vars = ["pre", "post"]
    __no_skip_vars     = ["append", "nopost", "nopre",\
                          "destdir", "source", "debug"]
##     __alpha_options    = ["alpha", "com"]
##     __beta_options     = []

    jobnames = []
    __guards = []

    _force_ = 0
    _gonly_ = 0
    _tex_   = 0

    ## initialize the global variables
    ##      these variable can be exported, i.e.,
    ##      we can use `--exec cmd' at command line.
    _kins_nopre   = '0'
    _kins_nopost  = '0'
    _kins_debug   = '0'
    _kins_destdir = '.'
    __kins_vars   = ["nopre", "nopost", "destdir", "debug"]
    _kins_pre_def = "%% This file was generate\n\
%% \tfrom the file `$source'\n\
%% \twith option `$option'\n\
%% GenDate: $date\n\
%% Generator: $generator\n"
    _kins_pos_def = "%% End of file `$dest'"

    ## init the <special> guards
    ##      we neednot do this, because if a guard appears in a DTX file
    ##      it is recognize by _xsplit and then set the value by __use
    ##      see the defintionof _xplist for more details
    ## __use(__alpha_options + __beta_options)

def _xstrip(options, debug=0):
    """Tach ma tu file DTX voi options"""
    global __ilines, __output
    _use(options, 1)
    __output = []
    __level = 0
    __prints = [1]
    if debug: print "%s" % ("=" * 72),
    for weapon in __ilines:
        print_code = 0
        if re_begin.match(weapon):
            __level = __level + 1
            if __prints[__level - 1]: # previous block
                current_bblock = re_begin.match(weapon).group(1)
                exec("print_code=%s" % _translate(current_bblock))
            __prints.append(int(print_code))
            if debug: print "\nlevel%2d  %s *%s -> "\
                    % (__level,__prints,re_begin.match(weapon).group(1)),
        elif re_end.match(weapon):
            __level = __level - 1
            if __level < 0: break
            __prints.pop()
            if debug: print "\nlevel%2d  %s    /%s -> "\
                    % (__level,__prints,re_end.match(weapon).group(1)),
        elif re_sblock.match(weapon): #
            if __prints[__level]:
                current_bblock = re_sblock.match(weapon).group(1)
                exec("print_code=%s" % _translate(current_bblock))
            if debug: print "\nlevel%2d  %s %s -> "\
                    % (__level,__prints,re_sblock.match(weapon).group(1)),
            if print_code:
                if debug: sys.stdout.write('s')
                else: __output.append(re_sblock.match(weapon).group(2))
            if debug:
                print "\nlevel%2d  %s -> " % (__level,__prints),
        elif re_code.match(weapon):
            if __prints[__level]:
                if debug: sys.stdout.write('n')
                else: __output.append(weapon)
    if __level:
        print \
"\nThe blocks of your DTX file donot balance.\n\
To debug, use <docstrip> with `--debug' option."
    if debug: print "\n%s" % ("=" * 72)

    _use(options, 0) # reset options' value to 0

def _readkins(filename):
    ## add, Ky Anh, 2003/12/25
    """Read a KINS file, remove the comment line, and strip the lines.
    This function returns a LIST of KINS lines."""
    mykinslines = []
    f = open(filename, 'r')
    iline = f.readline()
    while iline:
        iline = re_com.split(iline)[0]
        iline = string.strip(iline)
        if re_eof.match(iline):
            if re_eof.match(iline).group(1) == '1':
                break ## reach END OF FILE
        elif iline:
            mykinslines.append(iline)
        iline = f.readline()
    f.close()
    return mykinslines

def _dokins(filename):
    """Excute the KINS code. The original name is |_readkins|; this version
    wasnot support |$import|. To do |$import|, a new function |_readkins| was
    added, and this function is now named |_dokins|."""
    global _kins_pre, _kins_post, kins_lines, _kins_pre_def, _kins_pos_def
    kins_lines = []
    __imported = [] # list of imported files

    _kins_pre   = _kins_pre_def  # default preamble/
    _kins_post  = _kins_pos_def  # default /postamble
    _kins_source= ''

    in_pre = in_post = 0
    in_if     = [1]
    __iflevel = 0
    __ifcont  = []

    kins_lines = _readkins(filename)

    while kins_lines:
        iline = kins_lines.pop(0)
## :: = $if
        if re_if.match(iline):
            if_value = 0
            __iflevel = __iflevel + 1
            if in_if[__iflevel - 1]:
                var_name = re_if.match(iline).group(1)
                if re_kasg.match(var_name):
                    var_value = re_kasg.match(var_name).group(2)
                    var_name  = re_kasg.match(var_name).group(1)
                    try:
                        if var_name in __kins_vars:
                            exec("tmp_value=_kins_%s" % var_name)
                        else:
                            exec("tmp_value=_gen_%s" % var_name)
                        if var_value == tmp_value:
                            if_value = 1 
                    except NameError: pass
            in_if.append(if_value)
## :: = $elif
        elif re_elif.match(iline):
            __iflevel = __iflevel - 1
            iline = "$if%s" % iline[5:]
            kins_lines.insert(0, iline)
## :: = $else
        elif iline == "$else":
            in_if[__iflevel] = 1 - in_if[__iflevel]
## :: = $enif
        elif iline == "$enif":
            __iflevel = __iflevel - 1
            if __iflevel < 0:
                sys.stderr.write(\
                    "\nerror: to much $enif. The program is going to stop.\n")
                sys.exit(1)
            else:
                in_if.pop()
            if __iflevel == 0:
                kins_lines[0:0], __ifcont = __ifcont, []
        elif __iflevel:
            if in_if[__iflevel]:
                __ifcont.append(iline)
## :: = pre, post
        elif iline == "$pre":  _kins_pre,  in_pre  = "", 1
        elif iline == "$post": _kins_post, in_post = "", 1
        elif iline == "$enpre":  in_pre  = 0
        elif iline == "$enpost": in_post = 0
## ## :: = $(.+)
##         elif re_expand.match(iline):
##             var_name = re_expand.match(iline).group(1)
## :: = $<<<<
        elif re_exec.match(iline):
            try:
                exec(re_exec.match(iline).group(1))
            except:
                sys.stderr.write("E")
## :: = if in_pre, in_post
        ## hai do`ng sau pha?i dde^? sau bo^'n do`ng tre^n
        elif in_pre:  _kins_pre  = _kins_pre  + iline + '\n'
        elif in_post: _kins_post = _kins_post + iline + '\n'
## :: = $from
        elif re_from.match(iline): # from macro
            _kins_source = re_from.search(iline).group(1)
            _readsource(_kins_source)
            sys.stderr.write('_')
## :: = $import
        elif re_import.match(iline):
            _i_file = re_import.match(iline).group(1)
            if not _i_file in __imported:
                __imported.append(_i_file)
                if not string.lower(_i_file[-5:]) == ".kins":
                    _i_file = _i_file + ".kins"
                kins_lines[0:0] = _readkins(_i_file)
                sys.stderr.write('=')
            else:
                sys.stderr.write('*')
## :: = assign
        elif re_asg.match(iline):
            var_name = re_asg.match(iline).group(1)
            var_value= re_asg.match(iline).group(2)
## :: = = $docstrip
            if var_name == 'docstrip': #
                if SELF_VER < int(var_value):
                    sys.stderr.write(\
"need docstrip %d or higher. Current docstrip's version: %d.\n"\
                        % (int(var_value), SELF_VER))
                    return
## :: = = global kins variables
            elif var_name in __global_kins_vars:
                exec('global _kins_%s\n_kins_%s="""%s"""'\
                    % (var_name, var_name, var_value))
## :: = = other kins variables
            else:
                if not var_name in __kins_vars:
                    __kins_vars.append(var_name)
                exec('_kins_%s="""%s"""' % (var_name,var_value))
                if var_name == 'source': _readsource(_kins_source)
## :: = $local
        elif re_local.match(iline):
            zzz = re_local.match(iline).group(1)
            if re_kasg.match(zzz):
                var_name  = re_kasg.match(zzz).group(1)
                var_value = re_kasg.match(zzz).group(2)
                exec('_gen_%s="""%s"""' % (var_name,var_value))
## :: = $gen
        elif re_gen.match(iline): # gen macro
            gen_des = re_gen.match(iline).group(1)
            if (not _gonly_) or (only_files.search(gen_des)):
                gen_opt = re_gen.match(iline).group(2)
                ## neu $gen co them tham so thu ba
                ## tham so nay phai de trong ngoac: (.+)
                kins_skip    = 0
                _gen_append  = '0'          # <initial value must be '0'>
                _gen_nopre   = _kins_nopre  # get the global value
                _gen_nopost  = _kins_nopost # as the initialization
                _gen_destdir = _kins_destdir# add 2003/12/10
                _gen_debug   = _kins_debug  #
                if re_gen.search(iline).group(3) != "":
                    gen_optlist = string.split(\
                        re_gen.search(iline).group(3)[1:-1],',')
                    for item in gen_optlist:
                        item = string.strip(item)
                        if item   == "append": _gen_append = '1'
                        elif item == "nopost": _gen_nopost = '1'
                        elif item == "nopre" : _gen_nopre  = '1'
                        else:
                            zzz = re_kasg.match(item)
                            if zzz:
                                var_name = zzz.group(1)
                                var_value= str(zzz.group(2))
                                if var_name in __no_skip_vars:
                                    exec('_gen_%s="""%s"""' % (var_name,var_value))
                                else:
                                    try:
                                        if var_name in __kins_vars:
                                            exec("tmp_value=_kins_%s" % var_name)
                                        else:
                                            exec("tmp_value=_gen_%s" % var_name)
                                        if not var_value == tmp_value:
                                            kins_skip = 1
                                            break # break the FOR loop
                                            ## donot mention other check
                                    except NameError:
                                        exec('_gen_%s="""%s"""' % (var_name,var_value))
                if kins_skip:
                    sys.stderr.write('o')
                else:
                    gen_des = "%s/%s" % (_gen_destdir, gen_des)
                    _gen(gen_des,gen_opt,\
                        _gen_append,\
                        _gen_nopre,_gen_nopost,\
                        _kins_source, _gen_debug)
            else:
                sys.stderr.write('o')
## :: = anything else
        else: pass
    if __iflevel != 0:
        sys.stderr.write("\nerror: missing $if or $enif\n")

def _readsource(source):
    ## last modify: Ky Anh, 2003/12/27
    ##            : according to changes of _xsplit
    global __ilines,\
            src_time
    __ilines = []
    src_time = os.stat(source)[stat.ST_MTIME]
    f = open(source, 'r')
    iline = f.readline() #
    while iline:
        if re_code.match(iline):  # code
            __ilines.append(iline)
        elif re_begin.match(iline): # begin block
            __ilines.append(iline)
            _xsplit(re_begin.match(iline).group(1))
        elif re_sblock.match(iline):# single block
            __ilines.append(iline)
            _xsplit(re_sblock.match(iline).group(1))
        elif re_end.match(iline): # end block
            __ilines.append(iline)
        iline = f.readline()
    f.close()

def _gen(filename, opt,\
        _gen_append='0',\
        _gen_nopre='0', _gen_nopost='0',\
        source_name='', _gen_debug='0'):
    
    if not _gen_debug in NO: #yes, debug is ON
        sys.stderr.write('-')
        print "f(%s)s(%s)o(%s)a(%s)npre(%s)npos(%s)bug(%s)"\
            % (filename, source_name, opt,\
                _gen_append, _gen_nopre, _gen_nopost, _gen_debug)
        _xstrip(opt, 1)
    else:
        des = string.split(filename, '/')[-1:][0]
        try:
            dest_time = os.stat(filename)[stat.ST_MTIME]
        except os.error:
            dest_time = 0

        if _force_ or (src_time > dest_time):
            try:
                if _gen_append in NO:
                    g = open(filename, 'w')
                    sys.stderr.write('.')
                else:
                    g = open(filename, 'a')
                    g.write('\n')
                    sys.stderr.write('+')
            except IOError:
                sys.stderr.write('X')
                return

            if _gen_nopre in NO:
                global _kins_pre
                ## expand |preample|
                tmp__pre = string.replace(_kins_pre,"$date",      GEN_DATE)
                tmp__pre = string.replace(tmp__pre, "$c",         '#')
                tmp__pre = string.replace(tmp__pre, "$generator", SELF_INFOR)
                tmp__pre = string.replace(tmp__pre, "$option",    opt)
                tmp__pre = string.replace(tmp__pre, "$dest",      des)
                tmp__pre = string.replace(tmp__pre, "$source",    source_name)		
                g.write(tmp__pre)
##                 if _tex_:
##                     if tmp__pre[-1:] == '\n':
##                         tmp__pre = tmp__pre[:-1]
##                     print "\def\ktvpre{^^A"
##                     print string.replace(tmp__pre, "\n", "^^J^^A\n"),
##                     print "}\usepreamble\ktvpre"
            _xstrip(opt, 0)
            g.writelines(__output)
            if _tex_:
                print "\\generate{\\file{%s}{\\from{%s}{%s}}}"\
                    % (filename, source_name, opt)

            if _gen_nopost in NO:
                global _kins_post
                tmp__pre = _kins_post
                ## expand |posamble|. Only macro "$dest" is allowed.
                tmp__pre = string.replace(_kins_post,"$dest", des)
                tmp__pre = string.replace(tmp__pre, "$c",     "#")
                g.write(tmp__pre)# the tail

            g.close()
            os.utime(filename, (src_time, src_time))
        else:
            sys.stderr.write('|')

def usage():
    sys.stdout.write(\
"""Usage: docstrip [options] file1 file2...
    -e  --exec  code  excute <code> before any job
                      (only the assignments are accepted)
    -g  --gen   expr  generate only files whose names
                      match the regular expression <expr>
    -j  --job   job   specify the kins file named <job>
                      (the extension `.kins' can be omitted)
    -t  --tex         print the (TeX) INS code
    -d  --debug       print debug information (donot generate any file)
    -f  --force       force generatation (skip time check)
    -h  --help        show this message
    -v  --version     print version information and exit
Report:
    .   generate sucessfully
    +   generate in `append' mode
    o   skip file (specified by <kins> file)
    ?   some things wrong occur
    _   opening new source file
    =   importing a kins file
    *   file is already imported. Inogre it!
    X   cannot open file for writting
    E   failed on excuting embeded python code
    |   skip file (the source time <= the destination time)
Within the `--debug' option:
    -   debugging
    n         normal code
    s   single block code
""")

if __name__ == '__main__':
    try:
        opts, args\
            = getopt.getopt(sys.argv[1:],\
            "vdhftg:e:j:",\
            ["debug","tex","job=","version", "gen=","force","help","exec="])
    except:
        sys.stderr.write("Please try |docstrip.py --help|\n")
        sys.exit(1)

    _do_global()

    for o, a in opts:
        if o in ("-h", "--help"):
            usage()
            sys.exit(0)
        elif o in ("-v", "--version"):
            sys.stdout.write("%s\n" % SELF_INFOR)
            sys.exit(0)
        elif o in ("-f", "--force"):
            _force_ = 1
        elif o in ("-t", "--tex"):
            _tex_ = 1
        elif o in ("-d", "--debug"):
            _kins_debug = '1'
        elif o in ("-g", "--gen"):
            _gonly_ = 1
            only_files = re.compile(a)
            sys.stderr.write("  genonly = %s\n" % a)
        elif o in ("-j", "--job"):
            if not string.lower(a[-5:]) == ".kins":
                a = a + ".kins"
            jobnames.append(a)
        elif o in ("-e", "--exec"):
            a = string.split(a, ';')
            for code in a:
                zzz = re_kasg.match(string.strip(code))
                if zzz:
                    var_name = zzz.group(1)
                    var_value= zzz.group(2)
                    exec('_kins_%s="""%s"""' % (var_name,var_value))
                    if not var_name in __kins_vars:
                        __kins_vars.append(var_name)
                    sys.stderr.write("  %s = %s\n" % (var_name,var_value))
                else:
                    sys.stderr.write("  ?code: %s\n" % code)

    for item in args:
        if not string.lower(item[-5:]) == ".kins":
            item = item + ".kins"
        jobnames.append(item)

    if jobnames == []:
        sys.stderr.write("Please try |docstrip.py --help|\n")
        sys.exit(1)
    
    if _tex_:
        print\
"%%%% This file was generated by `%s'\n\
%%%% from the source(s) %s\n\
\\input docstrip.tex" % (SELF_INFOR, jobnames)

    for jobname in jobnames:
        if os.path.isfile(jobname):
            sys.stderr.write("\n<<%s>>\n" % jobname)
            _dokins(jobname)
        else:
            sys.stderr.write("\n<<%s>>: cannot open this file\n" % jobname)
    if _tex_:
        print "\\endbatchfile\n\\endinput\n%% End of file."
    
    sys.stderr.write("(ok)\n")

####################
## END OF PROGRAM ##
####################

## TO DO:

## 2003/12/27:
##  $if, $fi, $else, $elif