home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume15 / rot < prev    next >
Text File  |  1988-06-01  |  16KB  |  664 lines

  1. Subject:  v15i030:  Rotate text
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Martin Schmidt <exunido.irb.informatik.uni-dortmund.de!mschmidt>
  7. Posting-number: Volume 15, Issue 30
  8. Archive-name: rot
  9.  
  10. This program rotates a file, so that lines become columns and vice versa.
  11. Without any options, the file will be rotated clockwise. So, from the input
  12.  
  13.           abcde
  14.           abcd
  15.           abc
  16.           ab
  17.           a
  18.              xx xx
  19.           A
  20.           AB
  21.           ABC
  22.           ABCD
  23.           ABCDE
  24.  
  25. you will get
  26.  
  27.           AAAAA aaaaa
  28.           BBBB   bbbb
  29.           CCC     ccc
  30.           DD   x   dd
  31.           E    x    e
  32.  
  33.                x
  34.                x
  35.  
  36. # This is a shell archive.  Unpack with "sh <file".
  37. # Contents: Makefile rot.man rot.c
  38. #
  39. echo x - Makefile
  40. cat > "Makefile" << '!Funky!Stuff!'
  41. # Makefile for rot.c
  42. #
  43. # Edit this to your standards:
  44. CFLAGS= -O
  45. BINDIR=/usr/local
  46. MANDIR=/usr/man/man1
  47. # If you have preformatted manuals, remove the comment character
  48. # in the install section
  49. CATMANDIR=/usr/man/cat1
  50. #
  51. rot: rot.c
  52.     cc $(CFLAGS) rot.c -o rot
  53. rot.cat: rot.man
  54.     tbl rot.man | nroff -man | col > rot.cat
  55.  
  56. install: rot rot.man rot.cat
  57.     chmod 644 rot.man rot.cat
  58.     mv rot.man $(MANDIR)/rot.1
  59. #    mv rot.cat $(CATMANDIR)/rot.1
  60.     chmod 711 rot
  61.     mv rot $(BINDIR)
  62. !Funky!Stuff!
  63. echo x - rot.man
  64. cat > "rot.man" << '!Funky!Stuff!'
  65. .\"@(#) rot.man 88/03/03 -- use tbl
  66. .TH ROT 1 public UNIX
  67. .SH NAME
  68. rot \- rotate a file
  69. .SH SYNOPSIS
  70. rot [-rbloB] [-c \fIc\fP] [\fIfile\fP]
  71. .SH DESCRIPTION
  72. .I Rot
  73. rotates a file, so that lines become columns and vice versa. Without any
  74. options, the file will be rotated clockwise. So, from the input
  75. .nf
  76. .in +10
  77.  
  78. abcde
  79. abcd
  80. abc
  81. ab
  82. a
  83. \0\0\0xx\0xx
  84. A
  85. AB
  86. ABC
  87. ABCD
  88. ABCDE
  89.  
  90. .ti -10
  91. you will get
  92.  
  93. AAAAA\0aaaaa
  94. BBBB\0\0\0bbbb
  95. CCC\0\0\0\0\0ccc
  96. DD\0\0\0x\0\0\0dd
  97. E\0\0\0\0x\0\0\0\0e
  98. \0\0\0\0\0\0
  99. \0\0\0\0\0x
  100. \0\0\0\0\0x
  101.  
  102. .in -10
  103. .fi
  104. .I Rot
  105. uses a two pass algorithm, where the first part collects the line length of each
  106. line in the input, and the second prints out the new lines, seeking through
  107. the input file.
  108. When no file or - is given,
  109. .I rot
  110. reads from standard input.
  111. .SH OPTIONS
  112. .TP
  113. .B -r
  114. rotate reverse (counter-clockwise)
  115. .TP
  116. .B -b
  117. normally,
  118. .I rot
  119. suppresses printing of trailing blanks in output lines.
  120. This option retains them, so all blanks of the input will appear
  121. in the output
  122. .TP
  123. .B -l
  124. do only the first pass and print the number of lines and the length of the
  125. longest line found to standard output
  126. .TP
  127. .B -o
  128. change order of columns; in combination with the rotation this yields
  129. one more file operation (see below)
  130. .TP
  131. .B -B
  132. this is for big files; the data will be hold in temporary files rather
  133. than in memory; this slows down
  134. .I rot
  135. enormously
  136. .TP
  137. .B -c \fIc\fP
  138. use
  139. .I c
  140. as "line"-separator, instead of the newline character
  141. .br
  142. .ne 8
  143. .SH REMARKS
  144. One may ask, what
  145. .I rot
  146. is useful for.
  147. Think about the functionality of programs like
  148. .IR cat (1),
  149. or the line oriented
  150. .IR grep (1),
  151. .IR cut (1),
  152. .IR sed (1),
  153. .IR sort (1),
  154. and others, when applied to a rotated file.
  155. In conjunction with
  156. .I rot
  157. they do not longer work on lines, but columns.
  158. For example
  159. .P
  160. .ti +10
  161. rot f | grep ... | rot -r
  162. .P
  163. is a
  164. .I grep
  165. on columns of the file f.
  166. .P
  167. The -o option permits you to manipulate a file in some way of "reflecting" it
  168. in a "diagonal" line. The following table shows the different effects of
  169. .I rot
  170. called with various options. Data manipulation is shown by means of the
  171. output of a file with the contents
  172. .P
  173. .ti +10
  174. AB
  175. .br
  176. .ti +10
  177. CD
  178. .P
  179. and a symbolic notation. R means Rotation (angle given), M means
  180. reflection at given mirror axis.
  181. Combinations of two calls of
  182. .I rot
  183. are also given. (Other combinations
  184. have identical effects to one of the mentioned.)
  185.  
  186. .TS
  187. tab(#) center box;
  188. lfB | cfB | cfB
  189. l | c | c.
  190. call#output#function
  191. .sp 0.5
  192. =
  193. rot#CA#R
  194. \^#DB#-90 deg
  195. _
  196. rot -r#BD#R
  197. \^#AC#90 deg
  198. _
  199. rot -o#DB#M
  200. \^#CA#/
  201. _
  202. rot -ro#AC#M
  203. \^#BD#\e
  204. =
  205. rot | rot#DC#R
  206. \^#BA#180 deg
  207. _
  208. rot | rot -r#AB#(Id) *
  209. \^#CD#\^
  210. _
  211. rot | rot -o#BA#M **
  212. \^#DC#|
  213. _
  214. rot | rot -ro#CD#M
  215. \^#AB#\-
  216. .TE
  217.  
  218. * Note, that  rot|rot -r  (or  rot|rot|rot|rot)  is not exactly the null
  219. operator.
  220. .I Rot
  221. must insert blanks to keep track of the columns.
  222. They may appear at the end of lines in a further run of
  223. .IR rot ,
  224. if the -b option is given.
  225. Without this option blanks from the original input may be lost.
  226. .P
  227. ** This is not the same as what is done by
  228. .IR rev (1).
  229. Rev does not retain columns!
  230.  
  231. .I Rot
  232. knows nothing about tab characters, use
  233. .IR expand (1)
  234. to handle them correctly.
  235. .SH FILES
  236. .TP
  237. /tmp/rot* -
  238. temporarily copied input, if standard input is incapable of seeking
  239. (pipe or terminal) (-B option only)
  240. .TP
  241. /tmp/rod* -
  242. tempfile for holding length of input lines (-B option only)
  243. .SH SEE ALSO
  244. rev(1), tail(1bsd), tac(1public), expand(1), colrm(1)
  245. .SH AUTHOR
  246. .nf
  247. Martin Schmidt
  248. Dortmund - W. Germany
  249. mschmidt@exunido.uucp
  250. .fi
  251. !Funky!Stuff!
  252. echo x - rot.c
  253. cat > "rot.c" << '!Funky!Stuff!'
  254.  
  255.                       /**************************/
  256.                       /*****     rot.c      *****/
  257.                       /*****    -------     *****/
  258.                       /*****  Version 1.2   *****/
  259.                       /***** -------------  *****/
  260.                       /*****   16.02.1988   *****/
  261.                       /**************************/
  262.  
  263.  
  264. char what_id [] = "@(#) rot.c 1.2, M. Schmidt [1988/02/16]";
  265.  
  266. #include <stdio.h>
  267. #include <signal.h>
  268.  
  269. #define MEMPIECE     8192L
  270.  
  271. char *tmpdata = "/tmp/rodXXXXXX";       /* numbers     */
  272. char *tmpin = "/tmp/rotXXXXXX";         /* temp. stdin */
  273. char *bigmsg = "rot: file too big (%s), use -B flag\n";
  274. char nl;
  275. FILE *ftmpdata, *ftmpin;
  276. int lflag, rflag, bflag, oflag, Bflag, szl, cpin;
  277. long holdbl, *lsptr, *lptr, *leptr;
  278. char *fname, *isptr, *iptr, *ieptr;
  279. extern int errno;
  280. extern char *malloc(), *realloc();
  281. char getinput();
  282.  
  283. main (argc, argv)
  284. char **argv;
  285. {  long maxline, col;
  286.    int i;
  287.    long nextlong(), pass1();
  288.    int on_irupt();
  289.  
  290.    lflag = rflag = bflag = oflag = Bflag = cpin = 0;
  291.    fname = "";
  292.    nl = '\n';
  293.    umask (077);
  294.    szl = sizeof (long);
  295.  
  296.    i = 1;
  297.    while (i < argc)
  298.    {  if (*(argv[i]) == '-')
  299.          do
  300.          switch ( *(++(argv[i])) )
  301.          {  case 'r' : rflag++; break;
  302.             case 'l' : lflag++; break;
  303.             case 'b' : bflag++; break;
  304.             case 'o' : oflag++; break;
  305.             case 'B' : Bflag++; break;
  306.             case 'c' : nl = *(argv[++i]); break;
  307.             case '\0': fname = ""; break;
  308.             default  : fprintf (stderr, "usage: rot [-rbloB] [-c c] [file]\n");
  309.                        exit (1);
  310.          }
  311.          while (*(argv[i]) != '\0');
  312.       else
  313.         if (*fname != '\0')
  314.         {  fprintf (stderr, "rot: can rotate only one file\n");
  315.            exit (1);
  316.         }
  317.         else
  318.            fname = argv[i];
  319.       i++;
  320.    }
  321.  
  322.    if (signal (SIGINT, on_irupt) == SIG_IGN)
  323.       signal (SIGINT, SIG_IGN);
  324.    if (signal (SIGTERM, on_irupt) == SIG_IGN)
  325.       signal (SIGTERM, SIG_IGN);
  326.    if (signal (SIGHUP, on_irupt) == SIG_IGN)
  327.       signal (SIGHUP, SIG_IGN);
  328.    if (signal (SIGQUIT, on_irupt) == SIG_IGN)
  329.       signal (SIGQUIT, SIG_IGN);
  330.    signal (SIGSEGV, on_irupt);
  331.  
  332.    if ( Bflag && *fname == '\0' && fseek (stdin, 0L, 0) != 0)
  333.       cpin++;                                     /* stdin is pipe */
  334.  
  335.    if (*fname != '\0')
  336.       if (freopen (fname, "r", stdin) == NULL)
  337.       {  fprintf (stderr, "rot: can't open file %s\n", fname);
  338.          exit (1);
  339.       }
  340.  
  341.    if ( Bflag && isatty (fileno(stdin)))
  342.       cpin++;
  343.  
  344.    if (cpin) copyin();
  345.  
  346.    if (Bflag)
  347.    {  mktemp (tmpdata);
  348.       if ((ftmpdata = fopen (tmpdata, "w+")) == NULL)
  349.       {  fprintf (stderr, "rot: can't create tempfile\n");
  350.          exit (1);
  351.       }
  352.    }
  353.  
  354.    maxline = pass1 ();
  355.  
  356.    for (col = 1L; col <= maxline; col++)
  357.    {
  358.       if (rflag)
  359.          rseekcolumn (oflag ? col : maxline + 1 - col);
  360.       else
  361.          seekcolumn (oflag ? maxline + 1 - col : col);
  362.  
  363.       putchar (nl);                    /* one line finished */
  364.    }
  365.  
  366.    if (Bflag)
  367.    {  fclose (ftmpdata);
  368.       unlink (tmpdata);
  369.    }
  370.    if (cpin)
  371.    {  fclose (ftmpin);
  372.       unlink (tmpin);
  373.    }
  374.    exit (0);
  375. }  /* main */
  376.  
  377.  
  378. long
  379. pass1 ()                       /* save length of lines in memory/tempfile     */
  380.                                /*
  381.                                 * C-experts should have a close look at this.
  382.                                 * Pointer arithmetic is done without explicit
  383.                                 * use of arrays. Maybe non-portable. With
  384.                                 * big files memory segmentation may be
  385.                                 * significant (?). Segmentation-fault-signal is
  386.                                 * caught.
  387.                                 */
  388. {  long max, z, lines, ccount, *lp;
  389.    int c, tabseen = 0, lallocs, iallocs;
  390.    char *ip;
  391.  
  392.    z = max = lines = ccount = 0L;
  393.  
  394.    if (!Bflag && !lflag)                  /* allocs for linelengths and input */
  395.    {  lsptr = lp = (long *) malloc ((unsigned) MEMPIECE);
  396.       if (lsptr == NULL)
  397.       {  fprintf (stderr, bigmsg, "not enough memory");
  398.          exit (1);
  399.       }
  400.       lallocs = 1;
  401.       leptr = lsptr + ((long) lallocs) * (MEMPIECE/szl) - 1L;
  402.  
  403.       isptr = ip = malloc ((unsigned) (2 * MEMPIECE));
  404.       if (isptr == NULL)
  405.       {  fprintf (stderr, bigmsg, "not enough memory");
  406.          exit (1);
  407.       }
  408.       iallocs = 2;
  409.       ieptr = isptr + ((long) iallocs) * MEMPIECE - 1L;
  410.    }
  411.  
  412.    while ((c = getchar()) != EOF)
  413.    {  if (c == nl)
  414.       {  if (!lflag)
  415.          {  if (Bflag)                       /* write linelength in tempfile */
  416.                fwrite ((char *) &z, szl, 1, ftmpdata);
  417.             else                             /* put linelength into memory */
  418.             {  if ( ((long) lp) > ((long) leptr) )
  419.                {  lallocs++;                 /* more alloc */
  420.                   if ((lsptr = (long *)
  421.                      realloc (lsptr, (unsigned) (lallocs * MEMPIECE) )) == NULL)
  422.                   {  fprintf (stderr, bigmsg, "not enough memory");
  423.                      exit (1);
  424.                   }
  425.                   lp = lsptr + lines;
  426.                   leptr = lsptr + ((long) lallocs) * (MEMPIECE/szl) - 1L;
  427.                }
  428.                *(lp++) = z;
  429.             }
  430.          }
  431.          if (z > max) max = z;              /* find max. linelength */
  432.          z = 0L;
  433.          lines++;
  434.       }  /* c == nl */
  435.       else
  436.       {  if (c == '\t') tabseen++;
  437.          z++;
  438.       }
  439.       if (!Bflag && !lflag)                   /* put stdin into memory */
  440.       {  if (((long) ip) > ((long) ieptr))
  441.          {  iallocs += 2;                     /* more alloc */
  442.             if ((isptr =
  443.                  realloc (isptr, (unsigned) (iallocs * MEMPIECE) )) == NULL)
  444.             {  fprintf (stderr, bigmsg, "not enough memory");
  445.                exit (1);
  446.             }
  447.             ip = isptr + ccount;
  448.             ieptr = isptr + ((long) iallocs) * MEMPIECE - 1L;
  449.          }
  450.          *(ip++) = c;                         /* put inputchar into memory */
  451.          ccount++;
  452.       }
  453.    }  /* while */
  454.  
  455.    if (!Bflag && !lflag)
  456.    { leptr = lp - 1;                          /* mark end of memory sections */
  457.      ieptr = ip - 1;
  458.    }
  459.  
  460.    if (tabseen) fprintf (stderr, "rot: don't like tab characters!\n");
  461.  
  462.    if (lflag)
  463.    {  printf ("%ld %ld\n", lines, max);
  464.       if (cpin) unlink (tmpin);
  465.       exit (0);
  466.    }
  467.  
  468.    return max;
  469. }  /* pass1 */
  470.  
  471.  
  472. rseekcolumn (col)
  473. long col;
  474. {  register long i2, sum, z;
  475.    char c;
  476.    long nextlong();
  477.  
  478.    seekinput (0L, 0);                /* goto begin of input */
  479.    if (Bflag)
  480.       fseek (ftmpdata, 0L, 0);       /* goto begin of temp */
  481.    else
  482.       lptr = lsptr;                  /* goto begin of list */
  483.  
  484.    holdbl = 0L;
  485.    sum = - 1L;                       /* first seekinput() modified */
  486.    i2 = nextlong ();
  487.  
  488.    while (i2 >= 0L)                 /* i2 == -1L means EOF on temp or stdin */
  489.    {  z = 0L;
  490.       while (i2 < col && i2 >= 0L)  /* skip lines shorter col */
  491.       {  sum += i2;                 /* sum up linelengths */
  492.          z++;                       /* z: number of nl's skipped */
  493.          holdbl++;                  /* skipped lines -> blanks */
  494.          i2 = nextlong ();          /* read next line length */
  495.       }
  496.  
  497.       if (i2 >= 0L)
  498.       {
  499.          if (seekinput (sum + z + col, 1) == -1)
  500.             return;
  501.  
  502.          if ((c = getinput()) == EOF)
  503.             return;                  /* end of input */
  504.  
  505.          if (c == ' ' && !bflag)
  506.             holdbl++;
  507.          else
  508.          {  putblanks (holdbl);
  509.             holdbl = 0L;
  510.             putchar (c);
  511.          }
  512.  
  513.          sum = i2 - col;           /* rest of line or compensate col in fseek */
  514.          i2 = nextlong ();         /* read length of next line */
  515.       }
  516.    }
  517. }  /* rseekcolumn */
  518.  
  519.  
  520. seekcolumn (col)
  521. long col;
  522. {  register long i2, sum, z;
  523.    char c;
  524.    long nextlong();
  525.  
  526.    seekinput (-1L, 2);               /* goto end of input */
  527.    if (Bflag)
  528.       fseek (ftmpdata, (long) szl, 2);
  529.    else                              /* goto end of temp */
  530.       lptr = leptr;                  /* goto end of list */
  531.  
  532.    holdbl = 0L;
  533.    i2 = nextlong ();
  534.    sum = i2 - col - 1L;             /* first seekinput() modified */
  535.  
  536.    while (i2 >= 0L)                 /* i2 == -1L means EOF on temp */
  537.    {  z = 0L;
  538.       while (i2 < col && i2 >= 0L)  /* skip lines shorter col */
  539.       {  i2 = nextlong ();          /* read next line length */
  540.          sum += i2;                 /* sum up linelengths */
  541.          z++;                       /* z: number of nl's skipped */
  542.          holdbl++;                  /* skipped line  -> blank */
  543.       }
  544.  
  545.       if (i2 > 0L)
  546.       {
  547.          if (seekinput (- (sum + z + 2L), 1) == -1)
  548.             return;
  549.          if ((c = getinput()) == EOF)
  550.             return;                  /* end of input */
  551.  
  552.          if (c == ' ' && !bflag)
  553.             holdbl++;
  554.          else
  555.          {  putblanks (holdbl);
  556.             holdbl = 0L;
  557.             putchar (c);
  558.          }
  559.          sum = i2 = nextlong ();        /* read length of previous line */
  560.       }
  561.    }
  562. }  /* seekcolumn */
  563.  
  564.  
  565. putblanks (n)
  566. long n;
  567. {
  568.    for (; n > 0L; n--) putchar (' ');
  569. }  /* putblanks */
  570.  
  571.  
  572. long
  573. nextlong ()                                /* -1L = "EOF" */
  574. {  long i;
  575.  
  576.    if (!Bflag)                             /* get from memory */
  577.    {  if (lptr > leptr || lptr < lsptr)
  578.          i = -1L;
  579.       else
  580.          i = *lptr;
  581.       if (rflag)
  582.          lptr++;
  583.       else
  584.          lptr--;
  585.       return i;
  586.    }
  587.                                             /* read from tempfile */
  588.    if (!rflag)                              /* go back */
  589.       if (fseek (ftmpdata, (long) (-2 * szl), 1) < 0)
  590.          return -1L;
  591.  
  592.    if (fread ((char *) &i, szl, 1, ftmpdata) <= 0)
  593.       return -1L;
  594.    return i;
  595. }  /* nextlong */
  596.  
  597.  
  598. char
  599. getinput ()
  600. {  char c; if (Bflag)
  601.       return getchar();
  602.    else
  603.    {  if (iptr < isptr || iptr > ieptr)
  604.          return EOF;
  605.       else
  606.       {  c = *iptr;
  607.          iptr++;
  608.          return c;
  609.       }
  610.    }
  611. }
  612.  
  613.  
  614. seekinput (n, t)
  615. long n;
  616. {  if (Bflag)
  617.       return fseek (stdin, n, t);
  618.    else
  619.    {  switch (t)
  620.       {  case 0: iptr = isptr + n; break;
  621.          case 1: iptr += n; break;
  622.          case 2: iptr = ieptr + n + 1; break;
  623.       }
  624.       if (iptr < isptr || iptr > ieptr)
  625.          return -1;
  626.       else
  627.          return 0;
  628.    }
  629. }
  630.  
  631.  
  632. copyin ()
  633. {  register int c;
  634.    mktemp (tmpin);
  635.    if ((ftmpin = fopen (tmpin, "w+")) == NULL)
  636.    {  fprintf (stderr, "rot: can't create tempfile\n");
  637.       exit (1);
  638.    }
  639.    while ((c = getchar()) != EOF)
  640.       putc (c, ftmpin);
  641.    fclose (ftmpin);
  642.    if (freopen (tmpin, "r", stdin) == NULL)
  643.    {  fprintf (stderr, "rot: can't reopen tempfile\n");
  644.       unlink (tmpin);
  645.       exit (1);
  646.    }
  647.  
  648. }  /* copyin */
  649.  
  650.  
  651. on_irupt (s)
  652. {  signal (SIGINT, SIG_IGN);
  653.    signal (SIGTERM, SIG_IGN);
  654.    signal (SIGHUP, SIG_IGN);
  655.    signal (SIGQUIT, SIG_IGN);
  656.    if (Bflag) unlink (tmpdata);
  657.    if (cpin) unlink (tmpin);
  658.    if (s == SIGSEGV)
  659.       fprintf (stderr, bigmsg, "segmentation violation");
  660.    exit (1);
  661. }
  662. !Funky!Stuff!
  663.  
  664.