Added the capability to handle compressed GDS files through the use

of systems calls to "gzip" and "gunzip".  A compressed GDS file can
be made simply by doing "gds write <name>.gds.gz", and can be read
simply by doing "gds read <name>.gds.gz".  Names of compressed files
can be put in the GDS_FILE property of a cell.
This commit is contained in:
Tim Edwards 2022-05-05 17:40:56 -04:00
parent 468a8ae0be
commit 85d8ad6622
6 changed files with 254 additions and 5 deletions

View File

@ -1 +1 @@
8.3.298
8.3.299

View File

@ -943,12 +943,43 @@ calmaProcessDef(def, outf, do_library)
size_t defsize, numbytes;
off_t cellstart, cellend, structstart;
dlong cval;
int namelen;
char *modName;
FILE *fi;
/* Handle compressed files */
modName = filename;
namelen = strlen(filename);
if ((namelen > 4) && !strcmp(filename + namelen - 3, ".gz"))
{
char *sysCmd, sptr;
sptr = strrchr(filename, '/');
if (sptr == NULL)
sptr = filename;
else
sptr++;
modName = StrDup((char **)NULL, sptr);
*(modName + strlen(modName) - 3) = '\0';
sysCmd = mallocMagic(18 + namelen + strlen(modName));
sprinf(sysCmd, "gunzip -c -k %s > %s", filename, modName);
if (system(sysCmd) != 0)
{
/* File didn't uncompress. Go back to original name,
* although that will probably fail and raise an error.
*/
freeMagic(modName);
modName = filename;
}
}
/* Use PaOpen() so the paths searched are the same as were */
/* searched to find the .mag file that indicated this GDS file. */
fi = PaOpen(filename, "r", "", Path, CellLibPath, &retfilename);
fi = PaOpen(modName, "r", "", Path, CellLibPath, &retfilename);
if (fi == NULL)
{
/* This is a rare error, but if the subcell is inside */
@ -964,7 +995,9 @@ calmaProcessDef(def, outf, do_library)
TxError("Calma output error: Can't find GDS file \"%s\" "
"for vendor cell \"%s\". It will not be output.\n",
filename, def->cd_name);
modName, def->cd_name);
if (modName != filename) freeMagic(modName);
if (CalmaAllowUndefined)
return 0;
@ -1112,6 +1145,17 @@ calmaProcessDef(def, outf, do_library)
}
fclose(fi);
if (modName != filename)
{
/* Remove the uncompressed file */
if (unlink(modName) != 0)
{
TxError("Error attempting to delete uncompressed file \"%s\"\n",
modName);
}
freeMagic(modName);
}
/* Mark the definition as vendor GDS so that magic doesn't */
/* try to generate subcell interaction or array interaction */
/* paint for it. */

View File

@ -125,6 +125,9 @@ CmdCalma(w, cmd)
char **msg, *namep, *dotptr;
CellDef *rootDef;
FILE *f;
int namelen;
bool gzipd;
char *realName, *saveName, *modName;
extern int CalmaFlattenLimit;
@ -870,11 +873,54 @@ CmdCalma(w, cmd)
case CALMA_READ:
if (cmd->tx_argc != 3) goto wrongNumArgs;
/* Check for compressed files, and uncompress them. */
/* Always uncompress into the current working directory */
/* because the original compressed file might be in an */
/* unwriteable directory. */
modName = cmd->tx_argv[2];
namelen = strlen(modName);
if ((namelen > 4) && !strcmp(modName + namelen - 3, ".gz"))
{
char *sysCmd, *sptr;
/* First try to open the uncompressed file name. If */
/* the file exists, then don't try to uncompress on top */
/* of it, but just fail. */
sptr = strrchr(modName, '/');
if (sptr == NULL)
sptr = modName;
else
sptr++;
modName = StrDup((char **)NULL, sptr);
*(modName + strlen(modName) - 3) = '\0';
if ((f = PaOpen(modName, "r", NULL, Path,
(char *)NULL, NULL)) != (FILE *)NULL)
{
fclose(f);
TxError("Uncompressed file \"%s\" already exists!\n", modName);
freeMagic(modName);
return;
}
sysCmd = mallocMagic(18 + namelen + strlen(modName));
/* Note: "-k" keeps the original compressed file */
TxPrintf("Uncompressing file \"%s\".\n", cmd->tx_argv[2]);
sprintf(sysCmd, "gunzip -c -k %s > %s", cmd->tx_argv[2], modName);
if (system(sysCmd) != 0)
{
freeMagic(modName);
modName = NULL;
}
freeMagic(sysCmd);
}
/* Check for various common file extensions, including */
/* no extension (as-is), ".gds", ".gds2", and ".strm". */
for (ext = 0; gdsExts[ext] != NULL; ext++)
if ((f = PaOpen(cmd->tx_argv[2], "r", gdsExts[ext], Path,
if ((f = PaOpen(modName, "r", gdsExts[ext], Path,
(char *) NULL, &namep)) != (FILE *)NULL)
break;
@ -887,6 +933,18 @@ CmdCalma(w, cmd)
}
CalmaReadFile(f, namep);
(void) fclose(f);
if (modName != cmd->tx_argv[2])
{
/* A gzipped file was read and now the uncompressed */
/* file that was generated should be removed. */
if (unlink(namep) != 0)
{
TxError("Error attempting to delete uncompressed file \"%s\"\n",
namep);
}
freeMagic(modName);
}
return;
}
@ -898,8 +956,20 @@ CmdCalma(w, cmd)
outputCalma:
dotptr = strrchr(namep, '.');
/* Check for additional ".gz" extension */
if (!strcmp(dotptr, ".gz"))
{
gzipd = TRUE;
*dotptr = '\0';
dotptr = strrchr(namep, '.');
}
else
gzipd = FALSE;
f = PaOpen(namep, "w", (dotptr == NULL) ? ".gds" : "", ".",
(char *) NULL, (char **) NULL);
(char *) NULL, (char **)&realName);
if (gzipd)
saveName = StrDup((char **)NULL, realName);
if (f == (FILE *) NULL)
{
@ -914,6 +984,24 @@ outputCalma:
TxError("File may be incompletely written.\n");
}
(void) fclose(f);
if (gzipd)
{
char *sysCmd;
sysCmd = mallocMagic(16 + strlen(saveName));
TxPrintf("Compressing file \"%s\"\n", saveName);
sprintf(sysCmd, "gzip -n --best %s", saveName);
/* Note that without additional arguments, "gzip" will wholly */
/* replace the uncompressed file with the compressed one. */
if (system(sysCmd) != 0)
{
TxError("Failed to compress file \"%s\"\n", saveName);
}
freeMagic(sysCmd);
freeMagic(saveName);
}
}
#endif

99
scripts/configure vendored
View File

@ -672,6 +672,8 @@ X_PRE_LIBS
X_CFLAGS
XMKMF
PYTHON3
GUNZIP
GZIP
CSH
GCORE
EGREP
@ -5327,6 +5329,103 @@ if test "x${CSH}" = "xno"; then
as_fn_error $? "cannot find /bin/csh---cannot compile!" "$LINENO" 5
fi
# Extract the first word of "gzip", so it can be a program name with args.
set dummy gzip; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_GZIP+:} false; then :
$as_echo_n "(cached) " >&6
else
case $GZIP in
[\\/]* | ?:[\\/]*)
ac_cv_path_GZIP="$GZIP" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_GZIP="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_path_GZIP" && ac_cv_path_GZIP="no"
;;
esac
fi
GZIP=$ac_cv_path_GZIP
if test -n "$GZIP"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $GZIP" >&5
$as_echo "$GZIP" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "x${GZIP}" = "xno"; then
as_fn_error $? "cannot find gzip---will not be able to compress large files" "$LINENO" 5
else
$as_echo "#define HAVE_GZIP 1" >>confdefs.h
fi
# Extract the first word of "gunzip", so it can be a program name with args.
set dummy gunzip; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_GUNZIP+:} false; then :
$as_echo_n "(cached) " >&6
else
case $GUNZIP in
[\\/]* | ?:[\\/]*)
ac_cv_path_GUNZIP="$GUNZIP" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_GUNZIP="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_path_GUNZIP" && ac_cv_path_GUNZIP="no"
;;
esac
fi
GUNZIP=$ac_cv_path_GUNZIP
if test -n "$GUNZIP"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $GUNZIP" >&5
$as_echo "$GUNZIP" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "x${GUNZIP}" = "xno"; then
as_fn_error $? "cannot find gunzip---will not be able to automatically uncompress files" "$LINENO" 5
else
$as_echo "#define HAVE_GUNZIP 1" >>confdefs.h
fi
# Extract the first word of "python3", so it can be a program name with args.
set dummy python3; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5

View File

@ -285,6 +285,23 @@ if test "x${CSH}" = "xno"; then
AC_MSG_ERROR([cannot find /bin/csh---cannot compile!])
fi
dnl gzip and gunzip are used for file compression and uncompression of
dnl large files (e.g., GDS)
AC_PATH_PROG([GZIP], [gzip], [no])
if test "x${GZIP}" = "xno"; then
AC_MSG_ERROR([cannot find gzip---will not be able to compress large files])
else
AC_DEFINE(HAVE_GZIP)
fi
AC_PATH_PROG([GUNZIP], [gunzip], [no])
if test "x${GUNZIP}" = "xno"; then
AC_MSG_ERROR([cannot find gunzip---will not be able to automatically uncompress files])
else
AC_DEFINE(HAVE_GUNZIP)
fi
dnl Python3 is preferred for running the preprocessor script
dnl but CPP can be used instead.
AC_PATH_PROG([PYTHON3], [python3], [no])

View File

@ -44,6 +44,7 @@ extern int LookupStructFull();
extern int PaExpand(char **, char **, int);
extern char *nextName();
extern FILE *PaOpen(char *, char *, char *, char *, char *, char **);
extern FILE *PaZOpen(char *, char *, char *, char *, char *, char **, bool *);
extern FILE *PaLockOpen(char *, char *, char *, char *, char *, char **, bool *);
extern char *StrDup(char **, char *);
extern int Match();