/*
* ascii.c -- quick crossreference for ASCII character aliases
*
* Tries to interpret arguments as names or aliases of ascii characters
* and dumps out *all* the aliases of each. Accepts literal characters,
* standard mnemonics, C-style backslash escapes, caret notation for control
* characters, numbers in hex/decimal/octal/binary, English names.
*
* The slang names used are selected from the 2.2 version of the USENET ascii
* pronunciation guide. Some additional ones were merged in from the Jargon
* File.
*
* For license terms, see the file COPYING.
*/
#ifndef S_SPLINT_S
#include <unistd.h>
#include <ctype.h>
#endif /* S_SPLINT_S */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <getopt.h>
#ifdef __CYGWIN__
#undef stricmp
#endif /* __CYGWIN__ */
typedef char *string;
static bool terse = false;
static bool help = false;
static bool line = false;
enum { decimal, hex, octal } mode;
void print_table(unsigned short delivery);
static string cnames[128][16] =
{
{
#include "nametable.h"
}
};
static int atob(str)
/* ASCII-to-binary conversion */
char *str;
{
int val;
for (val = 0; *str != '\0'; str++)
{
val *= 2;
if (*str == '1')
val++;
else if (*str != '0')
return(-1);
}
return(val);
}
void
showHelp(FILE *out, char *progname)
{
fprintf(out,"Usage: %s [-dxohv] [-t] [char-alias...]\n", progname);
#define P(s) (void)fputs(s "\n", out);
#include "splashscreen.h"
#undef P
exit(0);
}
static void process_options(int argc, char *argv[], char * opt_string)
{
int op;
while( (op=getopt(argc, argv, opt_string)) != -1) {
switch (op) {
case 't':
terse = true;
break;
case 's':
terse = true;
line = true;
break;
case 'd':
print_table(decimal);
exit(0);
case 'x':
print_table(hex);
exit(0);
case 'o':
print_table(octal);
exit(0);
case '?':
case 'h':
help = true;
break;
case 'v':
printf("ascii %3.2f\n",REVISION);
exit(0);
default :
help = true;
break;
} /*switch*/
}/*while*/
}
static char *btoa(unsigned int val)
/* binary-to-ASCII conversion */
{
#define BITSPERCHAR 8
char *rp;
static char rep[BITSPERCHAR + 1];
/* write out external representation at least one char */
*(rp = rep + BITSPERCHAR) = '\0';
do {
*--rp = (char)('0' + (val & 1)); /* Is '1' == '0' + 1 in EBCDIC? */
val /= 2;
} while
(val != 0 && rp > rep);
#ifndef SHORT_BINARY_REPRESENTATION
while (rp > rep)
*--rp = '0';
#endif
return(rp);
}
static void speak(unsigned int ch)
/* list all the names for a given character */
{
char **ptr = &cnames[ch][0];
if (terse) {
(void) printf("%u/%u %u 0x%02X 0o%o %s\n",
ch / 16, ch % 16, ch, ch, ch, btoa(ch));
return;
}
(void) printf(
"ASCII %u/%u is decimal %03u, hex %02x, octal %03o, bits %s: ",
ch / 16, ch % 16, ch, ch, ch, btoa(ch));
/* display high-half characters */
if (ch & 0x80)
{
ch &=~ 0x80;
if (ch == 0x7f)
(void) printf("meta-^?\n");
else if (isprint((int)ch))
(void) printf("meta-%c\n", (char)ch);
else
(void) printf("meta-^%c\n", '@' + (ch & 0x1f));
return;
}
if (isprint((int)ch))
(void) printf("prints as `%s'\n", *ptr++);
else if (iscntrl((char)ch) || ch == 0x7F)
{
if (ch == 0x7f)
(void) printf("called ^?");
else
(void) printf("called ^%c", '@' + (ch & 0x1f));
for (; strlen(*ptr) < 4 && isupper(**ptr); ptr++)
(void) printf(", %s", *ptr);
(void) putchar('\n');
}
(void) printf("Official name: %s\n", *ptr++);
if (*ptr)
{
char *commentary = (char *)NULL;
if (**ptr == '\\')
{
(void) printf("C escape: '%s'\n", *ptr);
ptr++;
}
(void) printf("Other names: ");
for (; *ptr; ptr++)
if (**ptr == '#')
commentary = *ptr;
else
(void) printf("%s%s ", *ptr,
(ptr[1]!=NULL && *ptr[1] != '#') ? "," : "");
(void) putchar('\n');
if (commentary)
(void) printf("Note: %s\n", commentary+2);
}
(void) putchar('\n');
}
static int stricmp(char *s, char *t)
/* case-blind string compare */
{
while (*s!='\0' && tolower(*s) == tolower(*t))
s++, t++;
return (int)(*t - *s);
}
static void ascii(char *str)
{
int ch, hi, lo;
char **ptr;
size_t len = strlen(str);
/* interpret single characters as themselves */
if (len == 1) {
speak((unsigned int)str[0]);
/* also interpret single digits as numeric */
if(!line && strchr("0123456789ABCDEFabcdef",str[0])) {
int hval;
(void) sscanf(str, "%x", &hval);
speak(hval);
} return;
}
/* process multiple letters */
if (line == 1) {
for (ch = 0; ch < len; ch ++) {
speak((unsigned int)str[ch]);
}
return;
}
/* interpret ^-escapes as control-character notation */
if (strcmp(str, "^?") == 0)
{ speak((unsigned int)0x7F); return; }
else if (str[0] == '^' && len == 2)
{ speak((unsigned int)(str[1] & 0x1f)); return; }
/* interpret C-style backslash escapes */
if (*str == '\\' && len == 2 && strchr("abfnrtv0", str[1]))
for (ch = 7; ch < 14; ch++)
for (ptr = &cnames[ch][1]; *ptr; ptr++)
if (**ptr == '\\' && strcmp(str, *ptr) == 0)
{ speak((unsigned int)ch); return; }
/* interpret 2 and 3-character ASCII control mnemonics */
if (len == 2 || len == 3)
{
/* first check for standard mnemonics */
if (stricmp(str, "DEL") == 0)
{ speak(0x7f); return; }
if (stricmp(str, "BL") == 0)
{ speak(' '); return; }
else if (isalpha(str[0]))
for (ch = 0; ch <= 32; ch++)
if (!stricmp(str,cnames[ch][0]) || !strcmp(str,cnames[ch][1]))
{ speak(ch); return; }
}
/* OK, now try to interpret the string as a numeric */
if (len > 1 && len < 9)
{
int hval, dval, oval, bval, spoken = 0;
dval = oval = hval = bval = -1;
/* if it's all numeric it could be in one of three bases */
if (len <= 2 && strspn(str,"0123456789ABCDEFabcdef") == len)
(void) sscanf(str, "%x", &hval);
if (len <= 3 && strspn(str, "0123456789") == len)
(void) sscanf(str, "%d", &dval);
if (len <= 3 && strspn(str, "01234567") == len)
(void) sscanf(str, "%o", &oval);
if (len <= 9 && strspn(str, "01") == len)
bval = atob(str);
/* accept 0xnn, \xnn, xnn and nnh forms for hex */
if (hval == -1)
if ((str[0]=='0'||str[0]=='\\') && tolower(str[1]) == 'x')
(void) sscanf(str + 2, "%x", &hval);
else if (tolower(str[0]) == 'x')
(void) sscanf(str + 1, "%x", &hval);
else if ((len >= 2) && (len <= 3) &&
(strspn(str,"0123456789ABCDEFabcdef") == (len-1)) &&
(tolower(str[len - 1]) == 'h'))
(void) sscanf(str, "%x", &hval);
/* accept 0onn, \onnn, onnn and \nnn forms for octal */
if (oval == -1)
if ((str[0]=='0'||str[0]=='\\') && tolower(str[1]) == 'o')
(void) sscanf(str + 2, "%o", &oval);
else if (tolower(str[0]) == 'o')
(void) sscanf(str + 1, "%o", &oval);
else if (str[0] == '\\' && strspn(str + 1, "0123456789") == len - 1)
(void) sscanf(str + 1, "%o", &oval);
/* accept 0dnnn, \dnnn and dnnn forms for decimal */
if (dval == -1)
if ((str[0]=='0'||str[0]=='\\') && tolower(str[1]) == 'd')
(void) sscanf(str + 2, "%d", &dval);
else if (tolower(str[0]) == 'd')
(void) sscanf(str + 1, "%d", &dval);
/* accept 0bnnn, \bnnn and bnnn forms for binary */
if (bval == -1)
if ((str[0]=='0'||str[0]=='\\') && tolower(str[1]) == 'b')
bval = atob(str + 2);
else if (tolower(str[0]) == 'b')
bval = atob(str + 1);
/* OK, now output all values */
if (hval > -1 && hval < 256)
speak(hval & 0xff);
if (dval > -1 && dval < 256)
speak(dval & 0xff);
if (oval > -1 && oval < 256)
speak(oval & 0xff);
if (bval > -1 && bval < 256)
speak(bval & 0xff);
if (!(hval==-1 && dval==-1 && oval==-1 && bval==-1))
{
if (hval > -1 || dval > -1 || oval > -1 || bval > -1)
return;
if (hval < 256 || dval < 256 || oval < 256 || bval < 256)
return;
}
}
if (sscanf(str, "%d/%d", &hi, &lo) == 2) /* code table reference? */
{ speak(hi*16 + lo); return; }
else if (len > 1 && isalpha(str[0])) /* try to match long names */
{
char canbuf[BUFSIZ], *ep;
int i;
/* map dashes and other junk to spaces */
for (i = 0; i <= len; i++)
if (str[i] == '-' || isspace(str[i]))
canbuf[i] = ' ';
else
canbuf[i] = str[i];
/* strip `sign' or `Sign' suffix */
ep = canbuf + strlen(canbuf) - 4;
if (!strcmp(ep, "sign") || !strcmp(ep, "Sign"))
*ep = '\0';
/* remove any trailing whitespace */
while (canbuf[strlen(canbuf) - 1] == ' ')
canbuf[strlen(canbuf) - 1] = '\0';
/* look through all long names for a match */
for (ch = 0; ch < 128; ch++)
for (ptr = &cnames[ch][1]; *ptr; ptr++)
if (!stricmp(*ptr, canbuf))
speak(ch);
} /* outer if */
}
void print_table(unsigned short delivery)
{
static unsigned short i, j, len;
char separator[]= " ";
char *tail = separator + 3 ;
char *space;
char *name ;
for (i=0;i<16; i++) {
for (j=0; j<8; j++) {
name= *cnames[i+(j*16)];
len = strlen(name);
space = tail - (len % 3) ;
switch (delivery) {
case decimal: printf("%5d %1s%1s",i+(j*16),name,space);
break;
case octal : printf("%5o %1s%1s",i+(j*16),name,space);
break;
case hex : printf("%5X %1s%1s",i+(j*16),name,space);
break;
}
}
printf("\n");
}
}
int main(int argc, char **argv)
{
char *optstring="tshvxod" ;
process_options(argc, argv, optstring) ;
if (help || argc == optind)
showHelp(stdout, argv[0]);
else
while (optind < argc)
ascii(argv[optind++]);
exit(0);
}
/* ascii.c ends here */