tinycobol/lib/pictures.c

545 lines
16 KiB
C

//
// Copyright (C) 2001, 2000, 1999, Rildo Pragana, Jim Noeth,
// Andrew Cameron, David Essex.
// Copyright (C) 1993, 1991 Rildo Pragana.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation; either version 2.1,
// or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; see the file COPYING.LIB. If
// not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
/*---------------------------------------------------------------------------*\
| |
| COBOL Compiler Run Time Library -- Pictures |
| See each function's comments for more detail. |
| Independent of compressed PIC implementation: |
| tcob_picExpand() - Returns an expanded version of the PIC string |
| tcob_picCompLength() - Numeric character count |
| tcob_picEditedCompLength() - Numeric-edited character count |
| tcob_picEditedCompDecimals() - Decimal numeric-edited characters count |
| Dependent on compressed PIC implementation: |
| tcob_picElemVal() - Retrieve character value from a specified element |
| tcob_picElemLen() - Retrieve character count from a specified element |
| tcob_picReqLen() - Determine size to allocate for a new compressed PIC |
| tcob_picCreate() - Start a new compressed PIC string |
| tcob_picAppend() - Continue a compressed PIC string |
| |
\*---------------------------------------------------------------------------*/
#include "htcoblib.h"
#include "screenio.h"
extern int bDecimalComma;
/*------------------------------------------------------------------------*\
| |
| tcob_picExpand |
| expand a picture returning a malloc'ed string |
| from: "XAYBZC" (where X, Y, Z are picture characters and |
| A, B, C are binary counts for each character) |
| to: "XXXXYYYZZZZZ" |
| |
\*------------------------------------------------------------------------*/
char * tcob_picExpand( struct fld_desc *f ) {
char *result, c;
unsigned int i, t, tot;
for (i=0, tot=0; tcob_picElemVal(f->pic,i); i++)
tot += tcob_picElemLen(f->pic,i);
result = malloc(tot+1);
for (i=0, tot=0; (c=tcob_picElemVal(f->pic,i)); i++) {
t = tcob_picElemLen(f->pic,i);
memset (&result[tot], c, t);
tot += t;
}
result[tot] = '\0';
/*
#ifdef PICTURE_TESTING
printf("tcob_picexpand: %s\n", result);
free(result);
return NULL;
#else
return result;
#endif
*/
return result;
}
/*------------------------------------------------------------------------*\
| |
| tcob_picCompLength |
| For numeric types, determine the total number of stored digits. |
| Includes 9's. |
| |
\*------------------------------------------------------------------------*/
unsigned int tcob_picCompLength( struct fld_desc *f ) {
unsigned int len=0, i;
char c;
for (i=0; (c=tcob_picElemVal(f->pic,i)); i++) {
if (c == '9')
len += tcob_picElemLen(f->pic,i);
}
return len;
}
/*------------------------------------------------------------------------*\
| |
| tcob_picEditedCompLength |
| For the numeric-edited type, determine the total number of digits |
| available. Includes 9's, Z's,*'s, and multiples of +, -, and the |
| currency sign. |
| |
\*------------------------------------------------------------------------*/
unsigned int tcob_picEditedCompLength( struct fld_desc *f ) {
unsigned int len=0, i;
unsigned int bSeenPlus=0, bSeenMinus=0, bSeenCurrency=0;
char c;
extern char cCurrencySymbol;
for (i=0; (c=tcob_picElemVal(f->pic,i)); i++) {
unsigned int ilen = tcob_picElemLen(f->pic,i);
if (c == '9' || c == 'Z' || c == '*' ||
(bSeenPlus && (c == '+')) ||
(bSeenMinus && (c == '-')) ||
(bSeenCurrency && (c == cCurrencySymbol)) )
len += ilen;
if (!bSeenPlus && (c == '+')) {
bSeenPlus = 1;
len += ilen - 1;
} else if (!bSeenMinus && (c == '-')) {
bSeenMinus = 1;
len += ilen - 1;
} else if (!bSeenCurrency && (c == cCurrencySymbol)) {
bSeenCurrency = 1;
len += ilen - 1;
}
}
return len;
}
unsigned int tcob_picTotalLen( char *pic ) {
int len=0;
while (*pic) {
len += *(pic+1);
pic+=2;
}
return len;
}
/*------------------------------------------------------------------------*\
| |
| tcob_picSignPosition |
| For the numeric- type, determine the position of the sign |
| |
\*------------------------------------------------------------------------*/
unsigned int tcob_picSignPosition( struct fld_desc *f ) {
unsigned int len=0, i;
char c;
int d = DISPLAYFIELD(f->type);
for (i=0; (c=tcob_picElemVal(f->pic,i)); i++) {
unsigned int ilen = tcob_picElemLen(f->pic,i);
len += ilen;
if ((c == '+' || c == '-') || (c == 'S' && d && i == 0)) {
len -= ilen;
return len;
}
}
return -1;
}
/*------------------------------------------------------------------------*\
| |
| tcob_picDecimalPointPosition |
| For the numeric- type, determine the position of the decimal point |
| |
\*------------------------------------------------------------------------*/
unsigned int tcob_picDecimalPointPosition( struct fld_desc *f ) {
unsigned int len=0, i;
extern int bDecimalComma;
char c, cDecimal = (bDecimalComma) ? ',' : '.';
for (i=0; (c=tcob_picElemVal(f->pic,i)); i++) {
unsigned int ilen = tcob_picElemLen(f->pic,i);
len += ilen;
if (c == cDecimal) {
len -= ilen;
return len;
}
}
return -1;
}
/*------------------------------------------------------------------------*\
| |
| tcob_picEditedCompDecimals |
| For the numeric-edited type, determine the total number of digits |
| available after the decimal point. Includes 9's, Z's,*'s, and |
| multiples of +, -, and the currency sign. |
| |
\*------------------------------------------------------------------------*/
unsigned int tcob_picEditedCompDecimals( struct fld_desc *f ) {
unsigned int len=0, i;
int bSeenDecimal=0, bSeenPlus=0, bSeenMinus=0, bSeenCurrency=0;
extern int bDecimalComma;
extern char cCurrencySymbol;
char c, cDecimal = (bDecimalComma) ? ',' : '.';
for (i=0; (c=tcob_picElemVal(f->pic,i)); i++) {
unsigned int ilen = tcob_picElemLen(f->pic,i);
if (bSeenDecimal && // Must find the decimal point first
(c == '9' || c == 'Z' || c == '*' ||
(bSeenPlus && (c == '+')) ||
(bSeenMinus && (c == '-')) ||
(bSeenCurrency && (c == cCurrencySymbol)) ) )
len += ilen;
if (!bSeenDecimal && (c == cDecimal)) {
bSeenDecimal = 1;
} else if (!bSeenPlus && (c == '+')) {
bSeenPlus = 1;
if (bSeenDecimal)
len += ilen - 1;
} else if (!bSeenMinus && (c == '-')) {
bSeenMinus = 1;
if (bSeenDecimal)
len += ilen - 1;
} else if (!bSeenCurrency && (c == cCurrencySymbol)) {
bSeenCurrency = 1;
if (bSeenDecimal)
len += ilen - 1;
}
}
return len;
}
/*------------------------------------------------------------------------*\
| |
| tcob_picElemLen & tcob_picElemVal |
| Determine the length or value of element i in array p. |
| Each element is composed of an 8-bit character and an 8-bit length. |
| |
\*------------------------------------------------------------------------*/
unsigned int tcob_picElemLen(char *p, unsigned int i) {
return ( (unsigned int)(((unsigned short *)p)[i] >> 8) );
}
char tcob_picElemVal(char *p, unsigned int i) {
return ( ((unsigned short *)p)[i] & 0x0ff );
}
/*------------------------------------------------------------------------*\
| |
| tcob_picReqLen |
| Determine number of bytes to request for holding a compressed PIC |
| string of i elements. |
| |
\*------------------------------------------------------------------------*/
unsigned int tcob_picReqLen(unsigned int i) {
/* Currently using a 1-byte value and a 1-byte length for each
* element, plus a 1-byte NULL to indicate the end */
return ((i*2)+1);
}
/*------------------------------------------------------------------------*\
| |
| tcob_picCreate |
| Create a new PIC string and place in p. |
| |
\*------------------------------------------------------------------------*/
char *tcob_picCreate(char *p, unsigned int len, ...) {
char pc;
unsigned int i=0, ilen;
va_list args;
va_start(args, len);
while ((pc=va_arg(args,int))) {
for (ilen=va_arg(args, int); ilen>255; ilen-=255) {
if (i+1>=len)
break;
p[i] = pc;
p[i+1] = 255;
ilen -= 255;
i += 2;
}
if (i+1>=len)
break;
p[i] = pc;
p[i+1] = ilen;
i += 2;
}
if (i<len)
p[i] = '\0';
else if (i>1)
p[i-2] = '\0';
else if (len==1)
p[0] = '\0';
va_end(args);
return p;
}
/*------------------------------------------------------------------------*\
| |
| tcob_picAppend |
| Continue the PIC string found in p. |
| |
\*------------------------------------------------------------------------*/
char *tcob_picAppend(char *p, unsigned int len, ...) {
char pc;
unsigned int i, ilen;
va_list args;
for (i=0; p[i]; i+=2) ;
va_start(args, len);
while ((pc=va_arg(args,int))) {
for (ilen=va_arg(args, int); ilen>255; ilen-=255) {
if (i+1>=len)
break;
p[i] = pc;
p[i+1] = 255;
ilen -= 255;
i += 2;
}
if (i+1>=len)
break;
p[i] = pc;
p[i+1] = ilen;
i += 2;
}
if (i<len)
p[i] = '\0';
else if (i>1)
p[i-2] = '\0';
else if (len==1)
p[0] = '\0';
va_end(args);
return p;
}
/*------------------------------------------------------------------------*\
| |
| tcob_picChangeChar |
| change the PIC string char in p. |
| |
\*------------------------------------------------------------------------*/
void tcob_picChangeChar(char *p, int i, char c) {
p[i*2]= c;
}
/*-----------------------------------------------------------
* Classify picture type
* receives a compressed pic pointer
* returns picture type
*/
char tcob_classifyPic( char *p ) {
int i;
char type=0;
for (i=0; p[i]; i+=2) {
switch (p[i]) {
case 'A':
if ((type != DTYPE_ALPHANUMERIC && type != DTYPE_EDITED)
|| !type)
type = DTYPE_ALPHA;
break;
case 'X':
if (type == DTYPE_DISPLAY || !type)
type = DTYPE_ALPHANUMERIC;
break;
case 'Z':
type=DTYPE_EDITED;
break;
case '9':
if (!type)
type=DTYPE_DISPLAY;
break;
case 'V':
case 'P':
case 'S':
break;
case '.':
case ',':
case '0':
case 'B':
case '/':
case '+':
case '-':
case '*':
case 'C':
case 'R':
case 'D':
type=DTYPE_EDITED;
break;
}
}
return type;
}
/*********************************************
tcob_isNumEdit
check if a picture stands for a numeric-edited item (true) or
alphanumeric-edited (false).
Standard: ISO/IEC 1989:2001 (pp.323-324)
---------------------------
13.16.38.3 General Rules
...
FORMAT 1
...
7) To define an item as alphanumeric-edited, character-string-1 shall
include:
- at least one symbol 'A' or 'X', and
- at least one of the symbols from the set 'B', '0', '/'.
**********************************************/
int tcob_isNumEdit(char *p) {
char cDecimalChar = '.';
int i,dsep=0;
int axfound=0;
int bzslfound=0;
if (bDecimalComma)
cDecimalChar = ',';
for (i=0; p[i]; i+=2) {
switch (p[i]) {
/* the standard says we must find one of those below, at least,
but for dates (pic 99/99/999) which is visibly not
numeric-edited, there is none 'A' or 'X'. So let's not
require this until someone explains me what to do here. */
case 'A':
case 'X':
axfound=1;
break;
/* don't count a 'B' after 'D' (DB) */
case 'D':
if (p[i+1]==1 && p[i+2]=='B' && p[i+3]==1) {
i+=2;
continue;
}
case '.':
case ',':
if (p[i] == cDecimalChar) {
if (dsep++) {
return 0;
}
/* make sure there are no repetitions here */
if (p[i+1] > 1) {
return 0;
}
}
continue;
case 'B':
case '0':
case '/':
bzslfound=1;
break;
}
}
if (bzslfound && axfound)
return 0;
else
return 1;
}
int tcob_isNumeric(char *p) {
int i;
for (i=0; p[i]; i+=2) {
switch (p[i]) {
case 'S': // walter 13-12-05
continue;
case '9':
continue;
case 'V':
continue;
default:
return 0;
}
}
return 1;
}
int tcob_isZNum(char *p) {
int i;
for (i=0; p[i]; i+=2) {
switch (p[i]) {
case '-':
case ',':
case '.':
case '9':
case 'Z':
continue;
default:
return 0;
}
}
return 1;
}
int tcob_isAlpha(char *p) {
int i;
for (i=0; p[i]; i+=2) {
switch (p[i]) {
case 'A':
case 'X':
return 1;
}
}
return 0;
}
/* check if the picture has any pic Z string */
int tcob_hasZ(char *p) {
int i;
for (i=0; p[i]; i+=2) {
switch (p[i]) {
case 'Z':
return 1;
}
}
return 0;
}
/*********************
how many significative characters (Z,X,A,9,*) there
are in the picture
**********************/
int tcob_picCharLen( unsigned char *pic ) {
int n=0;
while (*pic) {
if (strchr("9ZXA*",*pic)) {
n+=*(pic+1);
}
pic += 2;
}
return n;
}