1 {- 
    2                       Mailing List Generator
    3                       ----------------------
    4                              
    5                 Written by Paul Hudak, January 1992.
    6 
    7 
    8 This program takes an ascii file of the form:
    9 
   10 Name1
   11 Address1
   12 City1
   13 
   14 Name2
   15 Address2
   16 City2
   17 
   18 ...
   19 
   20 Namen
   21 Addressn
   22 Cityn
   23 
   24 where each entry is up to 4 lines each and with at least one blank
   25 line between entries, and writes a new file containing reformatted
   26 entries along with LaTex commands, that, when run through Latex, will
   27 generate a printout of the form:
   28 
   29 Name1                       Name2                       Name3
   30 Address1                    Address2                    Address3
   31 City1                       City2                       City3
   32 ...
   33 
   34 which is suitably spaced to line up with the labels on a standard
   35 8 1/2 X 11, 30-per-page mailing label sheet.
   36 
   37 The program prompts the user for the name of the input file, and uses
   38 that name with a ".tex" suffix for the name of the output file.  That
   39 output file may be LaTexed directly, but it expects the following .sty
   40 file, whose name should be "labels.sty":
   41 
   42 \documentstyle[11pt]{article}
   43 \textheight=10.5in
   44 \textwidth=9.0in
   45 \topmargin=-1in
   46 \oddsidemargin=-1in
   47 \evensidemargin=-1in
   48 \pagestyle{empty}
   49 
   50 \newcommand{\leftspace}{.5in}
   51 \newcommand{\horspace}{0in}
   52 \newcommand{\vertspace}{.23in}
   53 
   54 \newcommand{\lpage}[3]
   55  {\newpage
   56   \vspace*{.05in}
   57   \noindent
   58   #1#2#3}
   59 
   60 \newcommand{\sblock}[3]
   61  {\lline{#1}{#2}{#3}\\}
   62 
   63 \newcommand{\lblock}[9]
   64  {\lline{#1}{#2}{#3}\vspace{\vertspace}\\ 
   65   \lline{#4}{#5}{#6}\vspace{\vertspace}\\
   66   \lline{#7}{#8}{#9}\vspace{\vertspace}\\}
   67 
   68 \newcommand{\lline}[3]
   69  {\hspace*{\leftspace}
   70   \lab{#1}\hspace{\horspace}
   71   \lab{#2}\hspace{\horspace}
   72   \lab{#3}}
   73 
   74 \newcommand{\lab}[1]
   75  {\begin{tabular}{p{2.5in}}
   76   #1
   77   \end{tabular}}
   78 
   79 
   80 Desired enhancements: 
   81 ---------------------
   82   allow more than one input file for same output file
   83   do character conversion for LaTex to avoid having to put "\&", etc. on input
   84 
   85 -}
   86 
   87 
   88 module Main where
   89 
   90 type Line      = String
   91 type Entry     = [Line]
   92 type FileName  = String
   93 type UserInput = [FileName]
   94 
   95 maxLineLength = 35 :: Int
   96 
   97 main =  do
   98     putStr "\n\nWelcome to the LaTex Mailing List Generator.\n\
   99                 \(Please type Cntrl-D at file prompt to exit.)\n"
  100     s <- getContents
  101     mainLoop (lines s)
  102 
  103 mainLoop :: UserInput -> IO ()
  104 mainLoop fns = 
  105         putStr "\nFile to be converted: " >>
  106         case fns of
  107           []        ->         putStr "\nGoodbye!\n"
  108           (fn:fns') ->         catch (readFile fn >>= process (fn ++ ".tex") fns')
  109                           (\err -> putStr ("\nCan't read " ++fn++ "; try again.\n") >>
  110                                    mainLoop fns')
  111                      
  112 
  113 process :: FileName -> UserInput -> String -> IO ()
  114 process out fns rawText = 
  115         writeFile out "% Latex Mailing List.\n\n\
  116                       \\\input{labels.sty}\n\n\
  117                       \\\begin{document}\n\n"     >>
  118         loop (paras (lines rawText))
  119         where loop [] = appendFile out "\n\\end{document}\n" >>
  120                         putStr ("\nConversion completed; file " ++out++ " written.\n") >>
  121                         mainLoop fns
  122               loop ps = writePage out ps loop
  123 
  124 paras :: [Line] -> [Entry]
  125 paras []  = []
  126 paras lns = p : paras (dropWhile blankLine lns')
  127             where (p,lns')  = break blankLine lns
  128                   blankLine = all (\c -> c==' ' || c=='\t')
  129 
  130 writePage :: FileName -> [Entry] -> ([Entry]-> IO ()) -> IO ()
  131 writePage out ps cont =
  132         appendFile out "\\lpage\n" >>
  133         writeBlock out ps long  9  >>= \ ps ->
  134         writeBlock out ps long  9  >>= \ ps ->
  135         writeBlock out ps long  9  >>= \ ps ->
  136         writeBlock out ps short 3  >>=
  137         cont
  138 
  139 -- got to here (partain)
  140 
  141 long  = "{\\lblock{\n"
  142 short = "{\\sblock{\n"
  143 
  144 writeBlock :: FileName -> [Entry] -> String -> Int -> IO [Entry]
  145 writeBlock out ps kind size = 
  146         appendFile out kind >>
  147         loop ps 1
  148         where  loop (e:es) n = 
  149                         writeEntry out e >>
  150                         (if n==size then appendFile out "\n}}\n" >>
  151                                          return es
  152                                     else appendFile out "\n}{\n" >>
  153                                          loop es (n+1) )
  154                 loop [] n = loop (take (size-n+1) (repeat [])) n
  155 
  156 writeEntry :: FileName -> Entry -> IO ()
  157 writeEntry out entry = loop entry 1  where
  158   loop [] n =
  159         if n<5 then loop (take (5-n) (repeat "")) n
  160                else return ()
  161   loop (ln:lns) n = 
  162         if n>4 
  163         then putStr
  164                "\nThis entry was truncated to 4 lines:\n" >>
  165              print entry >>
  166              putStr "\n" >>
  167              return ()
  168         else appendFile out ln >>
  169              appendFile out "\\\\ " >>
  170              (if length ln>maxLineLength
  171               then putStr "\nThis line may be too long:\n" >>
  172                    putStr ln >>
  173                    putStr "\nCheck LaTex output to be sure.\n" >>
  174                    loop lns (n+1)
  175               else loop lns (n+1) )