Contents of file 'dvlabel/dvlabel.w':
1 % File: dvlabel.w [CWEB source code]
2 % Created: December 5, 2003
3 % Last change: August 10, 2005
4 % Author: Fredrik Jonsson
5 % Description: CWEB source code for the DVLABEL program, which generates
6 % TeX source code for typesetting of labels for digital video
7 % tapes (DV format, typically used for hand-held video camera
8 % recorders). The program is primarily designed to run in
9 % interactive mode, but via command-line parameters it also
10 % supports batch-mode operation.
11 % A feature of the program is also that it is able to compile
12 % the generated TeX source code into PostScript, using the DVIPS
13 % program. (The DVIPS program is copyrighted by Radical Eye
14 % Software, but is typically included in most TeX distributions
15 % under UNIX, Linux, and Microsoft Windows; see the site
16 % http://www.radicaleye.com for further information).
17 % For information on the CWEB programming language, see
18 % http://www.literateprogramming.com.
19 % Compilation: Compile this program by using the enclosed Makefile, or use
20 % the blocks of the Makefile as listed in section five of the
21 % documentation (file dvlabel.ps or dvlabel.pdf). The C source
22 % code (as generated from this CWEB code) conforms to the ANSI
23 % standard for the C programming language (which is equivalent
24 % to the ISO C89 standard for C).
25 %
26 % Copyright (C) 2003-2004, Fredrik Jonsson
27 %
28 \input epsf
29 \def\version{1.6}
30 \def\lastrevdate{August 10, 2005}
31 \font\eightcmr=cmr8
32 \font\tensc=cmcsc10
33 \font\eightcmssq=cmssq8
34 \font\eightcmssqi=cmssqi8
35 \font\twentycmcsc=cmcsc10 at 20 truept
36 \def\dvlabel{{\eightcmr DVLABEL\spacefactor1000}}
37 \def\poincare{{\eightcmr POINCARE\spacefactor1000}}
38 \def\magbragg{{\eightcmr MAGBRAGG\spacefactor1000}}
39 \def\CEE{{\eightcmr C\spacefactor1000}} % The C programming language
40 \def\CWEB{{\eightcmr CWEB\spacefactor1000}} % The CWEB programming language
41 \def\DVIPS{{\eightcmr DVIPS\spacefactor1000}} % The DVIPS program
42 %
43 % Define a handy macro for the list of program revisions.
44 %
45 \newdimen\citemindent \citemindent=80pt
46 \newdimen\citemleftskip \citemleftskip=90pt
47 \def\citem[#1]{\smallbreak\noindent\hbox to 10pt{}%
48 \hbox to\citemindent{\bf #1\hfill}%
49 \hangindent\citemleftskip\ignorespaces}
50
51 \datethis
52
53 @*Introduction.
54 \vskip 120pt
55 \centerline{\twentycmcsc Dvlabel}
56 \vskip 20pt
57 \centerline{Creates TeX source code for typesetting labels for digital
58 video tapes}
59 \vskip 2pt
60 \centerline{(Version \version\ of \lastrevdate)}
61 \vskip 10pt
62 \centerline{Written by Fredrik Jonsson}
63 \vskip 80pt
64 \noindent
65 This \CWEB\footnote{${}^\dagger$}{For information on the \CWEB\ programming
66 language by Donald E.~Knuth, as well as samples of \CWEB\ programs, see
67 {\tt http://www-cs-faculty.stanford.edu/\~\ \kern -5pt knuth/cweb.html}.
68 For general information on literate programming, see
69 {\tt http://www.literateprogramming.com}.}
70 program generates \TeX\ source code for typesetting of labels for digital
71 video tapes (DV format, typically used for hand-held video camera recorders).
72
73 Most people have not heard of the \TeX\ system for typesetting mathematical
74 text, and if they have, they will most probably not use the system for
75 creating things like labels for video tapes.
76 However, the output generated by \TeX\ is in many cases absolutely superior
77 in balance and visual clarity, and in order to benefit from the compactness
78 and beauty of text processed by \TeX\ even for such basic things as labels
79 for video tapes, this program generates the necessary \TeX\ code and even
80 compiles it into printable PostScript.
81
82 The program is primarily designed to run in interactive mode, but via
83 command-line parameters it also supports batch-mode operation.
84 A feature of the program is also that it is able to compile
85 the generated TeX source code into PostScript, using the
86 \DVIPS\ program.\footnote{$\ddagger$}{The \DVIPS\ program is copyrighted
87 by Radical Eye Software, but is typically included in most \TeX\ distributions
88 under UNIX, Linux, and Microsoft Windows; see the site
89 {\tt http://www.radicaleye.com} for further information.}
90 \bigskip
91 \noindent Copyright \copyright\ Fredrik Jonsson, 2003--2005.
92 All rights reserved.
93 \vfill
94
95 @*Revision history of the program.
96 \medskip
97
98 \citem[2003-12-28]{[v.1.0]} {\tt <jonsson@@uni-wuppertal.de>}\hfill\break
99 First properly working version of the \dvlabel\ program.
100 I got the idea of creating this program from the {\tt audio-tape.ps} PostScript
101 code by Jamie Zawinski. This code is a splendid example of how one can
102 write a simple PostScript program with the help of a regular ASCII editor,
103 and by sending the PostScript program to the printer, one gets a neat
104 printout to be used for tape cassette labels, DAT, or video tapes.
105 However, whenever one has a new cassette to be labeled, one has to edit
106 the PostScript source, and for a rookie on PostScript programming this
107 task is somewhat inconvenient.
108 Therefore, I decided to create something similar, but with a standalone program
109 that could be operated either in interactive mode, with the program asking
110 for the specific information to be entered in the label, or in batch mode.
111 However, instead of directly generating PostScript, I decided to go for a
112 language that I know somewhat more in detail, namely plain \TeX, which also
113 has the benefit of being a language which the author, Donald E.~Knuth, has
114 decided to keep fixed in order to ensure future compatibility.
115
116 \citem[2003-12-29]{[v.1.1]} {\tt <jonsson@@uni-wuppertal.de>}\hfill\break
117 Revised the leading blocks (definitions) of the generator of the \TeX-code,
118 in order to have a more clearly structure of the labels. Included the
119 {\tt {\char'134}boxit} example from the \TeX-book to have the face, flap, and spine
120 of the labels neatly structured.
121 Also finished the parsing engine for the address and table of contents
122 fields.
123
124 \citem[2004-11-26]{[v.1.2]} {\tt <fredrik.jonsson@@nmrc.ie>}\hfill\break
125 Added support for supplying \DVIPS\ options via the command line when
126 invoking \dvlabel. In order to parse for an arbitrary number of \DVIPS\ options
127 at the command line, it is important to enclose the list of \DVIPS\ options
128 by quotes, hence forcing the \dvlabel\ program to parse the set of options as
129 one single string of characters. (The quotes are only necessary if the number
130 of \DVIPS\ options are two or more.)
131 Hence, for example, to force \DVIPS\ to generate output pages of US letter
132 format and at a resolution of 720 dpi one could invoke \dvlabel\ with
133 {\tt dvlabel --dvipsopts "-tletter -D720" ...}
134 Also slightly changed the way the input filename is used; now one can specify
135 only the basic filename, to which the \dvlabel\ program now automatically
136 appends the suffix {\tt .dvl}, if necessary.
137 Finally restructured the blocks related to scanning and saving code for
138 individual DV labels, in order to have the structure ready for making
139 the program generally capable of scanning one single file containing
140 an arbitrary number of labels, as for instance if one would keep all
141 records in one single text file.
142
143 \citem[2004-11-27]{[v.1.3]} {\tt <fredrik.jonsson@@nmrc.ie>}\hfill\break
144 The \dvlabel\ program now parses multiple label records from the same input
145 file. Also added the useful feature of crop marks in the generated \TeX\ output
146 of the program. In its current state, the program only generates labels in one
147 single horizontal column; this is something that I in the future versions will
148 change into a $[3\times3]$ array of labels, as soon as I get the {\tt\\vbox}
149 and {\tt\\hbox} statements of the {\tt\\boxit} definition right.
150
151 \citem[2004-12-28]{[v.1.4]} {\tt <fredrik.jonsson@@nmrc.ie>}\hfill\break
152 Added the {\tt --headline} and {\tt --linethick} options. Fixed a bug in
153 the page output, which previously caused \TeX\ to complain about vertical
154 underfill of the generated pages.
155
156 \citem[2005-01-01]{[v.1.5]} {\tt <fredrik.jonsson@@nmrc.ie>}\hfill\break
157 Added the {\tt --cropmark} and {\tt --edgeseparation} options. Also fixed a bug
158 in the vertical label dimensions. Added the |log()| way of displaying log and
159 error messages.
160
161 \citem[2005-08-10]{[v.1.6]} {\tt <fj@@phys.soton.ac.uk>}\hfill\break
162 Back in Southampton with my family after a hot summer. Wrote the code for
163 the |strip_away_path()| routine originally for the \poincare\ program and
164 immediately decided to adopt the code also into the \dvlabel\ and \magbragg\
165 programs in order to finally solve the problem with long path strings that
166 appear in the program name string whenever poincare is called with an explicit
167 path specified at the command line. The call to the |strip_away_path()| routine
168 is located in the beginning of the block for command line parsing.
169
170 @*Compiling the source code. The program is written in \CWEB, generating
171 ANSI-C conforming source code and documentation as \TeX-source, and is to
172 be compiled using the enclosed Makefile, leaving an executable
173 file {\tt dvlabel}\footnote{$\dagger$}{On platforms running Windows NT,
174 Windows 2000, or any other operating system by Microsoft, the executable
175 file will instead automatically be called {\tt dvlabel.exe}.} and a
176 PostScript file {\tt dvlabel.ps} (the document you currently are reading),
177 which contains the full documentation of the program:
178 \bigskip
179 {\obeyspaces\obeylines\tt
180 ~ \#
181 ~ \# Makefile designed for use with ctangle, cweave, gcc, and plain TeX.
182 ~ \#
183 ~ \# Copyright (C) 2003, Fredrik Jonsson <jonsson@@uni-wuppertal.de>
184 ~ \#
185 ~ CTANGLE = ctangle
186 ~ CC = gcc
187 ~ CCOPTS = -O2 -Wall -ansi -pedantic \# follow ISO C89 (ANSI) strictly
188 ~ LNOPTS = -lm
189 ~ CWEAVE = cweave
190 ~ TEX = tex
191 ~ DVIPS = dvips
192 ~ DVIPSOPT = -ta4 -D1200
193 ~ ~
194 ~ all: dvlabel.exe dvlabel.ps
195 ~ ~
196 ~ dvlabel.exe: dvlabel.o \# generate the executable file
197 ~ \$(CC) \$(CCOPTS) -o dvlabel dvlabel.o \$(LNOPTS)
198 ~ ~
199 ~ dvlabel.o: dvlabel.c \# generate the object file
200 ~ \$(CC) \$(CCOPTS) -c dvlabel.c
201 ~ ~
202 ~ dvlabel.c: dvlabel.w \# generate C code from the CWEB source
203 ~ \$(CTANGLE) dvlabel
204 ~ ~
205 ~ dvlabel.ps: dvlabel.dvi \# generate the PostScript documentation
206 ~ \$(DVIPS) \$(DVIPSOPT) dvlabel.dvi -o dvlabel.ps
207 ~ ~
208 ~ dvlabel.dvi: dvlabel.tex \# generate the device-independent documentation
209 ~ \$(TEX) dvlabel.tex
210 ~ ~
211 ~ dvlabel.tex: dvlabel.w \# generate plain TeX code from the CWEB source
212 ~ \$(CWEAVE) dvlabel
213 ~ ~
214 ~ clean:
215 ~ ~ -rm -Rf *.c *.o *.exe
216 ~ ~ -rm -Rf *.tex *.aux *.log *.toc *.idx *.scn *.dvi}
217 \bigskip
218
219 @*Running the program. The program is entirely controlled by the command
220 line options supplied when invoking the program.
221 To start the program in interactive mode, simply run {\tt dvlabel} from
222 the command line, without any command line options.
223 \medskip
224 \noindent{\bf Example I:} In the following excerpt
225 from an interactive terminal session, where a leading asterisk ({\tt *})
226 in a line indicates the user-supplied input to the program, a DV label is
227 generated as Encapsulated PostScript, stored in a file named {\tt fig.eps}.
228 \bigskip
229 {\obeyspaces\obeylines\tt
230 ~ ~[dvlabel> dvlabel -c -e -o fig
231 ~ ~This is dvlabel, Version 1.4
232 ~ ~Specify table of contents of the DV tape
233 ~ ~[Enter text and finish with single dot on blank line]:
234 ~ ~* Table of contents
235 ~ ~* This is line number one
236 ~ ~* This is line number two
237 ~ ~* This is line number three
238 ~ ~* .
239 ~ ~Specify time stamp of DV tape. This is typically
240 ~ ~the last date that appears as time stamp in the
241 ~ ~recorded tape. [Press enter to use the current date]
242 ~ ~* Monday 29/12/2003
243 ~ ~Specify title of the DV tape [Press enter to leave blank title]:
244 ~ ~* Beavis and Butthead
245 ~ ~Specify author of the DV tape [Press enter to leave blank]:
246 ~ ~* Fredrik Jonsson
247 ~ ~Specify address of author of the DV tape
248 ~ ~[Enter text and finish with single dot on blank line]:
249 ~ ~* Storgatan 77
250 ~ ~* SE-47111 Sunne, Sweden
251 ~ ~* .
252 ~ ~Specify email of author of the DV tape [Press enter to leave blank]:
253 ~ ~* hmv@@hotmail.com
254 }
255 \bigskip
256 The generated DV label {\tt fig.eps} looks like this:
257 \bigskip
258 \centerline{\epsfxsize=62.56mm\epsfbox{fig.eps}}
259 \vfill\eject
260 \noindent
261 In this example, the {\tt -c} command line option specifies that the program
262 should compile the generated \TeX\ code, {\tt -e} that it also should attempt
263 to generate the output as Encapsulated PostScript, and {\tt -o fig}
264 that the generated files all should have the base name ``{\tt fig}'',
265 that is to say, the program will use {\tt fig.tex} for the
266 generated \TeX-code, {\tt fig.dvi}
267 for the generated device-independent (DVI) output, and {\tt fig.eps} for
268 the generated Encapsulated PostScript (EPS) image of the DV label.
269 The command for invoking the \dvlabel\ program can equivalently be written in
270 a more extensive form as {\tt dvlabel --compile --eps --outputfile fig}.
271
272 The \TeX-code that the program generates (from which the Encapsulated
273 PostScript subsequently is generated) is stored in the file {\tt fig.tex},
274 which contains
275 \bigskip
276 {\obeylines\obeyspaces\tt
277 ~ ~\% File: fig.tex
278 ~ ~\% TeX code automatically generated by dvlabel, v.1.4,
279 ~ ~\% Mon Dec 29 15:46:36 2003
280 ~ ~\% Copyright (C) Fredrik Jonsson, 2003
281 ~ ~\%
282 ~ ~{\char'134}font{\char'134}eightcmssqeight=cmssq8
283 ~ ~{\char'134}font{\char'134}tencmssqten=cmssq8 at 10 truept
284 ~ ~{\char'134}font{\char'134}defaultfacefont=cmtt8
285 ~ ~{\char'134}font{\char'134}defaultflapfont=cmtt8
286 ~ ~{\char'134}def{\char'134}monthname{{\char'134}ifcase{\char'134}month\%
287 ~ ~ {\char'134}or Jan{\char'134}or Feb{\char'134}or Mar{\char'134}or
288 Apr{\char'134}or May{\char'134}or Jun\%
289 ~ ~ {\char'134}or Jul{\char'134}or Aug{\char'134}or Sep{\char'134}or
290 Oct{\char'134}or Nov{\char'134}or Dec\%
291 ~ ~ {\char'134}fi}
292 ~ ~{\char'134}def{\char'134}fullmonthname{{\char'134}ifcase{\char'134}month\%
293 ~ ~ {\char'134}or January{\char'134}or February{\char'134}or
294 March{\char'134}or April\%
295 ~ ~ {\char'134}or May{\char'134}or June{\char'134}or July{\char'134}or
296 August{\char'134}or September
297 ~ ~ {\char'134}or October{\char'134}or November{\char'134}or
298 December{\char'134}fi}
299 ~ ~{\char'134}def{\char'134}today{{\char'134}fullmonthname{\char'134}space%
300 {\char'134}number{\char'134}day,\%
301 ~ ~ {\char'134}space{\char'134}number{\char'134}year}
302 ~ ~{\char'134}def{\char'134}timestamp{Monday 29/12/2003}
303 ~ ~{\char'134}def{\char'134}title{Beavis and Butthead}
304 ~ ~{\char'134}def{\char'134}author{Fredrik Jonsson}
305 ~ ~{\char'134}def{\char'134}email{hmv@@hotmail.com}
306 ~ ~{\char'134}nopagenumbers
307 ~ ~{\char'134}newdimen{\char'134}facewidth
308 ~ ~{\char'134}newdimen{\char'134}faceheight
309 ~ ~{\char'134}newdimen{\char'134}spineheight
310 ~ ~{\char'134}newdimen{\char'134}flapheight
311 ~ ~{\char'134}newdimen{\char'134}edgeseparation
312 ~ ~{\char'134}facewidth=60mm
313 ~ ~{\char'134}faceheight=40mm
314 ~ ~{\char'134}spineheight=12mm
315 ~ ~{\char'134}flapheight=20mm
316 ~ ~{\char'134}edgeseparation=1pt
317 ~ ~{\char'134}def{\char'134}boxit\#1{{\char'134}vbox{{\char'134}hrule%
318 {\char'134}hbox{\%
319 ~ ~ {\char'134}vrule{\char'134}kern1pt{\char'134}vbox{{\char'134}kern1pt\#1%
320 {\char'134}kern1pt}\%
321 ~ ~{\char'134}kern1pt{\char'134}vrule}{\char'134}hrule}}
322 ~ ~{\char'134}parindent 0pt
323 }
324 \vfill\eject
325 {\obeylines\obeyspaces\tt
326 ~ ~
327 ~ ~\% Define the outline of the face of the label
328 ~ ~{\char'134}setbox1={\char'134}hbox to {\char'134}facewidth{{\%
329 ~ ~ {\char'134}vbox to {\char'134}faceheight{\%
330 ~ ~ {\char'134}hbox{{\char'134}defaultfacefont{\char'134}timestamp%
331 {\char'134}hfil}\%
332 ~ ~ {\char'134}vskip -3pt{\char'134}hbox{{\char'134}defaultfacefont
333 Table of contents{\char'134}hfil}\%
334 ~ ~ {\char'134}vskip -3pt{\char'134}hbox{{\char'134}defaultfacefont
335 This is line number one{\char'134}hfil}\%
336 ~ ~ {\char'134}vskip -3pt{\char'134}hbox{{\char'134}defaultfacefont
337 This is line number two{\char'134}hfil}\%
338 ~ ~ {\char'134}vskip -3pt{\char'134}hbox{{\char'134}defaultfacefont
339 This is line number three{\char'134}hfil}\%
340 ~ ~ {\char'134}vfil}}{\char'134}hfil}
341 ~ ~
342 ~ ~\% Define the outline of the spine of the label
343 ~ ~{\char'134}setbox2={\char'134}hbox to {\char'134}facewidth{{\%
344 ~ ~ {\char'134}vbox to {\char'134}spineheight{\%
345 ~ ~ {\char'134}hbox{{\char'134}bf{\char'134}timestamp{\char'134}hfil}\%
346 ~ ~ {\char'134}hbox{{\char'134}bf{\char'134}title{\char'134}hfil}\%
347 ~ ~ {\char'134}vfil}}{\char'134}hfil}
348 ~ ~
349 ~ ~\% Define the outline of the flap of the label
350 ~ ~{\char'134}setbox3={\char'134}hbox to {\char'134}facewidth{{\%
351 ~ ~ {\char'134}vbox to {\char'134}flapheight{\%
352 ~ ~ {\char'134}hbox{{\char'134}defaultflapfont Digital Video by
353 {\char'134}author{\char'134}hfil}\%
354 ~ ~ {\char'134}vskip -3pt{\char'134}hbox{{\char'134}defaultflapfont
355 Storgatan 77{\char'134}hfil}\%
356 ~ ~ {\char'134}vskip -3pt{\char'134}hbox{{\char'134}defaultflapfont
357 SE-47111 Sunne, Sweden{\char'134}hfil}\%
358 ~ ~ {\char'134}vskip -3pt{\char'134}hbox{{\char'134}defaultflapfont \%
359 ~ ~ <{\char'134}email>{\char'134}hfil}\%
360 ~ ~ {\char'134}vfil}}{\char'134}hfil}
361 ~ ~
362 ~ ~{\char'134}def{\char'134}dvlabel{{\char'134}boxit{{\char'134}boxit%
363 {{\char'134}box1}\%
364 ~ ~ {\char'134}vskip{\char'134}edgeseparation{\char'134}boxit%
365 {{\char'134}box2}\%
366 ~ ~ {\char'134}vskip{\char'134}edgeseparation{\char'134}%
367 boxit{{\char'134}box3}}}
368 ~ ~
369 ~ ~{\char'134}dvlabel
370 ~ ~
371 ~ ~{\char'134}bye
372 }
373 \vfill\eject
374 \noindent{\bf Example II:}
375 Another way of using the program is in batch mode, where the input instead
376 is read from a text file.
377 In the following example, the file named {\tt fig.asc} contains the
378 following text (compare with the interactive session on the previous pages):
379 \bigskip
380 {\obeyspaces\obeylines\tt
381 ~ ~Table of contents
382 ~ ~This is line number one
383 ~ ~This is line number two
384 ~ ~This is line number three
385 ~ ~.
386 ~ ~Monday 29/12/2003
387 ~ ~Beavis and Butthead
388 ~ ~Fredrik Jonsson
389 ~ ~Storgatan 77
390 ~ ~SE-47111 Sunne, Sweden
391 ~ ~.
392 ~ ~hmv@@hotmail.com
393 }
394 \bigskip
395 \noindent
396 When the \dvlabel\ program is launched with the above file specified as
397 the input to read, via the command\footnote{$\dagger$}{In similar to
398 the previous example, this command for invoking the \dvlabel\ program
399 can similarly written in a more extensive form as {\tt dvlabel --compile
400 --eps --inputfile fig.asc --outputfile fig}.}
401 \bigskip
402 {\obeyspaces\obeylines\tt
403 ~ ~[dvlabel> dvlabel -c -e -i fig.asc -o fig
404 }
405 \bigskip
406 \noindent
407 the same output as in the previous example will be generated.
408
409 @*The main program. Here follows the general outline of the main program.
410
411 @c
412 #include <time.h>
413 #include <sys/time.h>
414 #include <stdio.h>
415 #include <stdarg.h>
416 #include <stdlib.h>
417 #include <string.h>
418 #include <ctype.h>
419
420 #define VERSION "1.6" /* Program revision */
421 #define DEFAULT_DVIPSOPTS "-ta4 -D1200" /* Default DVIPS options */
422 #define DEFAULT_LINETHICKNESS (0.5) /* Default line thickness in pt */
423 #define DEFAULT_CROPLINETHICKNESS (0.15) /* Crop line thickness in pt */
424 #define DEFAULT_EDGESEPARATION (1.0)
425 #define MAXCHAR (128) /* Maximum allowed number of characters on each line */
426
427 #define SUCCESS (0) /* Return code for successful program termination */
428 #define FAILURE (1) /* Return code for unsuccessful program termination */
429
430 #define INSTREAM (infile_specified?infile:stdin)
431 #define OUTSTREAM (outfile_specified?outfile:stdout)
432
433 #define log(...) log_printf(__func__, __VA_ARGS__)
434
435 @<Global variables@>@;
436 @<Subroutines@>@;
437
438 int main(int argc, char *argv[])
439 {
440 @<Local variables@>@;
441 @<Parse command line@>@;
442 @<Display banner@>@;
443 @<Open files for reading@>@;
444 @<Open files for writing@>@;
445 @<Save preamble source code@>@;
446 num_labels=0;
447 while (newlabel(INSTREAM)) {
448 num_labels++;
449 @<Scan text lines of one label from input stream@>@;
450 if (num_labels==1) {
451 if (generate_crop_marks) {
452 @<Write vertical crop marks with width measure@>@;
453 @<Write horizontal crop marks with height measure@>@;
454 }
455 }
456 @<Save label source code@>@;
457 if (num_labels==2) {
458 if (generate_crop_marks) {
459 @<Write horizontal crop marks with height measure@>@;
460 }
461 }
462 if (num_labels==num_labels_per_page) {
463 if (generate_crop_marks) {
464 @<Write horizontal crop marks with height measure@>@;
465 @<Write vertical crop marks with width measure@>@;
466 }
467 @<Close output page@>@;
468 num_labels=0;
469 }
470 }
471 @<Save closing source code@>@;
472 @<Close files@>@;
473 @<Compile source code@>@;
474 return(SUCCESS);
475 }
476
477 @ Declaration of global variables. The only global variables allowed in
478 my programs are |optarg|, which is the string of characters that specified
479 the call from the command line, and |progname|, which simply is the string
480 containing the name of the program, as it was invoked from the command line.
481
482 @<Glob...@>=
483 extern char *optarg;
484 char *progname;
485
486 @ Declarations of subroutines used by the program.
487
488 @<Subroutines@>=
489 @<Routine for logging and error messaging@>@;
490 @<Routine for displaying help message@>@;
491 @<Scan for beginning of new label@>@;
492 @<Routine for removing preceding path of filenames@>@;
493
494 @ The |void log_printf(const char *function_name,const char *format, ...)|
495 routine writes formatted entries to standard output, displaying time and
496 calling routine in a coherent manner. Notice that although the |log_printf()|
497 routine is the one which performs the actual messaging, the |log()| macro
498 (defined in the header file) is the preferred way of accessing this routine,
499 as it provides a more compact notation and automatically takes care of supplying
500 the reference to the name of the calling function.
501
502 Also notice that the |const char| type of the last two input pointer arguments
503 here is absolutely essential in order to pass strict pedantic compilation with
504 GCC.
505
506 The routine accepts two input parameters. First, |function_name| which should
507 be the name of the calling function. This is to ensure that any displayed
508 error messages are properly matched to the issuing routines. Notice, however,
509 that the |log()| macro (which is the preferred way of displaying error messages)
510 automatically takes care of supplying the proper function name.
511 Second, |format|, which simply is the format and message string to be
512 displayed, formatted in the \CEE-standard |printf()| or |fprintf()| syntax.
513
514 @<Routine for logging and error messaging@>=
515 void log_printf(const char *function_name, const char *format, ...) {
516 va_list args;
517 time_t time0;
518 struct tm lt;
519 struct timeval tv;
520 char logentry[1024];
521
522 gettimeofday(&tv, NULL);
523 time(&time0);
524 lt = *localtime(&time0);
525 sprintf(logentry, "%02u%02u%02u %02u:%02u:%02u.%03d ",
526 lt.tm_year-100, lt.tm_mon+1, lt.tm_mday,
527 lt.tm_hour, lt.tm_min, lt.tm_sec, tv.tv_usec/1000);
528 sprintf(logentry+strlen(logentry),"(%s) ",function_name);
529 va_start(args, format); /* Initialize args by the |va_start()| macro */
530 vsprintf(logentry+strlen(logentry), format, args);
531 va_end(args); /* Terminate the use of args by the |va_end()| macro */
532 sprintf(logentry+strlen(logentry), "\n"); /* Always append newline */
533 fprintf(stdout, "%s", logentry);
534 return;
535 }
536
537 @ Routines for displaying help message.
538
539 @<Routine for displaying help message@>=
540 @<Routine for displaying a single line of the help message@>@;
541 void showsomehelp(void) {
542 hl("Usage: %s [options]",progname);
543 hl("When invoked without any command line options, this program enters");
544 hl("interactive mode.");
545 hl("Options:");
546 hl(" -i, --inputfile <str>");
547 hl(" Specifies the file where to read the label text strings, entered in");
548 hl(" a format corresponding to the input order as would have been");
549 hl(" entered in interactive mode.");
550 hl(" -o, --outputfile <str>");
551 hl(" Specifies the file where to save the generated TeX source code for");
552 hl(" the label. whenever this option is omitted, the generated source");
553 hl(" code will be written to standard terminal output instead. Notice");
554 hl(" that the name specified using this option is used as the *base");
555 hl(" name* for the generated output; this means that the TeX file");
556 hl(" automatically will get .tex as suffix, the DVIfile .dvi, etc.");
557 hl(" For example, if you want to have your TeX output stored into a file");
558 hl(" named, say, 'foo.tex', just specify '-o foo'.");
559 hl(" -H, --headline");
560 hl(" Toggle display of generation time and input source in page header");
561 hl(" of the generated TeX code. Default: off");
562 hl(" -C, --cropmarks");
563 hl(" Toggle display of crop marks (alignment marks) in the generated TeX");
564 hl(" code. Default: off");
565 hl(" -t, --linethick <f>");
566 hl(" Use linethickness of <f> typographic points in generating the boxes");
567 hl(" of the label. (One point, or pt, equals to 1/72.27 inch.)");
568 hl(" -s, --edgeseparation <f>");
569 hl(" Insert extra space of <f> typographic points between the text boxes");
570 hl(" at the folded edges of the label. This is useful when, for example,");
571 hl(" thick paper is used. By changing the line thickness, the internal");
572 hl(" margins of the label are also changed, since the inner edge-to-edge");
573 hl(" distance between the lines of the inner and outer boxes are linked");
574 hl(" to be twice the value of the line thickness. The correction of");
575 hl(" inner bounding boxes of the label text is automatically adjusted so");
576 hl(" as to ensure that the overall outer dimensions of the label are");
577 hl(" unchanged.");
578 hl(" -c, --compile");
579 hl(" Try to compile the generated TeX code. This requires DVIPS to be");
580 hl(" installed on your system, see www.radicaleye.com for further info.");
581 hl(" -e, --eps");
582 hl(" When compiling the generated TeX code, generate Encapsulated");
583 hl(" PostScript (EPS) instead of the default regular PostScript.");
584 hl(" -d, --dvipsopts <str>");
585 hl(" When compiling the generated TeX code, use <str> as options to be");
586 hl(" supplied to DVIPS. In order to parse for an arbitrary number of");
587 hl(" DVIPS options at the command line, it is important to enclose the");
588 hl(" list of DVIPS options by quotes. Hence, for example, to force DVIPS");
589 hl(" to generate output pages of US letter format and at a resolution of");
590 hl(" 720 dpi one could invoke DVLABEL with");
591 hl(" dvlabel --dvipsopts \"-tletter -D720\"");
592 hl(" The quotes are only necessary if the number of DVIPS options are");
593 hl(" two or more. Default: -D1200 -ta4 (1200 DPI on A4 paper).");
594 hl(" -v, --verbose");
595 hl(" Toggle verbose mode. Default: off");
596 hl(" -h, --help");
597 hl(" Display this help message and exit clean.");
598 hl("\nCopyright (C) 2003-2011 Fredrik Jonsson <http://jonsson.eu>");
599 }
600
601 @ In order to simplify the messaging, the |hl(const char *format, ...)| routine
602 acts as a simple front-end merely for compactifying the code by successive
603 calls to |hl(...)| rather than the full |fprintf(stderr, ...)|, still
604 maintaining all the functionality of string formatting in the regular
605 |printf()| or |fprintf()| syntax.
606
607 @<Routine for displaying a single line of the help message@>=
608 void hl(const char *format, ...) {
609 va_list args;
610 char line[1024];
611
612 va_start(args, format); /* Initialize args by the |va_start()| macro */
613 vsprintf(line, format, args);
614 va_end(args); /* Terminate the use of args by the |va_end()| macro */
615 sprintf(line+strlen(line), "\n"); /* Always append newline */
616 fprintf(stdout, "%s", line);
617 return;
618 }
619
620 @ Scan the input stream for a statement on what to do next, that is to say,
621 either to start generating a new label (if the character `n' is present, in
622 which case the |newlabel| routine returns 1) or quit the program (if the
623 character `q' is present, in which case the |newlabel| routine returns 0).
624 The |newlabel| routine also takes care of scanning away any trailing blanks
625 or other characters from the input stream until a carriage return character
626 is found, also removing this before return.
627
628 @<Scan for beginning of new label@>=
629 short newlabel(FILE *instream) {
630 char ch;
631 fprintf(stdout,"Create new label record or quit?\n");
632 fprintf(stdout,"['n'=new label / 'q'=quit]:\n");
633 fprintf(stdout,"**");
634 while((ch=fgetc(instream))==' '); /* get rid of leading blanks */
635 if (ch=='n') {
636 while((ch=fgetc(instream))!='\n'); /* get rid of trailing characters */
637 return(1);
638 } else if (ch=='q') {
639 while((ch=fgetc(instream))!='\n'); /* get rid of trailing characters */
640 return(0);
641 } else {
642 log("%s: Error: Unrecognized input stream control character '%c'.\n",
643 progname,ch);
644 exit(FAILURE);
645 }
646 }
647
648 @ Routines for removing preceding path of filenames.
649 In this block all routines related to removing preceding path strings go.
650 Not really fancy programming, and no contribution to any increase of numerical
651 efficiency or precision; just for the sake of keeping a tidy terminal output
652 of the program. The |strip_away_path()| routine is typically called when
653 initializing the program name string |progname| from the command line string
654 |argv[0]|, and is typically located in the blocks related to parsing of the
655 command line options.
656 The |strip_away_path()| routine takes a character string |filename| as
657 argument, and returns a pointer to the same string but without any
658 preceding path segments.
659
660 @<Routine for removing preceding path of filenames@>=
661 @<Routine for checking for a valid path character@>@;
662 char *strip_away_path(char filename[]) {
663 int j,k=0;
664 while (pathcharacter(filename[k])) k++;
665 j=(--k); /* this is the uppermost index of the full path+file string */
666 while (isalnum((int)(filename[j]))) j--;
667 j++; /* this is the lowermost index of the stripped file name */
668 return(&filename[j]);
669 }
670
671 @ In this program, valid path characters are any alphanumeric character or
672 `\.{.}', `\.{/}', `\.{\\}', `\.{\_}', `\.{-}', or `\.{+}'.
673
674 @<Routine for checking for a valid path character@>=
675 short pathcharacter(int ch) {
676 return(isalnum(ch)||(ch=='.')||(ch=='/')||(ch=='\\')||(ch=='_')||
677 (ch=='-')||(ch=='+'));
678 }
679
680 @*Declaration of local variables of the main program.
681 Here |num_labels| is a counter that is used for determining whenever a page
682 brake in the generated \TeX\ code is to appear, in order to give a nice output
683 with a $[3\times1]$ array of labels.
684
685 @<Local variables@>=
686 time_t now=time(NULL);
687 long j,k,n,num_address_lines,num_toc_lines,num_labels,num_labels_per_page=4;
688 int no_arg,tmpch;
689 FILE *infile=NULL,*outfile=NULL;
690 char inputfilename[MAXCHAR]="",outputfilename[MAXCHAR]="",tmpstr[MAXCHAR];
691 char dvipsopts[MAXCHAR]=DEFAULT_DVIPSOPTS;
692 char timestamp[MAXCHAR]="\today",title[MAXCHAR]="";
693 char author[MAXCHAR]="",email[MAXCHAR]="";
694 char address[10*MAXCHAR]="",toc[50*MAXCHAR]="";
695 short done,verbose=0,compile=0,eps_output=0;
696 short headline=1,generate_crop_marks=1;
697 short infile_specified=0,outfile_specified=0,dvipsopts_specified=0;
698 float linethickness=DEFAULT_LINETHICKNESS;
699 float clthick=DEFAULT_CROPLINETHICKNESS;
700 float edgeseparation=DEFAULT_EDGESEPARATION;
701 float facewidth,faceheight,spineheight,flapheight;
702 float ifacewidth,ifaceheight,ispineheight,iflapheight;
703
704
705 @*Parsing command line options. All input parameters are passed to the
706 program through command line options and arguments to the program.
707 The syntax of command line options is listed whenever the program is invoked
708 with the {\tt --help} option at startup, or whenever an error occurs in the
709 input.
710
711 @<Parse command line@>=
712 {
713 progname=strip_away_path(argv[0]);
714 no_arg=argc;
715 while(--argc) {
716 if(!strcmp(argv[no_arg-argc],"-o") ||
717 !strcmp(argv[no_arg-argc],"--outputfile")) {
718 --argc;
719 strcpy(outputfilename,argv[no_arg-argc]);
720 outfile_specified=1;
721 } else if(!strcmp(argv[no_arg-argc],"-i") ||
722 !strcmp(argv[no_arg-argc],"--inputfile")) {
723 --argc;
724 strcpy(inputfilename,argv[no_arg-argc]);
725 infile_specified=1;
726 } else if(!strcmp(argv[no_arg-argc],"-v") ||
727 !strcmp(argv[no_arg-argc],"--verbose")) {
728 verbose=(verbose?0:1);
729 } else if(!strcmp(argv[no_arg-argc],"-h") ||
730 !strcmp(argv[no_arg-argc],"--help")) {
731 showsomehelp();
732 exit(SUCCESS);
733 } else if(!strcmp(argv[no_arg-argc],"-H") ||
734 !strcmp(argv[no_arg-argc],"--headline")) {
735 headline=(headline?0:1);
736 } else if(!strcmp(argv[no_arg-argc],"-C") ||
737 !strcmp(argv[no_arg-argc],"--cropmarks")) {
738 generate_crop_marks=(generate_crop_marks?0:1);
739 } else if(!strcmp(argv[no_arg-argc],"-t") ||
740 !strcmp(argv[no_arg-argc],"--linethick")) {
741 --argc;
742 if (!sscanf(argv[no_arg-argc],"%f",&linethickness)) {
743 log("Error in linethickness argument.");
744 exit(1);
745 }
746 } else if(!strcmp(argv[no_arg-argc],"-s") ||
747 !strcmp(argv[no_arg-argc],"--edgeseparation")) {
748 --argc;
749 if (!sscanf(argv[no_arg-argc],"%f",&edgeseparation)) {
750 log("Error in edgeseparation argument.");
751 exit(1);
752 }
753 } else if(!strcmp(argv[no_arg-argc],"-c") ||
754 !strcmp(argv[no_arg-argc],"--compile")) {
755 compile=(compile?0:1);
756 } else if(!strcmp(argv[no_arg-argc],"-e") ||
757 !strcmp(argv[no_arg-argc],"--eps")) {
758 eps_output=(eps_output?0:1);
759 } else if(!strcmp(argv[no_arg-argc],"-d") ||
760 !strcmp(argv[no_arg-argc],"--dvipsopts")) {
761 --argc;
762 strcpy(dvipsopts,argv[no_arg-argc]);
763 dvipsopts_specified=1;
764 } else {
765 log("Error: Unknown option '%s'.",argv[no_arg-argc]);
766 showsomehelp();
767 exit(FAILURE);
768 }
769 }
770 if (verbose && !outfile_specified) {
771 fprintf(stdout,
772 "You have specified verbose mode without any specification of\n"
773 "a file where to save the generated TeX source code. This means\n"
774 "that any program comments that appear, due to the verbose mode,\n"
775 "will be mixed with the source code. It is highly recommended that\n"
776 "you either turn off verbose mode or specify a file where to save\n"
777 "the generated output (using the -o or --outputfile option).\n");
778 fprintf(stdout,
779 "In order to make a clean output, the TeX code is separately\n"
780 "enclosed in the blocks below.\n");
781 }
782 if (verbose && dvipsopts_specified) {
783 fprintf(stdout,"Specified options for later use with DVIPS: ");
784 fprintf(stdout,"%s\n",dvipsopts);
785 }
786 }
787
788 @ Display a banner at start-up of the program.
789
790 @<Display banner@>=
791 {
792 fprintf(stdout,"This is %s, Version %s\n",progname,VERSION);
793 }
794
795 @*Opening and closing files for data output.
796
797 @ Open files for reading. In order to read the text to typeset from an external
798 file rather than the default standard input stream {\tt stdin}, the name of the
799 input file is specified with the {\tt -i} or {\tt --inputfile} command line
800 options.
801 If the filename as specified on the command line does not exist, then the
802 program will instead try to open a file with the suffix {\tt .dvl} concatenated
803 to the name. This way, the program will accept short-hand filenames as well, in
804 a way analogous to the input syntax rules of, for example, the \TeX\ program.
805 If no input file can be opened, an error message is displayed and the program
806 will exit with return value |FAILURE|.
807
808 @<Open files for reading@>=
809 {
810 if (infile_specified) {
811 if ((infile=fopen(inputfilename,"r")) == NULL) {
812 if ((infile=fopen(strcat(inputfilename,".dvl"),"r")) == NULL) {
813 log("Could not open file %s for reading!",inputfilename);
814 exit(FAILURE);
815 }
816 }
817 fseek(infile,0L,SEEK_SET);
818 if (verbose) {
819 log("Opened input file %s for reading.",inputfilename);
820 }
821 } else {
822 if (verbose)
823 log("No input filename specified (Entering interactive mode).");
824 }
825 }
826
827 @ Open files for writing.
828
829 @<Open files for writing@>=
830 {
831 if (outfile_specified) {
832 sprintf(tmpstr,"%s.tex",outputfilename);
833 if ((outfile=fopen(tmpstr,"w")) == NULL) {
834 log("Could not open file %s for writing!",tmpstr);
835 exit(FAILURE);
836 }
837 fseek(outfile,0L,SEEK_SET);
838 if (verbose) {
839 log("Opened output file %s for writing.",outputfilename);
840 }
841 } else {
842 if (verbose) {
843 log("No output filename specified.");
844 log("Will write generated TeX output to standard terminal output.");
845 }
846 }
847 }
848
849 @ Close all open files.
850
851 @<Close files@>=
852 {
853 if (infile_specified) fclose(infile);
854 if (outfile_specified) fclose(outfile);
855 }
856
857 @*Reading input as supplied by the user.
858
859 @ Parsing the input as supplied by the user. When reading the input, the
860 \dvlabel\ program makes use of either the |stdin| stream (in the case of
861 interactive mode), or the file pointed out by the |infile| pointer (in the
862 case of processing of an input text file).
863 In the latter case, the syntax of the supplied file is identical to the
864 syntax as if operating the program in interactive mode, with every newline
865 character ({\tt /n}) interpreted as an end-of-line of a corresponding
866 interactive input.
867
868 Example: [TO BE INSERTED]
869
870 As the individual lines of text generally contain different number of
871 characters, the feedline character {\tt /n} of standard \CEE\ is throughout
872 the program used to keep track of the end of line. (This is more convenient
873 than keeping track of the indvidual line widths in, for example, and array
874 of integers.)
875
876 @<Scan text lines of one label from input stream@>=
877 {
878 @<Read table of contents@>@;
879 @<Read time stamp@>@;
880 @<Read title@>@;
881 @<Read author name@>@;
882 @<Read address@>@;
883 @<Read email address@>@;
884 }
885
886 @ Parse for the table of contents of the tape.
887 The syntax for specifying the table of contents is similar to that of the
888 address, with arbitrary number of lines of text. The input is ended by
889 a single dot on a new line, in similar to the way of entering, for example,
890 email messages in terminal mode using the basic engine of {\tt sendmail} on
891 regular UNIX and Linux systems.
892
893 @<Read table of contents@>=
894 {
895 fprintf(stdout,"Specify table of contents of the DV tape\n");
896 fprintf(stdout,"[Enter text and finish with single dot on blank line]:\n");
897 done=0;
898 n=0;
899 num_toc_lines=0;
900 while (!done) {
901 fprintf(stdout,"**");
902 while ((tmpch=fgetc(INSTREAM))==' '); /* Get rid of leading blanks */
903 ungetc(tmpch,INSTREAM);
904 k=0;
905 while ((tmpstr[k++]=fgetc(INSTREAM))!='\n'); /* Read line */
906 if (k>1) { /* If more text than just spaces and a linefeed character */
907 if ((tmpstr[0]=='.')&&(tmpstr[1]=='\n')) {
908 done=1;
909 } else {
910 for (j=0;j<k;j++) toc[n+j]=tmpstr[j];
911 if (1==0) toc[n+j]='\n';
912 n=n+j; /* Keep track of last index of the |toc| array */
913 num_toc_lines++;
914 }
915 } else { /* If just spaces and a linefeed character */
916 toc[n]='\n'; /* Blank line of table-of-contents field */
917 }
918 }
919 if (verbose) {
920 fprintf (stdout,"%s: Counted %ld number of table-of-contents lines.\n",
921 progname,num_toc_lines);
922 fprintf(stdout,"Table of contents:\n");
923 n=0;
924 for (k=1;k<=num_toc_lines;k++) {
925 for (j=n;toc[j]!='\n';j++) fprintf(stdout,"%c",toc[j]);
926 fprintf(stdout,"\n");
927 n=j+1;
928 }
929 }
930 }
931
932 @ Parse for the time stamp to be used.
933
934 @<Read time stamp@>=
935 {
936 fprintf(stdout,"Specify time stamp of DV tape. This is typically\n");
937 fprintf(stdout,"the last date that appears as time stamp in the\n");
938 fprintf(stdout,"recorded tape. [Press enter to use the current date]\n");
939 fprintf(stdout,"**");
940 while ((tmpch=fgetc(INSTREAM))==' '); /* Get rid of leading blank spaces */
941 ungetc(tmpch,INSTREAM);
942 k=0;
943 while ((tmpstr[k++]=fgetc(INSTREAM))!='\n'); /* Read line */
944 if (k>1) /* If more text than just spaces and a linefeed character */
945 for (j=0;j<k;j++) timestamp[j]=tmpstr[j];
946 else /* If just spaces and a linefeed character */
947 for (j=0;j<7;j++) timestamp[j]="\\today\n"[j];
948 if (verbose) {
949 fprintf(stdout,"Time stamp: ");
950 for (j=0;timestamp[j]!='\n';j++) fprintf(stdout,"%c",timestamp[j]);
951 fprintf(stdout,"\n");
952 }
953 }
954
955 @ Parse for the title to be used.
956
957 @<Read title@>=
958 {
959 fprintf(stdout,
960 "Specify title of the DV tape [Press enter to leave blank title]:\n");
961 fprintf(stdout,"**");
962 while ((tmpch=fgetc(INSTREAM))==' '); /* Get rid of leading blank spaces */
963 ungetc(tmpch,INSTREAM);
964 k=0;
965 while ((tmpstr[k++]=fgetc(INSTREAM))!='\n'); /* Read line */
966 if (k>1) /* If more text than just spaces and a linefeed character */
967 for (j=0;j<k;j++) title[j]=tmpstr[j];
968 else /* If just spaces and a linefeed character */
969 title[0]='\n'; /* Blank title */
970 if (verbose) {
971 fprintf(stdout,"Title: ");
972 for (j=0;title[j]!='\n';j++) fprintf(stdout,"%c",title[j]);
973 fprintf(stdout,"\n");
974 }
975 }
976
977 @ Parse for the author name to be used.
978
979 @<Read author name@>=
980 {
981 fprintf(stdout,
982 "Specify author of the DV tape [Press enter to leave blank]:\n");
983 fprintf(stdout,"**");
984 while ((tmpch=fgetc(INSTREAM))==' '); /* Get rid of leading blank spaces */
985 ungetc(tmpch,INSTREAM);
986 k=0;
987 while ((tmpstr[k++]=fgetc(INSTREAM))!='\n'); /* Read line */
988 if (k>1) /* If more text than just spaces and a linefeed character */
989 for (j=0;j<k;j++) author[j]=tmpstr[j];
990 else /* If just spaces and a linefeed character */
991 author[0]='\n'; /* Blank author field */
992 if (verbose) {
993 fprintf(stdout,"Author: ");
994 for (j=0;author[j]!='\n';j++) fprintf(stdout,"%c",author[j]);
995 fprintf(stdout,"\n");
996 }
997 }
998
999 @ Parse for the address to be used.
1000 The syntax for specifying the address is similar to that of the table of
1001 contents, with arbitrary number of lines of text. The input is ended by
1002 a single dot on a new line, in similar to the way of entering, for example,
1003 email messages in terminal mode using the basic engine of {\tt sendmail} on
1004 regular UNIX and Linux systems.
1005
1006 @<Read address@>=
1007 {
1008 fprintf(stdout,"Specify address of author of the DV tape\n");
1009 fprintf(stdout,"[Enter text and finish with single dot on blank line]:\n");
1010 fprintf(stdout,"**");
1011 done=0;
1012 n=0;
1013 num_address_lines=0;
1014 while (!done) {
1015 while ((tmpch=fgetc(INSTREAM))==' '); /* Get rid of leading spaces */
1016 ungetc(tmpch,INSTREAM);
1017 k=0;
1018 while ((tmpstr[k++]=fgetc(INSTREAM))!='\n'); /* Read line */
1019 if (k>1) { /* If more text than just spaces and a linefeed character */
1020 if ((tmpstr[0]=='.')&&(tmpstr[1]=='\n')) {
1021 done=1;
1022 } else {
1023 for (j=0;j<k;j++) address[n+j]=tmpstr[j];
1024 if (1==0) address[n+j]='\n';
1025 n=n+j; /* Keep track of last index of the |address| array */
1026 num_address_lines++;
1027 }
1028 } else { /* If just spaces and a linefeed character */
1029 address[n]='\n'; /* Blank line of address field */
1030 }
1031 fprintf(stdout,"**");
1032 }
1033 if (verbose) {
1034 fprintf (stdout,"%s: Counted %ld address lines.\n",
1035 progname,num_address_lines);
1036 fprintf(stdout,"Address:\n");
1037 n=0;
1038 for (k=1;k<=num_address_lines;k++) {
1039 for (j=n;address[j]!='\n';j++) fprintf(stdout,"%c",address[j]);
1040 fprintf(stdout,"\n");
1041 n=j+1;
1042 }
1043 }
1044 }
1045
1046 @ Parse for the email address to be used.
1047
1048 @<Read email address@>=
1049 {
1050 fprintf(stdout,
1051 "Specify email of author of the DV tape [Press enter to leave blank]:\n");
1052 fprintf(stdout,"**");
1053 while ((tmpch=fgetc(INSTREAM))==' '); /* Get rid of leading blank spaces */
1054 ungetc(tmpch,INSTREAM);
1055 k=0;
1056 while ((tmpstr[k++]=fgetc(INSTREAM))!='\n'); /* Read line */
1057 if (k>1) /* If more text than just spaces and a linefeed character */
1058 for (j=0;j<k;j++) email[j]=tmpstr[j];
1059 else /* If just spaces and a linefeed character */
1060 email[0]='\n'; /* Blank email field */
1061 if (verbose) {
1062 fprintf(stdout,"Email: ");
1063 for (j=0;email[j]!='\n';j++) fprintf(stdout,"%c",email[j]);
1064 fprintf(stdout,"\n");
1065 }
1066 }
1067
1068 @ Generating the preamble of output \TeX\ source code for the labels.
1069 The physical outer of the Mini Digital Label dimensions are based on the inset
1070 of TDK cassettes, with |flapheight| of 14.5~mm (41.3~pt), spineheight of
1071 12.5~mm (35.6~pt), |faceheight| of 47~mm (133.7~pt), and |facewidth| of
1072 67~mm (190.6~pt), hence summing up to overall outer dimensions of
1073 $190.6\times210.6$~pt of the label.
1074
1075 @<Save preamble source code@>=
1076 {
1077 facewidth=190.6+3.0*72.27/25.4;
1078 faceheight=133.7;
1079 spineheight=35.6;
1080 flapheight=41.3;
1081 ifacewidth=facewidth-14.0*linethickness;
1082 ifaceheight=faceheight-11.0*linethickness-0.5*edgeseparation;
1083 ispineheight=spineheight-8.0*linethickness-edgeseparation;
1084 iflapheight=flapheight-11.0*linethickness-0.5*edgeseparation;
1085 if (!outfile_specified)
1086 fprintf(OUTSTREAM,"%%-------- TEX CODE BEGINS HERE -----------------\n");
1087 fprintf(OUTSTREAM,"%% File: %s.tex\n",outputfilename);
1088 fprintf(OUTSTREAM,"%% TeX code generated by %s, v.%s, %s",
1089 progname,VERSION,ctime(&now));
1090 fprintf(OUTSTREAM,"%% Copyright (C) Fredrik Jonsson, 2003-2005\n%%\n");
1091 fprintf(OUTSTREAM,"\\hoffset=-35pt\\voffset=-25pt\n");
1092 fprintf(OUTSTREAM,"\\hsize=175mm\\vsize=254mm\n");
1093 fprintf(OUTSTREAM,"\\font\\eightcmssqeight=cmssq8\n");
1094 fprintf(OUTSTREAM,"\\font\\sevencmtt=cmtt7\n");
1095 fprintf(OUTSTREAM,"\\font\\tencmssqten=cmssq8 at 10 truept\n");
1096 fprintf(OUTSTREAM,"\\font\\deffacefont=cmr7\n");
1097 fprintf(OUTSTREAM,"\\font\\deftimestampfont=cmtt8 at 7 truept\n");
1098 fprintf(OUTSTREAM,"\\font\\defspinefont=cmr9\n");
1099 fprintf(OUTSTREAM,"\\font\\defflapfont=cmr7\n");
1100 fprintf(OUTSTREAM,"\\def\\monthname{\\ifcase\\month%%\n");
1101 fprintf(OUTSTREAM," \\or Jan\\or Feb\\or Mar\\or Apr\\or May\\or Jun%%\n");
1102 fprintf(OUTSTREAM," \\or Jul\\or Aug\\or Sep\\or Oct\\or Nov\\or Dec%%\n");
1103 fprintf(OUTSTREAM," \\fi}\n");
1104 fprintf(OUTSTREAM,"\\def\\fullmonthname{\\ifcase\\month%%\n");
1105 fprintf(OUTSTREAM," \\or January\\or February\\or March\\or April%%\n");
1106 fprintf(OUTSTREAM," \\or May\\or June\\or July\\or August\\or September\n");
1107 fprintf(OUTSTREAM," \\or October\\or November\\or December\\fi}\n");
1108 fprintf(OUTSTREAM,"\\def\\today{\\fullmonthname\\space\\number\\day,%%\n");
1109 fprintf(OUTSTREAM," \\space\\number\\year}\n");
1110 fprintf(OUTSTREAM,"\\def\\dvby{Digital Video by\\ }\n");
1111 fprintf(OUTSTREAM,"\\parindent 0pt\n");
1112 fprintf(OUTSTREAM,"\\newdimen\\facewidth\n");
1113 fprintf(OUTSTREAM,"\\newdimen\\faceheight\n");
1114 fprintf(OUTSTREAM,"\\newdimen\\spineheight\n");
1115 fprintf(OUTSTREAM,"\\newdimen\\flapheight\n");
1116 fprintf(OUTSTREAM,"\\newdimen\\linethick\n");
1117 fprintf(OUTSTREAM,"\\newdimen\\spacethick\n");
1118 fprintf(OUTSTREAM,"\\newdimen\\edgeseparation\n");
1119 fprintf(OUTSTREAM,"\\newdimen\\cropthick\n");
1120 fprintf(OUTSTREAM,"\\facewidth=%1.3fpt\n",facewidth);
1121 fprintf(OUTSTREAM,"\\faceheight=%1.3fpt\n",faceheight);
1122 fprintf(OUTSTREAM,"\\spineheight=%1.3fpt\n",spineheight);
1123 fprintf(OUTSTREAM,"\\flapheight=%1.3fpt\n",flapheight);
1124 fprintf(OUTSTREAM,"\\linethick=%1.3fpt\n",linethickness);
1125 fprintf(OUTSTREAM,"\\spacethick=%1.3fpt\n",2.0*linethickness);
1126 fprintf(OUTSTREAM,"\\edgeseparation=%1.3fpt\n",edgeseparation);
1127 fprintf(OUTSTREAM,"\\cropthick=%1.3fpt\n",clthick);
1128 if (headline) {
1129 fprintf(OUTSTREAM,"\\headline={\\hfill{\\tt dvlabel output");
1130 fprintf(OUTSTREAM," %s",ctime(&now));
1131 fprintf(OUTSTREAM," [%s]}}\n",(infile_specified?inputfilename:"stdin"));
1132 fprintf(OUTSTREAM,"\\footline={\\hfill\\folio\\hfill}\n");
1133 } else {
1134 fprintf(OUTSTREAM,"\\headline={\\hfil}\n");
1135 fprintf(OUTSTREAM,"\\nopagenumbers\n");
1136 }
1137 fprintf(OUTSTREAM,"\\def\\boxit#1{\\vbox{\\hrule height\\linethick%%\n");
1138 fprintf(OUTSTREAM," \\hbox{\\vrule width\\linethick\\kern\\spacethick%%\n");
1139 fprintf(OUTSTREAM," \\vbox{\\kern\\spacethick#1\\kern\\spacethick}%%\n");
1140 fprintf(OUTSTREAM," \\kern\\spacethick\\vrule width\\linethick}%%\n");
1141 fprintf(OUTSTREAM," \\hrule height\\linethick}}%%\n");
1142 }
1143
1144 @ Generating the output \TeX\ source code for the labels.
1145
1146 @<Save label source code@>=
1147 {
1148 fprintf(OUTSTREAM,"\\def\\timestamp{");
1149 for (j=0;timestamp[j]!='\n';j++) fprintf(OUTSTREAM,"%c",timestamp[j]);
1150 fprintf(OUTSTREAM,"}%%\n");
1151 fprintf(OUTSTREAM,"\\def\\title{");
1152 for (j=0;title[j]!='\n';j++) fprintf(OUTSTREAM,"%c",title[j]);
1153 fprintf(OUTSTREAM,"}%%\n");
1154 fprintf(OUTSTREAM,"\\def\\author{");
1155 for (j=0;author[j]!='\n';j++) fprintf(OUTSTREAM,"%c",author[j]);
1156 fprintf(OUTSTREAM,"}%%\n");
1157 fprintf(OUTSTREAM,"\\def\\email{");
1158 for (j=0;email[j]!='\n';j++) fprintf(OUTSTREAM,"%c",email[j]);
1159 fprintf(OUTSTREAM,"}%%\n");
1160 fprintf(OUTSTREAM,"%% Define the outline of the face of the label\n");
1161 fprintf(OUTSTREAM,"\\setbox1=\\hbox to %1.3fpt{{%%\n",ifacewidth);
1162 fprintf(OUTSTREAM," \\vbox to \\faceheight{%%\n");
1163 fprintf(OUTSTREAM," \\hbox{\\deffacefont\\timestamp\\hfil}%%\n");
1164 n=0;
1165 for (k=1;k<=num_toc_lines;k++) {
1166 fprintf(OUTSTREAM," \\vskip -3pt\\hbox{\\deffacefont ");
1167 for (j=n;toc[j]!='\n';j++) fprintf(OUTSTREAM,"%c",toc[j]);
1168 fprintf(OUTSTREAM,"\\hfil}%%\n");
1169 n=j+1;
1170 }
1171 fprintf(OUTSTREAM," \\vfil}}\\hfil}%%\n");
1172 fprintf(OUTSTREAM,"%% Define the outline of the spine of the label\n");
1173 fprintf(OUTSTREAM,"\\setbox2=\\hbox to %1.3fpt{{%%\n",ifacewidth);
1174 fprintf(OUTSTREAM," \\vbox to %1.3fpt{%%\n",ispineheight);
1175 fprintf(OUTSTREAM," \\hbox{\\deftimestampfont\\timestamp\\hfil}%%\n");
1176 fprintf(OUTSTREAM," \\hbox{\\defspinefont\\title\\hfil}%%\n");
1177 fprintf(OUTSTREAM," \\vfil}}\\hfil}%%\n");
1178 fprintf(OUTSTREAM,"%% Define the outline of the flap of the label\n");
1179 fprintf(OUTSTREAM,"\\setbox3=\\hbox to %1.3fpt{{%%\n",ifacewidth);
1180 fprintf(OUTSTREAM," \\vbox to %1.3fpt{%%\n",iflapheight);
1181 fprintf(OUTSTREAM," \\hbox{\\defflapfont\\dvby\\author\\hfil}%%\n");
1182 n=0;
1183 for (k=1;k<=num_address_lines;k++) {
1184 fprintf(OUTSTREAM," \\vskip -3pt\\hbox{\\defflapfont ");
1185 for (j=n;address[j]!='\n';j++) fprintf(OUTSTREAM,"%c",address[j]);
1186 fprintf(OUTSTREAM,"\\hfil}\n");
1187 n=j+1;
1188 }
1189 fprintf(OUTSTREAM," \\vskip -3pt\\hbox{\\defflapfont\\email\\hfil}%%\n");
1190 fprintf(OUTSTREAM," \\vfil}}\\hfil}%%\n");
1191 fprintf(OUTSTREAM,"\\def\\dvlabel{\\hskip\\linethick\\boxit{%%\n");
1192 fprintf(OUTSTREAM," \\boxit{\\box1}\\vskip\\edgeseparation%%\n");
1193 fprintf(OUTSTREAM," \\boxit{\\box2}\\vskip\\edgeseparation%%\n");
1194 fprintf(OUTSTREAM," \\boxit{\\box3}}\\hskip\\linethick}%%\n");
1195 if ((num_labels==1)||(num_labels==3)) fprintf(OUTSTREAM,"\\hskip %1.3fpt",
1196 (20.0));
1197 fprintf(OUTSTREAM,"\\dvlabel\n");
1198 if ((num_labels==2)||(num_labels==4)||(num_labels==6)) {
1199 fprintf(OUTSTREAM,"\\par\\nointerlineskip\n");
1200 }
1201 }
1202
1203 @ Close one page of output, with each page containing |num_labels_per_page|
1204 labels, and write any preamble for initialization of a new page to the output
1205 stream.
1206
1207 @<Close output page@>=
1208 {
1209 fprintf(OUTSTREAM,"\\vfill\\eject\n");
1210 }
1211
1212 @ Before writing the first row of labels to the page output, save the vertical
1213 crop marks to be used as alignment marks in vertical cutting of the final
1214 pages.
1215
1216 @<Write vertical crop marks with width measure@>=
1217 {
1218 fprintf(OUTSTREAM,"\\hskip %1.3fpt\\vrule height20pt width%1.3fpt%%\n",
1219 20.0-clthick/2.0,clthick);
1220 fprintf(OUTSTREAM,"\\hbox to%1.3fpt{\\hfil",facewidth-clthick);
1221 fprintf(OUTSTREAM,"$\\matrix{{%1.3f{\\rm\\ pt}/%1.3f{\\rm\\ mm}}"
1222 "\\cr{}\\cr}$\\hfil}%%\n",facewidth,facewidth*(25.4/72.27));
1223 fprintf(OUTSTREAM,"\\vrule height20pt width%1.3fpt%%\n",clthick);
1224 fprintf(OUTSTREAM,"\\hbox to %1.3fpt{\\hfil",facewidth-clthick);
1225 fprintf(OUTSTREAM,"$\\matrix{{%1.3f{\\rm\\ pt}/%1.3f{\\rm\\ mm}}"
1226 "\\cr{}\\cr}$\\hfil}%%\n",facewidth,facewidth*(25.4/72.27));
1227 fprintf(OUTSTREAM,"\\vrule height20pt width%1.3fpt\\par\\nointerlineskip\n",
1228 clthick);
1229 }
1230
1231 @ The following block is analogous to the previous one, but now instead
1232 considering horizontal crop marks, to be used as alignment marks in
1233 horizontal cutting of the final pages.
1234
1235 @<Write horizontal crop marks with height measure@>=
1236 {
1237 fprintf(OUTSTREAM,"\\vskip\\linethick\n");
1238 fprintf(OUTSTREAM,"\\vrule height%1.3fpt width20pt",clthick);
1239 fprintf(OUTSTREAM,"\\hskip %1.3fpt",2.0*facewidth);
1240 fprintf(OUTSTREAM,"\\vrule height%1.3fpt width20pt\\par\\nointerlineskip\n",
1241 clthick);
1242 fprintf(OUTSTREAM,"\\vskip\\linethick\n");
1243 }
1244
1245 @ Generating the closing \TeX\ source code for the labels.
1246
1247 @<Save closing source code@>=
1248 {
1249 if ((num_labels!=2)&&(num_labels!=4)) {
1250 fprintf(OUTSTREAM,"\\par\\nointerlineskip\n");
1251 }
1252 if (num_labels!=num_labels_per_page) {
1253 if (num_labels!=0) {
1254 if (generate_crop_marks) {
1255 @<Write horizontal crop marks with height measure@>@;
1256 @<Write vertical crop marks with width measure@>@;
1257 }
1258 }
1259 @<Close output page@>@;
1260 }
1261 fprintf(OUTSTREAM,"\\bye\n");
1262 if (!outfile_specified)
1263 fprintf(OUTSTREAM,"%%-------- TEX CODE ENDS HERE -----------------\n");
1264 }
1265
1266 @ Compiling the output \TeX\ source code. If the {\tt -c} or {\tt --compile}
1267 option was present at the command line during startup of \dvlabel, then
1268 the program will make use of \DVIPS\ to compile the previously generated
1269 \TeX\ source code into PostScript.
1270 If the {\tt -c} or {\tt --compile} option is used together with a specified
1271 output file (specified using the {\tt-o} or {\tt --outputfile} options),
1272 then this output file will be compiled.
1273 On the other hand, if the {\tt -c} or {\tt --compile} option is used while
1274 the program should send the generated source to |stdout|, then the internally
1275 stored lines of output will be compiled instead (hence eliminating the need
1276 for a temporary file for the compilation).
1277
1278 @<Compile source code@>=
1279 {
1280 if (compile) {
1281 if (verbose) {
1282 fprintf(stdout,"%s: Compiling the TeX source code into PostScript.\n",
1283 progname);
1284 }
1285 if (outfile_specified) {
1286 if (eps_output) {
1287 sprintf(tmpstr,"tex %s; dvips %s %s -E -o %s.eps",
1288 outputfilename,dvipsopts,outputfilename,outputfilename);
1289 } else {
1290 sprintf(tmpstr,"tex %s; dvips %s %s -o %s.ps",
1291 outputfilename,dvipsopts,outputfilename,outputfilename);
1292 }
1293 system(tmpstr); /* System call to execute |tmpstr| */
1294 } else {
1295 fprintf(stdout,"Compiling terminal output: Not implemented yet.\n");
1296 exit(FAILURE);
1297 }
1298 }
1299 }
1300
1301 @*Index.
1302
Generated by ::viewsrc::