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; size_t defsize, numbytes;
off_t cellstart, cellend, structstart; off_t cellstart, cellend, structstart;
dlong cval; dlong cval;
int namelen;
char *modName;
FILE *fi; 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 */ /* Use PaOpen() so the paths searched are the same as were */
/* searched to find the .mag file that indicated this GDS file. */ /* 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) if (fi == NULL)
{ {
/* This is a rare error, but if the subcell is inside */ /* 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\" " TxError("Calma output error: Can't find GDS file \"%s\" "
"for vendor cell \"%s\". It will not be output.\n", "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) if (CalmaAllowUndefined)
return 0; return 0;
@ -1112,6 +1145,17 @@ calmaProcessDef(def, outf, do_library)
} }
fclose(fi); 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 */ /* Mark the definition as vendor GDS so that magic doesn't */
/* try to generate subcell interaction or array interaction */ /* try to generate subcell interaction or array interaction */
/* paint for it. */ /* paint for it. */

View File

@ -125,6 +125,9 @@ CmdCalma(w, cmd)
char **msg, *namep, *dotptr; char **msg, *namep, *dotptr;
CellDef *rootDef; CellDef *rootDef;
FILE *f; FILE *f;
int namelen;
bool gzipd;
char *realName, *saveName, *modName;
extern int CalmaFlattenLimit; extern int CalmaFlattenLimit;
@ -870,11 +873,54 @@ CmdCalma(w, cmd)
case CALMA_READ: case CALMA_READ:
if (cmd->tx_argc != 3) goto wrongNumArgs; 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 */ /* Check for various common file extensions, including */
/* no extension (as-is), ".gds", ".gds2", and ".strm". */ /* no extension (as-is), ".gds", ".gds2", and ".strm". */
for (ext = 0; gdsExts[ext] != NULL; ext++) 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) (char *) NULL, &namep)) != (FILE *)NULL)
break; break;
@ -887,6 +933,18 @@ CmdCalma(w, cmd)
} }
CalmaReadFile(f, namep); CalmaReadFile(f, namep);
(void) fclose(f); (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; return;
} }
@ -898,8 +956,20 @@ CmdCalma(w, cmd)
outputCalma: outputCalma:
dotptr = strrchr(namep, '.'); 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" : "", ".", 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) if (f == (FILE *) NULL)
{ {
@ -914,6 +984,24 @@ outputCalma:
TxError("File may be incompletely written.\n"); TxError("File may be incompletely written.\n");
} }
(void) fclose(f); (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 #endif

99
scripts/configure vendored
View File

@ -672,6 +672,8 @@ X_PRE_LIBS
X_CFLAGS X_CFLAGS
XMKMF XMKMF
PYTHON3 PYTHON3
GUNZIP
GZIP
CSH CSH
GCORE GCORE
EGREP EGREP
@ -5327,6 +5329,103 @@ if test "x${CSH}" = "xno"; then
as_fn_error $? "cannot find /bin/csh---cannot compile!" "$LINENO" 5 as_fn_error $? "cannot find /bin/csh---cannot compile!" "$LINENO" 5
fi 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. # Extract the first word of "python3", so it can be a program name with args.
set dummy python3; ac_word=$2 set dummy python3; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 { $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!]) AC_MSG_ERROR([cannot find /bin/csh---cannot compile!])
fi 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 Python3 is preferred for running the preprocessor script
dnl but CPP can be used instead. dnl but CPP can be used instead.
AC_PATH_PROG([PYTHON3], [python3], [no]) AC_PATH_PROG([PYTHON3], [python3], [no])

View File

@ -44,6 +44,7 @@ extern int LookupStructFull();
extern int PaExpand(char **, char **, int); extern int PaExpand(char **, char **, int);
extern char *nextName(); extern char *nextName();
extern FILE *PaOpen(char *, char *, char *, char *, char *, char **); 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 FILE *PaLockOpen(char *, char *, char *, char *, char *, char **, bool *);
extern char *StrDup(char **, char *); extern char *StrDup(char **, char *);
extern int Match(); extern int Match();