diff --git a/VERSION b/VERSION index 643711b8..8465a3b5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.298 +8.3.299 diff --git a/calma/CalmaWrite.c b/calma/CalmaWrite.c index 7657c046..d06325ee 100644 --- a/calma/CalmaWrite.c +++ b/calma/CalmaWrite.c @@ -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. */ diff --git a/commands/CmdCD.c b/commands/CmdCD.c index 114aacb9..44189c47 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -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 diff --git a/scripts/configure b/scripts/configure index ddf28479..9ab0f802 100755 --- a/scripts/configure +++ b/scripts/configure @@ -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 diff --git a/scripts/configure.in b/scripts/configure.in index 2d0558b0..ddd4a9d8 100644 --- a/scripts/configure.in +++ b/scripts/configure.in @@ -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]) diff --git a/utils/utils.h b/utils/utils.h index 3f1b481c..6f69266c 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -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();