some old helper tools for rotation

Eli the Bearded <*@eli.users.panix.com> Wed, 20 May 2026 17:25:09 -0000 (UTC)
Newsgroups alt.ascii-art
Organization Some absurd concept
Message-ID <[email protected]>
A few weeks ago I found these in an old backup of mine. There's four
utilies, three of them using a compiled C heler tool and the fourth
based on awk. Combined they provide a way to rotate ASCII art 90
degrees, 180 degrees, 270 degrees, and to left-right flip an image.

The left-right flip is by Jef Poskanzer ( www.acme.com ) and clearly
licensed. The others are of ambitious origin and have no clear license.
I suspect the authors would be 100% okay with my sharing this old code
for the purpose of hobbyists to use non-commercially.

Code distributed in the old-school shell archive format. You can extract
by hand easily enough or use `sh` to do it automatically. There was no
makefile when I got this, but "make asciitool" worked for me. My only
changes to the code were to add the #include lines above the comment
in the C file and add line breaks to the C file usage message.

Elijah
------
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	notes
#	asciitool.c
#	ccw90
#	cw90
#	tb
#	lr
#
echo x - notes
sed 's/^X//' >notes << 'END-of-notes'
XDownloaded from
X	gopher://samuell.com:70/ 
Xsometime in June 2006
END-of-notes
echo x - asciitool.c
sed 's/^X//' >asciitool.c << 'END-of-asciitool.c'
X#include <stdlib.h>
X#include <stdio.h>
X/* **********************************************************************
X  asciitool.c    An ASCII Rotation and Mirroring tool
X 
Xcompile with: cc -o asciitool asciitool.c
X 
XNot my code! (Joshua Bell, [email protected])
X 
XWell, some of it is, but not much.
XChanges:    - changed if/else if/else if/else if... to a switch
X            - fixed bug with -r270 (no longer requires rectangular images)
X            - made Infile and Outfile default to STDIN and STDOUT (for pipes)
X            - made incorrect calling syntax quit program 
X            - reformatted the source to be more concise
X 
Xasciitool -{mh|mv|r90|r180|r270} [Infile [Outfile]]
X   -mh          Mirror horizontally
X   -mv          Mirror vertically
X   -r90         Rotate 90 degrees counterclockwise
X   -r180        Rotate 90 degrees counterclockwise
X   -r270        Rotate 90 degrees counterclockwise
X 
X********************************************************************** */
X 
X#include <stdio.h>
X#include <string.h>
X 
X#define NUM_FLAGS 5
X 
Xchar *FlagStrings[NUM_FLAGS] = { "-mv", "-mh", "-r90", "-r180", "-r270" };
Xenum { V_MIRROR, H_MIRROR, R90, R180, R270 };
X 
Xchar **GetFile(FilePtr, NumberOfLinesPtr, ErrorString)
X  FILE *FilePtr;
X  int *NumberOfLinesPtr;
X  char *ErrorString;
X{
X  char **FileLines;
X  char Buffer[255];
X  int CurrentLine, c, Error;
X  
X  ErrorString[0] = '\0';
X  
X  CurrentLine = 0;
X  Error = 0;
X  
X  while((c = fgetc(FilePtr)) != EOF) {
X    ungetc(c, FilePtr);
X    fgets(Buffer, sizeof(Buffer), FilePtr);
X    
X    if(CurrentLine == 0) {
X      if((FileLines = (char **)malloc(sizeof(char *))) == NULL) {
X        strcpy(ErrorString, "Memory Allocation Error: <malloc>");
X        return(NULL);
X      }
X 
X    } else {
X      if((FileLines = 
X          (char **)realloc(FileLines,(1 + CurrentLine) * sizeof(char *))) 
X         == NULL) {
X        strcpy(ErrorString, "Memory Allocation Error: <realloc>\n");
X        return(NULL);
X      }
X    }
X    
X    if((FileLines[CurrentLine] = (char *)malloc(strlen(Buffer) + 1)) == NULL) {
X      strcpy(ErrorString, "Memory Allocation Error: <malloc>\n");
X      return(NULL);
X    }
X 
X    strcpy(FileLines[CurrentLine++], Buffer);
X  }
X 
X  *NumberOfLinesPtr = CurrentLine;
X 
X  return(FileLines);
X 
X} /* GetFile */
X 
Xint main(argc, argv)
X   int argc;
X   char **argv;
X{
X  int i, j, k, Flag, NumberOfLines, Length, MaxLength;
X  FILE *Infile, *Outfile;
X  char String[255];
X  char **FileLines, **NewFileLines, *CharPtr;
X  
X  if((argc < 2) | (argc > 4)) {
X    printf("Usage: %s -{mh|mv|r90|r180|r270} [Infile [Outfile]]\n", argv[0]);
X    printf("   -mh          Mirror horizontally\n");
X    printf("   -mv          Mirror vertically\n");
X    printf("   -r90         Rotate 90 degrees counterclockwise\n");
X    printf("   -r180        Rotate 90 degrees counterclockwise\n");
X    printf("   -r270        Rotate 90 degrees counterclockwise\n");
X    return(-1);
X  }
X 
X  switch (argc) {
X  case 2: 
X    Infile = stdin;
X    Outfile = stdout;
X    break;
X  case 3:
X    if((Infile = fopen(argv[2], "r")) == NULL)
X      {
X        printf("Could not open input file: %s\n", argv[1]);
X        return(-1);
X      }
X    Outfile = stdout;
X    break;
X  case 4: 
X    if((Outfile = fopen(argv[3], "w")) == NULL)
X      {
X        printf("Could not open output file: %s\n", argv[2]);
X        return(-1);
X      }
X    break;
X  }
X  
X  
X  strcpy(String, argv[1]);
X  
X  for(i = 0; String[i]; i ++)
X    if(String[i] >= 'A' && String[i] <= 'Z')
X      String[i] += ('a' - 'A');
X  
X  for(i = 0; i < NUM_FLAGS; i ++)
X    if(!strcmp(String, FlagStrings[i]))
X      break;
X  
X  if(i == NUM_FLAGS)
X    {
X      printf("Illegal flag: %s\n", argv[3]);
X      return(-1);
X    }
X  else
X    Flag = i;
X  
X  if((FileLines = GetFile(Infile, &NumberOfLines, String)) == NULL) {
X    printf("%s\n", String);
X    return(-1);
X  }
X  
X  for(i = 0; i < NumberOfLines; i ++) {
X    if((CharPtr = strrchr(FileLines[i], '\n')) != NULL)
X      *CharPtr = '\0';
X    
X    Length = strlen(FileLines[i]);
X    
X    if(i == 0 || (Length > MaxLength))
X      MaxLength = Length;
X  }
X  
X  switch (Flag) {
X 
X  case V_MIRROR:
X    for(i = NumberOfLines - 1; i >= 0; i --)
X      fprintf(Outfile, "%s\n", FileLines[i]);
X    break;
X    
X  case H_MIRROR:
X    for(i = 0; i < NumberOfLines; i ++) {
X      Length = strlen(FileLines[i]);
X      
X      for(j = 0; j < Length; j ++)
X        String[Length - j - 1] = FileLines[i][j];
X      
X      String[j] = '\0';
X      fprintf(Outfile, "%*s%s\n", MaxLength - Length, "", String);
X    }
X    break;
X    
X  case R180:
X    for(i = NumberOfLines - 1; i >= 0; i --) {
X      Length = strlen(FileLines[i]);
X      
X      for(j = 0; j < Length; j ++)
X        String[Length - j - 1] = FileLines[i][j];
X      
X      String[j] = '\0';
X      fprintf(Outfile, "%*s%s\n", MaxLength - Length, "", String);
X    }
X    break;
X    
X/*** For "real" rotations, need extra code ***/
X    
X  default:
X    
X    if((NewFileLines = 
X        (char **)malloc(MaxLength * sizeof(char *))) == NULL) {
X      printf("Memory Allocation Error: <malloc>");
X      return(-1);
X    }
X    
X    for(i = 0; i < MaxLength; i ++) {
X      if((NewFileLines[i] = 
X          (char *)malloc((NumberOfLines + 1) * sizeof(char))) == NULL) {
X        printf("Memory Allocation Error: <malloc>");
X        return(-1);
X      }
X    }
X    
X    switch (Flag) {
X      
X    case R90:
X 
X      for(i = 0; i < NumberOfLines; i ++)
X        {
X          for(j = 0; FileLines[i][j]; j ++)
X            NewFileLines[MaxLength - 1 - j][i] = FileLines[i][j];
X          
X          while(j < MaxLength) {
X            NewFileLines[MaxLength - 1 - j][i] = ' ';
X            j++;
X          }
X        }
X      break;
X      
X    case R270:
X 
X      for(i = 0; i < NumberOfLines; i ++) {
X        Length = strlen(FileLines[i]);
X        
X        for(k = 0, j = MaxLength - 1; j >= 0; j --, k ++)
X          if (j >= Length) 
X            NewFileLines[MaxLength - k - 1][NumberOfLines - i - 1] = ' ';
X          else
X            NewFileLines[MaxLength - k - 1][NumberOfLines - i - 1] = 
X              FileLines[i][j];
X        
X        while(k < MaxLength) {
X          NewFileLines[MaxLength - k - 1][NumberOfLines - i - 1] = ' ';
X          k++;
X        }
X      }
X      
X      break;
X    }
X 
X    for(j = 0; j < MaxLength; j ++) {
X      NewFileLines[j][NumberOfLines] = '\0';
X      fprintf(Outfile, "%s\n", NewFileLines[j]);
X    }
X  }
X  
X  
X  for(i = 0; i < NumberOfLines; i ++)
X    free((void *)FileLines[i]);
X  
X  free((void *)FileLines);
X  
X  fclose(Infile), fclose(Outfile);
X  
X  return(0);
X  
X} /* main */
END-of-asciitool.c
echo x - ccw90
sed 's/^X//' >ccw90 << 'END-of-ccw90'
X#!/bin/sh
X#
X# ccw90 - rotates ASCII pictures by 90 degrees counter clockwise
X#
X# by Joshua Bell <[email protected]>, July 1994
X#
X# Requires the asciitool program is present in your search path.
X#
X# Inspiration from Jef Poskanzer's "lr" utility for left/right flips.
X#
X# Mapping is:     _-~^<>v/\NZ!]|[()nu:;{}"'`,CUciIl17t=H
X# to:             |||<v^>\/ZN-~-_un()""_~:\/\U)u----r+H=
X
Xcat $* |
X  ./asciitool -r90 |
X  tr '_\-~^<>v/\\NZ!]|[()nu:;{}"'\''`,CUciIl17t=H' \
X     '|||<v^>\\/ZN\-~\-_un()""_~:\\/\\U)u\-\-\-\-r+H=' |
X  sed 's/  *$//'
X
END-of-ccw90
echo x - cw90
sed 's/^X//' >cw90 << 'END-of-cw90'
X#!/bin/sh
X#
X# cw90 - rotates ASCII pictures by 90 degrees clockwise
X#
X# by Joshua Bell <[email protected]>, July 1994
X#
X# Requires the asciitool program is present in your search path.
X#
X# Inspiration from Jef Poskanzer's "lr" utility for left/right flips.
X#
X# Mapping is:     _-~^<>v/\NZ!]|[()nu:;{}"'`,CUciIl1rt=H
X# to:             |||>^v<\/ZN-_-~nu)(""~_:\/\nCn----7+H=
X
Xcat $* |
X  ./asciitool -r270 |
X  tr '_\-~^<>v/\\NZ!]|[()nu:;{}"'\''`,CUciIl1rt=H' \
X     '|||>^v<\\/ZN\-_\-~nu)(""~_:\\/\\nCn\-\-\-\-7+H=' |
X  sed 's/  *$//'
X
END-of-cw90
echo x - tb
sed 's/^X//' >tb << 'END-of-tb'
X#!/bin/sh
X#
X# tb - flips ASCII pictures top for bottom
X#
X# by Joshua Bell <[email protected]>, Feb 1994
X#
X# Requires the asciitool program is present in your search path.
X#
X# Inspiration from Jef Poskanzer's "lr" utility for left/right flips.
X#
X# Mapping is:     ;!~_`,.'"^/\AFJLMPSTUVWYZbfghimnpqrstuvwyz257
X# to:             :i_~,`'..v\/VL7TWb2LAAMASPt6y!wubdtzfn^mhsSZJ
X
Xcat $* |
X  ./asciitool -mv |
X  tr ';!~_\140,.\047"^/\\AFJLMPSTUVWYZbfghimnpqrstuvwyz257' \
X     ':i_~,\140\047..v\\/VL7TWb2LAAMASPt6y!wubdtzfn^mhsSZJ' |
X  sed 's/  *$//'
X
END-of-tb
echo x - lr
sed 's/^X//' >lr << 'END-of-lr'
X#!/bin/sh
X#
X# lr - reverse ASCII pictures left for right
X#
X# Copyright (C) 1994 by Jef Poskanzer.
X#
X# Permission to use, copy, modify, and distribute this software and its
X# documentation for any purpose and without fee is hereby granted, provided
X# that the above copyright notice appear in all copies and that both that
X# copyright notice and this permission notice appear in supporting
X# documentation.  This software is provided "as is" without express or
X# implied warranty.
X
X# Translation of . -> , changed removed. Better to lose some symmetry than
X# induce asymmetry, IMHO. (jsbell@acs)
X
Xcat $* |
X  expand |
X  awk '{printf "%s%s\n", $0, substr("                                                                               ", length)}' |
X  rev |
X  tr '()<>{}\[]/\\.,\140\047LJZSE3dbqp' ')(><}{]\[\\/..\047\140JLSZ3Ebdpq' |
X  sed 's/  *$//'
END-of-lr
exit